From 573d4ec1c59d58f0bb5cbce933c47f96e1fc95b8 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 8 May 2024 19:30:28 -0700 Subject: [PATCH] replacer and json features --- .../array-newlines.json.test.ts.snap | 10 +- .../camel.assets.json.test.ts.snap | 108 ++--- .../camel.chain.json.test.ts.snap | 444 +++++++++--------- .../__snapshots__/camel.ibc.json.test.ts.snap | 42 +- .../property-rename.test.ts.snap | 189 ++++++++ .../__snapshots__/stringify.json.test.ts.snap | 34 +- __tests__/property-rename.test.ts | 139 ++++++ package.json | 7 +- src/js.ts | 86 +++- src/json.ts | 63 +-- types/index.d.ts | 13 +- types/js.d.ts | 13 + types/json.d.ts | 9 + types/utils.d.ts | 5 + 14 files changed, 755 insertions(+), 407 deletions(-) create mode 100644 __tests__/__snapshots__/property-rename.test.ts.snap create mode 100644 __tests__/property-rename.test.ts create mode 100644 types/js.d.ts create mode 100644 types/json.d.ts create mode 100644 types/utils.d.ts diff --git a/__tests__/__snapshots__/array-newlines.json.test.ts.snap b/__tests__/__snapshots__/array-newlines.json.test.ts.snap index 4f997ef..6eb32f3 100644 --- a/__tests__/__snapshots__/array-newlines.json.test.ts.snap +++ b/__tests__/__snapshots__/array-newlines.json.test.ts.snap @@ -2,13 +2,13 @@ exports[`handles nested arrays with inlineArrayLimit 1`] = ` "{ - matrix: [[1, 2], [3, 4]] + "matrix": [[1, 2], [3, 4]] }" `; exports[`serializes arrays with newlines when length exceeds the inlineArrayLimit with space set 1`] = ` "{ - numbers: [ + "numbers": [ 1, 2, 3, @@ -20,10 +20,10 @@ exports[`serializes arrays with newlines when length exceeds the inlineArrayLimi exports[`serializes arrays without newlines when length equals the inlineArrayLimit 1`] = ` "{ - numbers: [1, 2, 3, 4, 5] + "numbers": [1, 2, 3, 4, 5] }" `; -exports[`serializes arrays without newlines when length exceeds the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3, 4, 5]}"`; +exports[`serializes arrays without newlines when length exceeds the inlineArrayLimit 1`] = `"{"numbers": [1, 2, 3, 4, 5]}"`; -exports[`serializes arrays without newlines when length is below the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3]}"`; +exports[`serializes arrays without newlines when length is below the inlineArrayLimit 1`] = `"{"numbers": [1, 2, 3]}"`; diff --git a/__tests__/__snapshots__/camel.assets.json.test.ts.snap b/__tests__/__snapshots__/camel.assets.json.test.ts.snap index 406e71d..f4de76a 100644 --- a/__tests__/__snapshots__/camel.assets.json.test.ts.snap +++ b/__tests__/__snapshots__/camel.assets.json.test.ts.snap @@ -2,90 +2,90 @@ exports[`assetlist 1`] = ` "{ - $schema: "../assetlist.schema.json", - chainName: "comdex", - assets: [ + "$schema": "../assetlist.schema.json", + "chainName": "comdex", + "assets": [ { - description: "Native Token of Comdex Protocol", - denomUnits: [ + "description": "Native Token of Comdex Protocol", + "denomUnits": [ { - denom: "ucmdx", - exponent: 0 + "denom": "ucmdx", + "exponent": 0 }, { - denom: "cmdx", - exponent: 6 + "denom": "cmdx", + "exponent": 6 } ], - base: "ucmdx", - name: "Comdex", - display: "cmdx", - symbol: "CMDX", - logoURIs: { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" + "base": "ucmdx", + "name": "Comdex", + "display": "cmdx", + "symbol": "CMDX", + "logoURIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" }, - coingeckoId: "comdex", - images: [ + "coingeckoId": "comdex", + "images": [ { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" } ] }, { - description: "Governance Token of Harbor protocol on Comdex network", - denomUnits: [ + "description": "Governance Token of Harbor protocol on Comdex network", + "denomUnits": [ { - denom: "uharbor", - exponent: 0 + "denom": "uharbor", + "exponent": 0 }, { - denom: "harbor", - exponent: 6 + "denom": "harbor", + "exponent": 6 } ], - base: "uharbor", - name: "Harbor", - display: "harbor", - symbol: "HARBOR", - logoURIs: { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg" + "base": "uharbor", + "name": "Harbor", + "display": "harbor", + "symbol": "HARBOR", + "logoURIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg" }, - coingeckoId: "harbor-2", - images: [ + "coingeckoId": "harbor-2", + "images": [ { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg" + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg" } ] }, { - description: "Stable Token of Harbor protocol on Comdex network", - denomUnits: [ + "description": "Stable Token of Harbor protocol on Comdex network", + "denomUnits": [ { - denom: "ucmst", - exponent: 0 + "denom": "ucmst", + "exponent": 0 }, { - denom: "cmst", - exponent: 6 + "denom": "cmst", + "exponent": 6 } ], - base: "ucmst", - name: "CMST", - display: "cmst", - symbol: "CMST", - logoURIs: { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg" + "base": "ucmst", + "name": "CMST", + "display": "cmst", + "symbol": "CMST", + "logoURIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg" }, - coingeckoId: "composite", - images: [ + "coingeckoId": "composite", + "images": [ { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg" + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg" } ] } diff --git a/__tests__/__snapshots__/camel.chain.json.test.ts.snap b/__tests__/__snapshots__/camel.chain.json.test.ts.snap index 2739c30..7659804 100644 --- a/__tests__/__snapshots__/camel.chain.json.test.ts.snap +++ b/__tests__/__snapshots__/camel.chain.json.test.ts.snap @@ -2,392 +2,392 @@ exports[`chain 1`] = ` "{ - $schema: "../chain.schema.json", - chainName: "comdex", - status: "live", - networkType: "mainnet", - website: "https://comdex.one/", - prettyName: "Comdex", - chainId: "comdex-1", - bech32Prefix: "comdex", - slip44: 118, - fees: { - feeTokens: [ - { - denom: "ucmdx", - fixedMinGasPrice: 0, - lowGasPrice: 0, - averageGasPrice: 0.025, - highGasPrice: 0.04 + "$schema": "../chain.schema.json", + "chainName": "comdex", + "status": "live", + "networkType": "mainnet", + "website": "https://comdex.one/", + "prettyName": "Comdex", + "chainId": "comdex-1", + "bech32Prefix": "comdex", + "slip44": 118, + "fees": { + "feeTokens": [ + { + "denom": "ucmdx", + "fixedMinGasPrice": 0, + "lowGasPrice": 0, + "averageGasPrice": 0.025, + "highGasPrice": 0.04 } ] }, - staking: { - stakingTokens: [ + "staking": { + "stakingTokens": [ { - denom: "ucmdx" + "denom": "ucmdx" } ] }, - codebase: { - gitRepo: "https://github.com/comdex-official/comdex", - recommendedVersion: "v13.4.0", - compatibleVersions: [ + "codebase": { + "gitRepo": "https://github.com/comdex-official/comdex", + "recommendedVersion": "v13.4.0", + "compatibleVersions": [ "v13.4.0" ], - binaries: { + "binaries": { "linux/amd64": "https://github.com/comdex-official/comdex/releases/download/v13.4.0/comdex-linux-amd64.tar.gz" }, - cosmosSdkVersion: "v0.47.5", - consensus: { - type: "cometbft", - version: "0.37.2" + "cosmosSdkVersion": "v0.47.5", + "consensus": { + "type": "cometbft", + "version": "0.37.2" }, - cosmwasmVersion: "v0.41.0", - cosmwasmEnabled: true, - genesis: { - genesisUrl: "https://comdex-mainnet-genesis.s3.ap-southeast-1.amazonaws.com/genesis.json" + "cosmwasmVersion": "v0.41.0", + "cosmwasmEnabled": true, + "genesis": { + "genesisUrl": "https://comdex-mainnet-genesis.s3.ap-southeast-1.amazonaws.com/genesis.json" }, - versions: [ + "versions": [ { - name: "v9.0.0", - recommendedVersion: "v9.0.0", - compatibleVersions: [ + "name": "v9.0.0", + "recommendedVersion": "v9.0.0", + "compatibleVersions": [ "v9.0.0" ], - cosmwasmEnabled: true, - nextVersionName: "v10.0.0" + "cosmwasmEnabled": true, + "nextVersionName": "v10.0.0" }, { - name: "v10.0.0", - recommendedVersion: "v10.0.0", - compatibleVersions: [ + "name": "v10.0.0", + "recommendedVersion": "v10.0.0", + "compatibleVersions": [ "v10.0.0" ], - cosmwasmEnabled: true, - nextVersionName: "v11.5.0" + "cosmwasmEnabled": true, + "nextVersionName": "v11.5.0" }, { - name: "v11.5.0", - height: 8184000, - proposal: 154, - recommendedVersion: "v11.5.2", - compatibleVersions: [ + "name": "v11.5.0", + "height": 8184000, + "proposal": 154, + "recommendedVersion": "v11.5.2", + "compatibleVersions": [ "v11.5.2" ], - cosmwasmEnabled: true, - nextVersionName: "v13.3.0" + "cosmwasmEnabled": true, + "nextVersionName": "v13.3.0" }, { - name: "v13.3.0", - proposal: 216, - height: 10981900, - recommendedVersion: "v13.4.0", - compatibleVersions: [ + "name": "v13.3.0", + "proposal": 216, + "height": 10981900, + "recommendedVersion": "v13.4.0", + "compatibleVersions": [ "v13.4.0" ], - binaries: { + "binaries": { "linux/amd64": "https://github.com/comdex-official/comdex/releases/download/v13.4.0/comdex-linux-amd64.tar.gz" }, - cosmosSdkVersion: "v0.47.5", - consensus: { - type: "cometbft", - version: "0.37.2" + "cosmosSdkVersion": "v0.47.5", + "consensus": { + "type": "cometbft", + "version": "0.37.2" }, - cosmwasmVersion: "v0.41.0", - cosmwasmEnabled: true, - nextVersionName: "" + "cosmwasmVersion": "v0.41.0", + "cosmwasmEnabled": true, + "nextVersionName": "" } ] }, - daemonName: "comdex", - nodeHome: "$HOME/.comdex", - keyAlgos: [ + "daemonName": "comdex", + "nodeHome": "$HOME/.comdex", + "keyAlgos": [ "secp256k1" ], - logoURIs: { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" + "logoURIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" }, - peers: { - seeds: [ + "peers": { + "seeds": [ { - id: "7ca14a1d156299999eba9c394ca060368022d52f", - address: "54.194.178.110:26656" + "id": "7ca14a1d156299999eba9c394ca060368022d52f", + "address": "54.194.178.110:26656" }, { - id: "ade4d8bc8cbe014af6ebdf3cb7b1e9ad36f412c0", - address: "seeds.polkachu.com:13156", - provider: "Polkachu" + "id": "ade4d8bc8cbe014af6ebdf3cb7b1e9ad36f412c0", + "address": "seeds.polkachu.com:13156", + "provider": "Polkachu" }, { - id: "c30dacf15e97a30b78792c7fa817fd2ef529b820", - address: "comdex.seed.stavr.tech:2026", - provider: "🔥STAVR🔥" + "id": "c30dacf15e97a30b78792c7fa817fd2ef529b820", + "address": "comdex.seed.stavr.tech:2026", + "provider": "🔥STAVR🔥" }, { - id: "20e1000e88125698264454a884812746c2eb4807", - address: "seeds.lavenderfive.com:13156", - provider: "Lavender.Five Nodes 🐝" + "id": "20e1000e88125698264454a884812746c2eb4807", + "address": "seeds.lavenderfive.com:13156", + "provider": "Lavender.Five Nodes 🐝" }, { - id: "ebc272824924ea1a27ea3183dd0b9ba713494f83", - address: "comdex-mainnet-seed.autostake.com:26776", - provider: "AutoStake 🛡️ Slash Protected" + "id": "ebc272824924ea1a27ea3183dd0b9ba713494f83", + "address": "comdex-mainnet-seed.autostake.com:26776", + "provider": "AutoStake 🛡️ Slash Protected" }, { - id: "6596d143fd128b2394b27cd7846bda099ca5a193", - address: "seeds.goldenratiostaking.net:1621", - provider: "Golden Ratio Staking" + "id": "6596d143fd128b2394b27cd7846bda099ca5a193", + "address": "seeds.goldenratiostaking.net:1621", + "provider": "Golden Ratio Staking" }, { - id: "8542cd7e6bf9d260fef543bc49e59be5a3fa9074", - address: "seed.publicnode.com:26656", - provider: "Allnodes ⚡️ Nodes & Staking" + "id": "8542cd7e6bf9d260fef543bc49e59be5a3fa9074", + "address": "seed.publicnode.com:26656", + "provider": "Allnodes ⚡️ Nodes & Staking" }, { - id: "c28827cb96c14c905b127b92065a3fb4cd77d7f6", - address: "seeds.whispernode.com:13156", - provider: "WhisperNode 🤐" + "id": "c28827cb96c14c905b127b92065a3fb4cd77d7f6", + "address": "seeds.whispernode.com:13156", + "provider": "WhisperNode 🤐" }, { - id: "88ba33fbdf0279efaf27cff629f3cf72814d4069", - address: "seed-comdex-01.stakeflow.io:10007", - provider: "Stakeflow" + "id": "88ba33fbdf0279efaf27cff629f3cf72814d4069", + "address": "seed-comdex-01.stakeflow.io:10007", + "provider": "Stakeflow" }, { - id: "df949a46ae6529ae1e09b034b49716468d5cc7e9", - address: "seeds.stakerhouse.com:10456", - provider: "StakerHouse" + "id": "df949a46ae6529ae1e09b034b49716468d5cc7e9", + "address": "seeds.stakerhouse.com:10456", + "provider": "StakerHouse" } ], - persistentPeers: [ + "persistentPeers": [ { - id: "d478882a80674fa10a32da63cc20cae13e3a2a57", - address: "43.204.0.243:26656" + "id": "d478882a80674fa10a32da63cc20cae13e3a2a57", + "address": "43.204.0.243:26656" }, { - id: "d8b74791ee56f1b345d822f62bd9bc969668d8df", - address: "194.163.128.55:36656" + "id": "d8b74791ee56f1b345d822f62bd9bc969668d8df", + "address": "194.163.128.55:36656" }, { - id: "ebc272824924ea1a27ea3183dd0b9ba713494f83", - address: "comdex-mainnet-peer.autostake.com:26776", - provider: "AutoStake 🛡️ Slash Protecteds" + "id": "ebc272824924ea1a27ea3183dd0b9ba713494f83", + "address": "comdex-mainnet-peer.autostake.com:26776", + "provider": "AutoStake 🛡️ Slash Protecteds" }, { - id: "88ba33fbdf0279efaf27cff629f3cf72814d4069", - address: "peer-comdex-01.stakeflow.io:10007", - provider: "Stakeflow" + "id": "88ba33fbdf0279efaf27cff629f3cf72814d4069", + "address": "peer-comdex-01.stakeflow.io:10007", + "provider": "Stakeflow" } ] }, - apis: { - rpc: [ + "apis": { + "rpc": [ { - address: "https://rpc.comdex.one", - provider: "comdex" + "address": "https://rpc.comdex.one", + "provider": "comdex" }, { - address: "https://comdex-rpc.polkachu.com", - provider: "Polkachu" + "address": "https://comdex-rpc.polkachu.com", + "provider": "Polkachu" }, { - address: "https://comdex.rpc.m.stavr.tech", - provider: "🔥STAVR🔥" + "address": "https://comdex.rpc.m.stavr.tech", + "provider": "🔥STAVR🔥" }, { - address: "https://rpc.comdex.chaintools.tech/", - provider: "ChainTools" + "address": "https://rpc.comdex.chaintools.tech/", + "provider": "ChainTools" }, { - address: "https://comdex-rpc.lavenderfive.com/", - provider: "Lavender.Five Nodes 🐝" + "address": "https://comdex-rpc.lavenderfive.com/", + "provider": "Lavender.Five Nodes 🐝" }, { - address: "https://rpc-comdex.cosmos-spaces.cloud", - provider: "Cosmos Spaces" + "address": "https://rpc-comdex.cosmos-spaces.cloud", + "provider": "Cosmos Spaces" }, { - address: "https://rpc-comdex.whispernode.com:443", - provider: "WhisperNode 🤐" + "address": "https://rpc-comdex.whispernode.com:443", + "provider": "WhisperNode 🤐" }, { - address: "https://comdex-mainnet-rpc.autostake.com:443", - provider: "AutoStake 🛡️ Slash Protected" + "address": "https://comdex-mainnet-rpc.autostake.com:443", + "provider": "AutoStake 🛡️ Slash Protected" }, { - address: "https://comdex-rpc.w3coins.io", - provider: "w3coins" + "address": "https://comdex-rpc.w3coins.io", + "provider": "w3coins" }, { - address: "https://comdex-rpc.stakerhouse.com", - provider: "StakerHouse" + "address": "https://comdex-rpc.stakerhouse.com", + "provider": "StakerHouse" }, { - address: "https://comdex-rpc.publicnode.com:443", - provider: "Allnodes ⚡️ Nodes & Staking" + "address": "https://comdex-rpc.publicnode.com:443", + "provider": "Allnodes ⚡️ Nodes & Staking" }, { - address: "https://rpc-comdex-01.stakeflow.io", - provider: "Stakeflow" + "address": "https://rpc-comdex-01.stakeflow.io", + "provider": "Stakeflow" }, { - address: "https://comdex-rpc.validatornode.com", - provider: "ValidatorNode" + "address": "https://comdex-rpc.validatornode.com", + "provider": "ValidatorNode" } ], - rest: [ + "rest": [ { - address: "https://rest.comdex.one", - provider: "comdex" + "address": "https://rest.comdex.one", + "provider": "comdex" }, { - address: "https://api.comdex.chaintools.tech/", - provider: "ChainTools" + "address": "https://api.comdex.chaintools.tech/", + "provider": "ChainTools" }, { - address: "https://comdex-api.polkachu.com", - provider: "Polkachu" + "address": "https://comdex-api.polkachu.com", + "provider": "Polkachu" }, { - address: "https://comdex.api.m.stavr.tech", - provider: "🔥STAVR🔥" + "address": "https://comdex.api.m.stavr.tech", + "provider": "🔥STAVR🔥" }, { - address: "https://comdex-api.lavenderfive.com/", - provider: "Lavender.Five Nodes 🐝" + "address": "https://comdex-api.lavenderfive.com/", + "provider": "Lavender.Five Nodes 🐝" }, { - address: "https://api-comdex.cosmos-spaces.cloud", - provider: "Cosmos Spaces" + "address": "https://api-comdex.cosmos-spaces.cloud", + "provider": "Cosmos Spaces" }, { - address: "https://comdex-mainnet-lcd.autostake.com:443", - provider: "AutoStake 🛡️ Slash Protected" + "address": "https://comdex-mainnet-lcd.autostake.com:443", + "provider": "AutoStake 🛡️ Slash Protected" }, { - address: "https://lcd-comdex.whispernode.com:443", - provider: "WhisperNode 🤐" + "address": "https://lcd-comdex.whispernode.com:443", + "provider": "WhisperNode 🤐" }, { - address: "https://comdex-api.w3coins.io", - provider: "w3coins" + "address": "https://comdex-api.w3coins.io", + "provider": "w3coins" }, { - address: "https://comdex-rest.stakerhouse.com", - provider: "StakerHouse" + "address": "https://comdex-rest.stakerhouse.com", + "provider": "StakerHouse" }, { - address: "https://comdex-rest.publicnode.com", - provider: "Allnodes ⚡️ Nodes & Staking" + "address": "https://comdex-rest.publicnode.com", + "provider": "Allnodes ⚡️ Nodes & Staking" }, { - address: "https://api-comdex-01.stakeflow.io", - provider: "Stakeflow" + "address": "https://api-comdex-01.stakeflow.io", + "provider": "Stakeflow" }, { - address: "https://comdex-api.validatornode.com", - provider: "ValidatorNode" + "address": "https://comdex-api.validatornode.com", + "provider": "ValidatorNode" } ], - grpc: [ + "grpc": [ { - address: "grpc-comdex-ia.cosmosia.notional.ventures:443", - provider: "Notional" + "address": "grpc-comdex-ia.cosmosia.notional.ventures:443", + "provider": "Notional" }, { - address: "comdex.grpcui.chaintools.host:443", - provider: "ChainTools" + "address": "comdex.grpcui.chaintools.host:443", + "provider": "ChainTools" }, { - address: "comdex-grpc.polkachu.com:13190", - provider: "Polkachu" + "address": "comdex-grpc.polkachu.com:13190", + "provider": "Polkachu" }, { - address: "comdex.grpc.m.stavr.tech:104", - provider: "🔥STAVR🔥" + "address": "comdex.grpc.m.stavr.tech:104", + "provider": "🔥STAVR🔥" }, { - address: "grpc-comdex.cosmos-spaces.cloud:2300", - provider: "Cosmos Spaces" + "address": "grpc-comdex.cosmos-spaces.cloud:2300", + "provider": "Cosmos Spaces" }, { - address: "comdex-grpc.lavenderfive.com:443", - provider: "Lavender.Five Nodes 🐝" + "address": "comdex-grpc.lavenderfive.com:443", + "provider": "Lavender.Five Nodes 🐝" }, { - address: "comdex-mainnet-lcd.autostake.com:443", - provider: "AutoStake 🛡️ Slash Protected" + "address": "comdex-mainnet-lcd.autostake.com:443", + "provider": "AutoStake 🛡️ Slash Protected" }, { - address: "comdex-grpc.w3coins.io:13190", - provider: "w3coins" + "address": "comdex-grpc.w3coins.io:13190", + "provider": "w3coins" }, { - address: "comdex-grpc.publicnode.com:443", - provider: "Allnodes ⚡️ Nodes & Staking" + "address": "comdex-grpc.publicnode.com:443", + "provider": "Allnodes ⚡️ Nodes & Staking" }, { - address: "grpc-comdex-01.stakeflow.io:10002", - provider: "Stakeflow" + "address": "grpc-comdex-01.stakeflow.io:10002", + "provider": "Stakeflow" }, { - address: "comdex-grpc.stakerhouse.com:443", - provider: "StakerHouse" + "address": "comdex-grpc.stakerhouse.com:443", + "provider": "StakerHouse" } ] }, - explorers: [ + "explorers": [ { - kind: "ezstaking", - url: "https://ezstaking.app/comdex", - txPage: "https://ezstaking.app/comdex/txs/\${txHash}", - accountPage: "https://ezstaking.app/comdex/account/\${accountAddress}" + "kind": "ezstaking", + "url": "https://ezstaking.app/comdex", + "txPage": "https://ezstaking.app/comdex/txs/\${txHash}", + "accountPage": "https://ezstaking.app/comdex/account/\${accountAddress}" }, { - kind: "mintscan", - url: "https://www.mintscan.io/comdex", - txPage: "https://www.mintscan.io/comdex/transactions/\${txHash}", - accountPage: "https://www.mintscan.io/comdex/accounts/\${accountAddress}" + "kind": "mintscan", + "url": "https://www.mintscan.io/comdex", + "txPage": "https://www.mintscan.io/comdex/transactions/\${txHash}", + "accountPage": "https://www.mintscan.io/comdex/accounts/\${accountAddress}" }, { - kind: "🔥STAVR🔥", - url: "https://explorer.stavr.tech/Comdex-Mainnet", - txPage: "https://explorer.stavr.tech/Comdex-Mainnet/txs/\${txHash}", - accountPage: "https://explorer.stavr.tech/Comdex-Mainnet/accounts/\${accountAddress}" + "kind": "🔥STAVR🔥", + "url": "https://explorer.stavr.tech/Comdex-Mainnet", + "txPage": "https://explorer.stavr.tech/Comdex-Mainnet/txs/\${txHash}", + "accountPage": "https://explorer.stavr.tech/Comdex-Mainnet/accounts/\${accountAddress}" }, { - kind: "aneka", - url: "https://comdex.aneka.io/", - txPage: "https://comdex.aneka.io/txs/\${txHash}" + "kind": "aneka", + "url": "https://comdex.aneka.io/", + "txPage": "https://comdex.aneka.io/txs/\${txHash}" }, { - kind: "ping.pub", - url: "https://ping.pub/comdex", - txPage: "https://ping.pub/comdex/tx/\${txHash}" + "kind": "ping.pub", + "url": "https://ping.pub/comdex", + "txPage": "https://ping.pub/comdex/tx/\${txHash}" }, { - kind: "atomscan", - url: "https://atomscan.com/comdex", - txPage: "https://atomscan.com/comdex/transactions/\${txHash}", - accountPage: "https://atomscan.com/comdex/accounts/\${accountAddress}" + "kind": "atomscan", + "url": "https://atomscan.com/comdex", + "txPage": "https://atomscan.com/comdex/transactions/\${txHash}", + "accountPage": "https://atomscan.com/comdex/accounts/\${accountAddress}" }, { - kind: "Stakeflow", - url: "https://stakeflow.io/comdex", - accountPage: "https://stakeflow.io/comdex/accounts/\${accountAddress}" + "kind": "Stakeflow", + "url": "https://stakeflow.io/comdex", + "accountPage": "https://stakeflow.io/comdex/accounts/\${accountAddress}" }, { - kind: "ValidatorNode", - url: "https://explorer.validatornode.com/comdex", - txPage: "https://explorer.validatornode.com/comdex/tx/\${txHash}" + "kind": "ValidatorNode", + "url": "https://explorer.validatornode.com/comdex", + "txPage": "https://explorer.validatornode.com/comdex/tx/\${txHash}" } ], - images: [ + "images": [ { - png: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", - svg: "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" } ] }" diff --git a/__tests__/__snapshots__/camel.ibc.json.test.ts.snap b/__tests__/__snapshots__/camel.ibc.json.test.ts.snap index 1569ad8..94ac3ef 100644 --- a/__tests__/__snapshots__/camel.ibc.json.test.ts.snap +++ b/__tests__/__snapshots__/camel.ibc.json.test.ts.snap @@ -2,32 +2,32 @@ exports[`ibc 1`] = ` "{ - $schema: "../ibc_data.schema.json", - chain1: { - chainName: "terra", - clientId: "07-tendermint-235", - connectionId: "connection-142" + "$schema": "../ibc_data.schema.json", + "chain1": { + "chainName": "terra", + "clientId": "07-tendermint-235", + "connectionId": "connection-142" }, - chain2: { - chainName: "terra2", - clientId: "07-tendermint-394", - connectionId: "connection-384" + "chain2": { + "chainName": "terra2", + "clientId": "07-tendermint-394", + "connectionId": "connection-384" }, - channels: [ + "channels": [ { - chain1: { - channelId: "channel-85", - portId: "transfer" + "chain1": { + "channelId": "channel-85", + "portId": "transfer" }, - chain2: { - channelId: "channel-314", - portId: "transfer" + "chain2": { + "channelId": "channel-314", + "portId": "transfer" }, - ordering: "unordered", - version: "ics20-1", - tags: { - status: "live", - preferred: true + "ordering": "unordered", + "version": "ics20-1", + "tags": { + "status": "live", + "preferred": true } } ] diff --git a/__tests__/__snapshots__/property-rename.test.ts.snap b/__tests__/__snapshots__/property-rename.test.ts.snap new file mode 100644 index 0000000..570eeca --- /dev/null +++ b/__tests__/__snapshots__/property-rename.test.ts.snap @@ -0,0 +1,189 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`assetlist 1`] = ` +"{ + $schema: '../assetlist.schema.json', + chainName: 'comdex', + assets: [ + { + description: 'Native Token of Comdex Protocol', + denominations: [ + { + denom: 'ucmdx', + exponent: 0 + }, + { + denom: 'cmdx', + exponent: 6 + } + ], + base: 'ucmdx', + name: 'Comdex', + display: 'cmdx', + symbol: 'CMDX', + logoURIs: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg' + }, + coingeckoId: 'comdex', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg' + } + ] + }, + { + typeAsset: 'sdk.Coin', + description: 'Governance Token of Harbor protocol on Comdex network', + denominations: [ + { + denom: 'uharbor', + exponent: 0 + }, + { + denom: 'harbor', + exponent: 6 + } + ], + base: 'uharbor', + name: 'Harbor', + display: 'harbor', + symbol: 'HARBOR', + logoURIs: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg' + }, + coingeckoId: 'harbor-2', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg' + } + ] + }, + { + description: 'Stable Token of Harbor protocol on Comdex network', + denominations: [ + { + denom: 'ucmst', + exponent: 0 + }, + { + denom: 'cmst', + exponent: 6 + } + ], + base: 'ucmst', + name: 'CMST', + display: 'cmst', + symbol: 'CMST', + logoURIs: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg' + }, + coingeckoId: 'composite', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg' + } + ] + } + ] +}" +`; + +exports[`replacer 1`] = ` +"{ + $schema: '../assetlist.schema.json', + chainName: 'comdex', + assets: [ + { + description: 'Native Token of Comdex Protocol', + denominations: [ + { + denom: 'ucmdx', + exponent: 0 + }, + { + denom: 'cmdx', + exponent: 6 + } + ], + base: 'ucmdx', + name: 'Comdex', + display: 'cmdx', + symbol: 'CMDX', + logos: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg' + }, + coingeckoId: 'comdex', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg' + } + ] + }, + { + typeAsset: 'sdk.Coin', + description: 'Governance Token of Harbor protocol on Comdex network', + denominations: [ + { + denom: 'uharbor', + exponent: 0 + }, + { + denom: 'harbor', + exponent: 6 + } + ], + base: 'uharbor', + name: 'Harbor', + display: 'harbor', + symbol: 'HARBOR', + logos: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg' + }, + coingeckoId: 'harbor-2', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg' + } + ] + }, + { + description: 'Stable Token of Harbor protocol on Comdex network', + denominations: [ + { + denom: 'ucmst', + exponent: 0 + }, + { + denom: 'cmst', + exponent: 6 + } + ], + base: 'ucmst', + name: 'CMST', + display: 'cmst', + symbol: 'CMST', + logoURIs: { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg' + }, + coingeckoId: 'composite', + images: [ + { + png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png', + svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg' + } + ] + } + ] +}" +`; diff --git a/__tests__/__snapshots__/stringify.json.test.ts.snap b/__tests__/__snapshots__/stringify.json.test.ts.snap index 25a2273..58cdc66 100644 --- a/__tests__/__snapshots__/stringify.json.test.ts.snap +++ b/__tests__/__snapshots__/stringify.json.test.ts.snap @@ -1,14 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`applies replacer function if provided 1`] = `"{firstName: "Alice", lastName: "Johnson", age: undefined}"`; +exports[`applies replacer function if provided 1`] = `"{"firstName": "Alice", "lastName": "Johnson", "age": undefined}"`; exports[`handles complex nested objects with arrays 1`] = ` "{ - user: { - id: 2, - details: { - name: "Bob", - hobbies: [ + "user": { + "id": 2, + "details": { + "name": "Bob", + "hobbies": [ "skiing", "cycling" ] @@ -19,15 +19,15 @@ exports[`handles complex nested objects with arrays 1`] = ` exports[`handles nested arrays with inlineArrayLimit 1`] = ` "{ - matrix: [[1, 2], [3, 4]] + "matrix": [[1, 2], [3, 4]] }" `; -exports[`properly escapes strings when necessary 1`] = `"{complexString: "She said, \\"That's \`incredible\`!\\""}"`; +exports[`properly escapes strings when necessary 1`] = `"{"complexString": "She said, \\"That's \`incredible\`!\\""}"`; exports[`serializes arrays with newlines when length exceeds the inlineArrayLimit with space set 1`] = ` "{ - numbers: [ + "numbers": [ 1, 2, 3, @@ -39,20 +39,20 @@ exports[`serializes arrays with newlines when length exceeds the inlineArrayLimi exports[`serializes arrays without newlines when length equals the inlineArrayLimit 1`] = ` "{ - numbers: [1, 2, 3, 4, 5] + "numbers": [1, 2, 3, 4, 5] }" `; -exports[`serializes arrays without newlines when length exceeds the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3, 4, 5]}"`; +exports[`serializes arrays without newlines when length exceeds the inlineArrayLimit 1`] = `"{"numbers": [1, 2, 3, 4, 5]}"`; -exports[`serializes arrays without newlines when length is below the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3]}"`; +exports[`serializes arrays without newlines when length is below the inlineArrayLimit 1`] = `"{"numbers": [1, 2, 3]}"`; -exports[`serializes objects with keys starting with $ correctly 1`] = `"{$id: 1, name: "Alice", $type: "user"}"`; +exports[`serializes objects with keys starting with $ correctly 1`] = `"{"$id": 1, "name": "Alice", "$type": "user"}"`; -exports[`serializes simple objects without quotes on keys where possible 1`] = `"{id: 1, name: "Alice", isActive: true}"`; +exports[`serializes simple objects without quotes on keys where possible 1`] = `"{"id": 1, "name": "Alice", "isActive": true}"`; -exports[`switches to backticks when single quotes are in the string 1`] = `"{message: "It's a wonderful day!"}"`; +exports[`switches to backticks when single quotes are in the string 1`] = `"{"message": "It's a wonderful day!"}"`; -exports[`uses double quotes when backticks and single quotes are present 1`] = `"{quote: "\`This\` is 'awesome'!"}"`; +exports[`uses double quotes when backticks and single quotes are present 1`] = `"{"quote": "\`This\` is 'awesome'!"}"`; -exports[`uses single quotes for strings by default 1`] = `"{greeting: "Hello, world!"}"`; +exports[`uses single quotes for strings by default 1`] = `"{"greeting": "Hello, world!"}"`; diff --git a/__tests__/property-rename.test.ts b/__tests__/property-rename.test.ts new file mode 100644 index 0000000..eb778e8 --- /dev/null +++ b/__tests__/property-rename.test.ts @@ -0,0 +1,139 @@ +import { minimatch } from "minimatch"; +import { jsStringify } from "../src"; + +const assetlist = { + "$schema": "../assetlist.schema.json", + "chain_name": "comdex", + "assets": [ + { + "description": "Native Token of Comdex Protocol", + "denom_units": [ + { + "denom": "ucmdx", + "exponent": 0 + }, + { + "denom": "cmdx", + "exponent": 6 + } + ], + "base": "ucmdx", + "name": "Comdex", + "display": "cmdx", + "symbol": "CMDX", + "logo_URIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" + }, + "coingecko_id": "comdex", + "images": [ + { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmdx.svg" + } + ] + }, + { + "type_asset": "sdk.Coin", + "description": "Governance Token of Harbor protocol on Comdex network", + "denom_units": [ + { + "denom": "uharbor", + "exponent": 0 + }, + { + "denom": "harbor", + "exponent": 6 + } + ], + "base": "uharbor", + "name": "Harbor", + "display": "harbor", + "symbol": "HARBOR", + "logo_URIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg" + }, + "coingecko_id": "harbor-2", + "images": [ + { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/harbor.svg" + } + ] + }, + { + "description": "Stable Token of Harbor protocol on Comdex network", + "denom_units": [ + { + "denom": "ucmst", + "exponent": 0 + }, + { + "denom": "cmst", + "exponent": 6 + } + ], + "base": "ucmst", + "name": "CMST", + "display": "cmst", + "symbol": "CMST", + "logo_URIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg" + }, + "coingecko_id": "composite", + "images": [ + { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/comdex/images/cmst.svg" + } + ] + } + ] +}; + + +it('assetlist', () => { + + const options = { + camelCase: true, + space: 2, + propertyRenameMap: { + "/assets/*/denom_units": "denominations", + "/assets/[0-1]/logo_URIs": "logos" + } + }; + + const jsonString = jsStringify(assetlist, options); + + expect(jsonString).toMatchSnapshot(); +}); + +function propertyReplacer( + currentKey: string, + currentPath: string, + propertyRenameMap: { [pattern: string]: string } +): string { + let finalKey = currentKey; + Object.keys(propertyRenameMap).forEach(pattern => { + if (minimatch(currentPath, pattern)) { + finalKey = propertyRenameMap[pattern]; + } + }); + return finalKey; +} + +it('replacer', () => { + const options = { + camelCase: true, + space: 2, + propertyRenameMap: { + "/assets/*/denom_units": "denominations", + "/assets/[0-1]/logo_URIs": "logos" + }, + propertyReplacer + }; + const jsonString = jsStringify(assetlist, options); + expect(jsonString).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/package.json b/package.json index 14b2a19..2e05ef0 100644 --- a/package.json +++ b/package.json @@ -58,16 +58,17 @@ }, "devDependencies": { "@types/jest": "^29.5.12", - "eslint": "8.38.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.0.0", + "eslint": "8.38.0", "esprima": "4.0.1", - "jest": "^29.5.0", "jest-in-case": "1.0.2", + "jest": "^29.5.0", + "minimatch": "^9.0.4", "prettier": "^2.8.7", "rimraf": "5.0.0", "ts-jest": "^29.1.0", "ts-node": "10.9.2", "typescript": "^5.0.4" } -} +} \ No newline at end of file diff --git a/src/js.ts b/src/js.ts index 2de0b35..ed16caf 100644 --- a/src/js.ts +++ b/src/js.ts @@ -1,14 +1,18 @@ import { camelCaseTransform, escapeStringForBacktickQuotes, escapeStringForDoubleQuotes, escapeStringForSingleQuotes, isSimpleKey } from "./utils"; export interface JSStringifyOptions { - space?: number; // defaults to 0 - replacer?: (this: any, key: string, value: any) => any | null; // defaults to null - quotes?: 'single' | 'double'; // defaults to single - inlineArrayLimit?: number; // default is undefined, allowing inline arrays below this length - camelCase?: boolean; // defaults to false - camelCaseFn?: (str: string) => string; // optional function to convert keys to camelCase + space?: number; + replacer?: (key: string, value: any) => any | null; + propertyReplacer?: (currentKey: string, currentPath: string, propertyRenameMap: { [pattern: string]: string }) => string + quotes?: 'single' | 'double' | 'backtick'; + inlineArrayLimit?: number; + camelCase?: boolean; + camelCaseFn?: (str: string) => string; + propertyRenameMap?: { [key: string]: string }; + json?: boolean; } + export function chooseQuotes(str: string, preferred: 'single' | 'double' | 'backtick'): string { switch (preferred) { case 'single': @@ -22,13 +26,53 @@ export function chooseQuotes(str: string, preferred: 'single' | 'double' | 'back } } +function matchesPattern(path, pattern) { + const pathSegments = path.split('/'); + const patternSegments = pattern.split('/'); + if (pathSegments.length !== patternSegments.length) { + return false; + } + for (let i = 0; i < pathSegments.length; i++) { + if (patternSegments[i] !== '*' && patternSegments[i] !== pathSegments[i]) { + return false; + } + } + return true; +} + +function defaultPropertyReplacer( + currentKey: string, + currentPath: string, + propertyRenameMap: { [pattern: string]: string } +): string { + let finalKey = currentKey; + Object.keys(propertyRenameMap).forEach(pattern => { + if (matchesPattern(currentPath, pattern)) { + finalKey = propertyRenameMap[pattern]; + } + }); + return finalKey; +} + export function jsStringify(obj: any, options?: JSStringifyOptions): string { - const { space = 0, replacer = null, quotes = 'single', inlineArrayLimit = undefined, camelCase = false, camelCaseFn = camelCaseTransform } = options || {}; + const { + space = 0, + replacer = null, + propertyReplacer = null, + quotes = 'single', + inlineArrayLimit = undefined, + camelCase = false, + camelCaseFn = camelCaseTransform, + propertyRenameMap = {}, + json = false // JSON compliance mode + } = options || {}; + const isObject = (val: any): boolean => typeof val === 'object' && val !== null && !Array.isArray(val); + let indentLevel: number = 0; - const serialize = (obj: any): string => { + const serialize = (obj: any, currentPath = "", isArray: boolean = false): string => { if (replacer instanceof Function) { obj = replacer.call(null, '', obj); // Call replacer for the root element initially } @@ -36,29 +80,41 @@ export function jsStringify(obj: any, options?: JSStringifyOptions): string { if (Array.isArray(obj)) { const useInline = inlineArrayLimit !== undefined && obj.length <= inlineArrayLimit; indentLevel++; - const result = '[' + (space && !useInline ? '\n' : '') + obj.map(item => { - return ' '.repeat(useInline ? 0 : indentLevel * space) + serialize(item); + const result = '[' + (space && !useInline ? '\n' : '') + obj.map((item, index) => { + return ' '.repeat(useInline ? 0 : indentLevel * space) + serialize(item, `${currentPath}/${index}`, true); }).join(',' + (space && !useInline ? '\n' : ' ')) + (space && !useInline ? '\n' + ' '.repeat((indentLevel - 1) * space) : '') + ']'; indentLevel--; return result; } else if (isObject(obj)) { indentLevel++; const props = Object.keys(obj).map(key => { + const fullPath = `${currentPath}/${key}`; const value = replacer instanceof Function ? replacer.call(obj, key, obj[key]) : obj[key]; - const transformedKey = camelCase ? camelCaseFn(key) : key; - const keyPart = isSimpleKey(transformedKey) ? transformedKey : `"${transformedKey}"`; - const valuePart = serialize(value); + + + let replacedKey: string; + switch (true) { + case propertyReplacer instanceof Function: + replacedKey = propertyReplacer.call(obj, key, fullPath, propertyRenameMap); + break; + default: + replacedKey = defaultPropertyReplacer(key, fullPath, propertyRenameMap); + } + + const finalKey = camelCase ? camelCaseFn(replacedKey) : replacedKey; + const keyPart = json ? `"${finalKey}"` : isSimpleKey(finalKey) ? finalKey : `"${finalKey}"`; + const valuePart = serialize(value, fullPath); return ' '.repeat(indentLevel * space) + `${keyPart}: ${valuePart}`; }); const result = '{' + (space ? '\n' : '') + props.join(',' + (space ? '\n' : ' ')) + (space ? '\n' + ' '.repeat((indentLevel - 1) * space) : '') + '}'; indentLevel--; return result; } else if (typeof obj === 'string') { - return chooseQuotes(obj, quotes); + return json ? `"${escapeStringForDoubleQuotes(obj)}"` : chooseQuotes(obj, quotes); } else { return String(obj); } }; return serialize(obj); -} \ No newline at end of file +} diff --git a/src/json.ts b/src/json.ts index 2e57b27..8e6e2f3 100644 --- a/src/json.ts +++ b/src/json.ts @@ -1,63 +1,8 @@ -import { camelCaseTransform, isSimpleKey } from "./utils"; +import { jsStringify, JSStringifyOptions } from "./js"; -export interface JSONStringifyOptions { - space?: number; // defaults to 0 - replacer?: (this: any, key: string, value: any) => any; // defaults to null - quotes?: 'single' | 'double'; // defaults to double - inlineArrayLimit?: number; // default is undefined, allowing inline arrays below this length - camelCase?: boolean; // defaults to false - camelCaseFn?: (str: string) => string; // optional function to convert keys to camelCase -} - -function escapeString(str: string): string { - str = str.replace(/\\/g, '\\\\'); // Escape backslashes first - str = str.replace(/\n/g, '\\n'); // Escape newlines - str = str.replace(/\r/g, '\\r'); // Escape carriage returns - str = str.replace(/\t/g, '\\t'); // Escape tabs - str = str.replace(/"/g, '\\"'); // Escape double quotes - return str; -} - -function chooseQuotes(str: string): string { - return `"${escapeString(str)}"`; -} +export interface JSONStringifyOptions extends Omit { } export function jsonStringify(obj: any, options?: JSONStringifyOptions): string { - const { space = 0, replacer = null, quotes = 'double', inlineArrayLimit = undefined, camelCase = false, camelCaseFn = camelCaseTransform } = options || {}; - const isObject = (val: any): boolean => typeof val === 'object' && val !== null && !Array.isArray(val); - let indentLevel: number = 0; - - const serialize = (obj: any): string => { - if (replacer instanceof Function) { - obj = replacer.call(null, '', obj); // Call replacer for the root element initially - } - - if (Array.isArray(obj)) { - const useInline = inlineArrayLimit !== undefined && obj.length <= inlineArrayLimit; - indentLevel++; - const result = '[' + (space && !useInline ? '\n' : '') + obj.map(item => { - return ' '.repeat(useInline ? 0 : indentLevel * space) + serialize(item); - }).join(',' + (space && !useInline ? '\n' : ' ')) + (space && !useInline ? '\n' + ' '.repeat((indentLevel - 1) * space) : '') + ']'; - indentLevel--; - return result; - } else if (isObject(obj)) { - indentLevel++; - const props = Object.keys(obj).map(key => { - const value = replacer instanceof Function ? replacer.call(obj, key, obj[key]) : obj[key]; - const transformedKey = camelCase ? camelCaseFn(key) : key; - const keyPart = isSimpleKey(transformedKey) ? transformedKey : chooseQuotes(transformedKey); - const valuePart = serialize(value); - return ' '.repeat(indentLevel * space) + `${keyPart}: ${valuePart}`; - }); - const result = '{' + (space ? '\n' : '') + props.join(',' + (space ? '\n' : ' ')) + (space ? '\n' + ' '.repeat((indentLevel - 1) * space) : '') + '}'; - indentLevel--; - return result; - } else if (typeof obj === 'string') { - return chooseQuotes(obj); - } else { - return String(obj); - } - }; - - return serialize(obj); + // Set json option to true and spread the rest of the options + return jsStringify(obj, { ...options, json: true }); } diff --git a/types/index.d.ts b/types/index.d.ts index 37bca66..99130f6 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,11 +1,2 @@ -interface StringifyOptions { - space?: number; - replacer?: (this: any, key: string, value: any) => any | null; - quotes?: 'single' | 'double'; - inlineArrayLimit?: number; - camelCase?: boolean; - camelCaseFn?: (str: string) => string; -} -export declare function chooseQuotes(str: string, preferred: 'single' | 'double' | 'backtick'): string; -export declare function jsStringify(obj: any, options?: StringifyOptions): string; -export {}; +export * from './js'; +export * from './json'; diff --git a/types/js.d.ts b/types/js.d.ts new file mode 100644 index 0000000..320b820 --- /dev/null +++ b/types/js.d.ts @@ -0,0 +1,13 @@ +export interface JSStringifyOptions { + space?: number; + replacer?: (this: any, key: string, value: any) => any | null; + quotes?: 'single' | 'double' | 'backtick'; + inlineArrayLimit?: number; + camelCase?: boolean; + camelCaseFn?: (str: string) => string; + propertyRenameMap?: { + [key: string]: string; + }; +} +export declare function chooseQuotes(str: string, preferred: 'single' | 'double' | 'backtick'): string; +export declare function jsStringify(obj: any, options?: JSStringifyOptions): string; diff --git a/types/json.d.ts b/types/json.d.ts new file mode 100644 index 0000000..94177f4 --- /dev/null +++ b/types/json.d.ts @@ -0,0 +1,9 @@ +export interface JSONStringifyOptions { + space?: number; + replacer?: (this: any, key: string, value: any) => any; + quotes?: 'single' | 'double'; + inlineArrayLimit?: number; + camelCase?: boolean; + camelCaseFn?: (str: string) => string; +} +export declare function jsonStringify(obj: any, options?: JSONStringifyOptions): string; diff --git a/types/utils.d.ts b/types/utils.d.ts new file mode 100644 index 0000000..2a0196c --- /dev/null +++ b/types/utils.d.ts @@ -0,0 +1,5 @@ +export declare function camelCaseTransform(key: string): string; +export declare function isSimpleKey(key: string): boolean; +export declare function escapeStringForSingleQuotes(str: string): string; +export declare function escapeStringForDoubleQuotes(str: string): string; +export declare function escapeStringForBacktickQuotes(str: string): string;