├── .all-contributorsrc ├── .bettercodehub.yml ├── .codecov.yml ├── .eslintignore ├── .eslintrc.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── BUG.md │ ├── DOCS.md │ ├── FEATURE.md │ ├── QUESTION.md │ ├── REGRESSION.md │ └── SECURITY.md ├── PULL_REQUEST_TEMPLATE.md ├── config.yml ├── eslint-disable-bot.yml ├── issue-states.yml ├── issue_label_bot.yaml ├── stale.yml └── workflows │ ├── nodejs.yml │ ├── semantic-pr.yml │ ├── semantic-release.yml │ └── snyk.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .releaserc ├── .remarkignore ├── .remarkrc ├── .snyk ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── src ├── __tests__ │ ├── index.js │ ├── intact.js │ ├── more.js │ └── utils.js ├── fixer.js ├── json.pegjs ├── json.pjs ├── test.utils.js ├── transform.js └── utils.js └── test ├── samples ├── b.json ├── bin.json ├── comment.json ├── concat.json ├── doublyMissingQuotes.json ├── doublyMissingQuotesMin.json ├── exp.json ├── extraBrackets.json ├── extraChar.json ├── fp.json ├── hex.json ├── issue31.json ├── lefty1.json ├── lefty2.json ├── leftyO.json ├── missing.json ├── missingLHQuotes.json ├── missingQuotes.json ├── monOps.json ├── multiComment.json ├── multiOps.json ├── newLines.json ├── noLHQuotes.json ├── noQuotes.json ├── normal.json ├── notCurly.json ├── notSquare.json ├── o.json ├── oct.json ├── ops.json ├── quoteInQuotes.json ├── singleQuote.json ├── smComment.json ├── tab.json ├── tabs.json ├── threeErrs.json ├── trailingChar.json ├── trailingComma.json ├── trailingDot.json ├── twoErrs.json └── x.json └── sandbox.js /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "json-fixer", 3 | "projectOwner": "Berkmann18", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "angular", 12 | "contributors": [ 13 | { 14 | "login": "Berkmann18", 15 | "name": "Maximilian Berkmann", 16 | "avatar_url": "https://avatars0.githubusercontent.com/u/8260834?v=4", 17 | "profile": "http://maxcubing.wordpress.com", 18 | "contributions": [ 19 | "code", 20 | "doc", 21 | "ideas", 22 | "maintenance", 23 | "test", 24 | "security" 25 | ] 26 | }, 27 | { 28 | "login": "semantic-release-bot", 29 | "name": "Semantic Release Bot", 30 | "avatar_url": "https://avatars1.githubusercontent.com/u/32174276?v=4", 31 | "profile": "http://semantic-release.org/", 32 | "contributions": [ 33 | "platform", 34 | "doc" 35 | ] 36 | }, 37 | { 38 | "login": "all-contributors[bot]", 39 | "name": "all-contributors[bot]", 40 | "avatar_url": "https://avatars1.githubusercontent.com/u/649578?v=4", 41 | "profile": "https://github.com/apps/all-contributors", 42 | "contributions": [ 43 | "doc" 44 | ] 45 | }, 46 | { 47 | "login": "Bkucera", 48 | "name": "Ben Kucera", 49 | "avatar_url": "https://avatars0.githubusercontent.com/u/14625260?v=4", 50 | "profile": "https://github.com/Bkucera", 51 | "contributions": [ 52 | "code" 53 | ] 54 | }, 55 | { 56 | "login": "SvetozarMateev", 57 | "name": "Svetozar Mateev", 58 | "avatar_url": "https://avatars3.githubusercontent.com/u/25162335?v=4", 59 | "profile": "https://github.com/SvetozarMateev", 60 | "contributions": [ 61 | "bug", 62 | "code" 63 | ] 64 | }, 65 | { 66 | "login": "andre-paulo98", 67 | "name": "André Paulo", 68 | "avatar_url": "https://avatars1.githubusercontent.com/u/19685105?v=4", 69 | "profile": "https://andrepaulo.me", 70 | "contributions": [ 71 | "bug" 72 | ] 73 | }, 74 | { 75 | "login": "Erkin97", 76 | "name": "Erkin Matkaziev", 77 | "avatar_url": "https://avatars2.githubusercontent.com/u/22586805?v=4", 78 | "profile": "https://www.linkedin.com/in/erkinmatkaziev/", 79 | "contributions": [ 80 | "bug" 81 | ] 82 | }, 83 | { 84 | "login": "codacy-badger", 85 | "name": "Codacy Badger", 86 | "avatar_url": "https://avatars3.githubusercontent.com/u/23704769?v=4", 87 | "profile": "https://www.codacy.com/", 88 | "contributions": [ 89 | "infra", 90 | "doc" 91 | ] 92 | }, 93 | { 94 | "login": "GiraffeKey", 95 | "name": "GiraffeKey", 96 | "avatar_url": "https://avatars2.githubusercontent.com/u/11844126?v=4", 97 | "profile": "https://github.com/GiraffeKey", 98 | "contributions": [ 99 | "code", 100 | "test" 101 | ] 102 | }, 103 | { 104 | "login": "jonasmaertens", 105 | "name": "jonasmaertens", 106 | "avatar_url": "https://avatars3.githubusercontent.com/u/71458938?v=4", 107 | "profile": "https://github.com/jonasmaertens", 108 | "contributions": [ 109 | "bug" 110 | ] 111 | }, 112 | { 113 | "login": "Geoxor", 114 | "name": "George Tsotsos", 115 | "avatar_url": "https://avatars.githubusercontent.com/u/34042825?v=4", 116 | "profile": "https://geoxor.moe", 117 | "contributions": [ 118 | "code" 119 | ] 120 | } 121 | ], 122 | "contributorsPerLine": 7, 123 | "skipCi": true 124 | } 125 | -------------------------------------------------------------------------------- /.bettercodehub.yml: -------------------------------------------------------------------------------- 1 | exclude: 2 | - /dist/.* 3 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: off 4 | changes: on 5 | patch: 6 | default: 7 | target: auto 8 | base: pr 9 | 10 | comment: off 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/samples/*.json 2 | test/sandbox.js 3 | src/json.js 4 | dist 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "plugins": [ 8 | "standard", 9 | "node", 10 | "security", 11 | "jest", 12 | "jquery" 13 | ], 14 | "extends": [ 15 | "eslint:recommended", 16 | "plugin:security/recommended", 17 | "plugin:node/recommended", 18 | "plugin:you-dont-need-lodash-underscore/compatible" 19 | ], 20 | "rules": { 21 | "indent": [ 22 | "error", 23 | 2 24 | ], 25 | "linebreak-style": [ 26 | "error" 27 | ], 28 | "no-console": "off", 29 | "no-extra-semi": "off", 30 | "no-process-exit": "warn", 31 | "prefer-const": "warn", 32 | "no-trailing-spaces": [ 33 | "error" 34 | ], 35 | "semi": "off", 36 | "symbol-description": [ 37 | "warn" 38 | ], 39 | "jest/no-disabled-tests": "error", 40 | "jest/no-focused-tests": "error", 41 | "jest/no-identical-title": "error", 42 | "node/no-unsupported-features": "off", 43 | "node/no-unsupported-features/es-syntax": "off", 44 | "node/no-unpublished-require": "off" 45 | }, 46 | "parserOptions": { 47 | "ecmaVersion": 9, 48 | "ecmaFeatures": { 49 | "impliedStrict": true 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Berkmann18 2 | patreon: berkmann18 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug report 3 | about: Create a report to help us improve 4 | labels: 'Type: Bug :bug:, Priority: Medium' 5 | --- 6 | 7 | 8 | 9 | ## Expected behaviour 10 | 11 | ## Actual behaviour 12 | 13 | ## How to reproduce 14 | 15 | 16 | 17 | ## Possible solution(s) 18 | 19 | 20 | 21 | ## Environment 22 | 23 | - Version: 24 | - OS(s): 25 | - Browser(s) (if applicable): 26 | - Node version: 27 | - NPM version: 28 | 29 | ## Link or repo 30 | 31 | 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/DOCS.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📖 Documentation issue 3 | about: Create a report to improve the documentation 4 | labels: 'Type: Documentation :book:, Priority: Medium' 5 | --- 6 | 7 | 8 | 9 | ## Expected information 10 | 11 | ## Actual information 12 | 13 | ## Possible solutions 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature request 3 | about: Submit a proposal for a feature request 4 | labels: 'Type: Enhancement :bulb:, Priority: Low' 5 | --- 6 | 7 | 8 | 9 | ## Proposal 10 | 11 | ## Motivation 12 | 13 | ## Use cases and examples 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/QUESTION.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💬 Question 3 | about: Need support or a question in mind? 4 | labels: 'Type: Question :grey_question:, Priority: Low' 5 | --- 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/REGRESSION.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💥 Regression Report 3 | about: Report unexpected behaviour that worked in previous versions 4 | labels: 'Type: Regression :boom:, Priority: Medium' 5 | --- 6 | 7 | 8 | 9 | ## Expected behaviour 10 | 11 | 12 | 13 | ## Versions 14 | 15 | It worked up to: 16 | It stopped working in version: 17 | 18 | ## How to reproduce 19 | 20 | 21 | 22 | ## Environment 23 | 24 | - Version: 25 | - OS(s): 26 | - Browser(s) (if applicable): 27 | - Node version: 28 | - NPM version: 29 | 30 | ## Link or repo 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/SECURITY.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ⚠️ Security issue disclosure 3 | about: Report a security issue 4 | title: 'Security vulnerability' 5 | labels: 'Type: Vulnerability :warning:, Priority: High' 6 | --- 7 | 8 | Please email us/me in order to report the security vulnerability. 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Checklist 2 | 3 | - [ ] The PR follows the [guidelines](CONTRIBUTING.md) 4 | - [ ] Passes all the tests (including added/updated ones) 5 | - [ ] Contains a valid documentation 6 | - [ ] It's not a duplicate from another PR 7 | 8 | ## Changes 9 | 10 | This PR implements: 11 | 12 | - [ ] Bugfix 13 | - [ ] Feature 14 | - [ ] Refactoring 15 | - [ ] Documentation/wiki/tutorial update 16 | - [ ] Code style update 17 | - [ ] Build related change 18 | - [ ] Other, please specify: 19 | 20 | ## Details 21 | 22 | What does this PR implement exactly? 23 | 24 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | ## Configuration for request-info - https://github.com/behaviorbot/request-info 2 | 3 | # *Required* Comment to reply with 4 | #requestInfoReplyComment: > 5 | # We would appreciate it if you could provide us with more info about this issue/PR! 6 | 7 | # *OPTIONAL* default titles to check against for lack of descriptiveness 8 | # MUST BE ALL LOWERCASE 9 | requestInfoDefaultTitles: 10 | - update readme.md 11 | - updates 12 | - error 13 | - issue 14 | 15 | # *OPTIONAL* Label to be added to Issues and Pull Requests with insufficient information given 16 | requestInfoLabelToAdd: needs-more-info 17 | 18 | requestInfoReplyComment: > 19 | We would appreciate it if you could provide us with more info about this 20 | issue/PR! 21 | 22 | ## Configuration for todo - https://github.com/jasonetco/todo 23 | todo: 24 | keyword: '@makeAnIssue' 25 | 26 | # Configuration for welcome - https://github.com/behaviorbot/welcome 27 | # Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome 28 | 29 | # Comment to be posted to on first time issues 30 | newIssueWelcomeComment: > 31 | Thanks for opening your first issue here! Be sure to follow the issue 32 | templates :simple_smile: ! 33 | 34 | # Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome 35 | 36 | # Comment to be posted to on PRs from first time contributors in your repository 37 | newPRWelcomeComment: > 38 | Thanks for opening this PR (Pull Request)! Please check out our [contributing 39 | guidelines](https://github.com/Berkmann18/community-starter-kit/blob/master/CONTRIBUTING.md). 40 | 41 | # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge 42 | 43 | # Comment to be posted to on pull requests merged by a first time user 44 | firstPRMergeComment: > 45 | :tada: Congrats on merging your first PR! We are proud of you! 46 | 47 | #requestInfoLabelToAdd: request-info 48 | 49 | # Configuration for sentiment-bot - https://github.com/behaviorbot/sentiment-bot 50 | 51 | # *Required* toxicity threshold between 0 and .99 with the higher numbers being the most toxic 52 | # Anything higher than this threshold will be marked as toxic and commented on 53 | sentimentBotToxicityThreshold: .7 54 | 55 | # *Required* Comment to reply with 56 | sentimentBotReplyComment: > 57 | Please be sure to review the code of conduct and be respectful of other users. 58 | cc/ @Berkmann18 59 | 60 | # Configuration for issuelabeler - https://riyadhalnur.github.io/issuelabeler/ 61 | # Number of labels to fetch (optional). Defaults to 20 62 | numLabels: 40 63 | # These labels will not be used even if the issue contains them (optional). 64 | # Pass a blank array if no labels are to be excluded. 65 | excludeLabels: [] 66 | -------------------------------------------------------------------------------- /.github/eslint-disable-bot.yml: -------------------------------------------------------------------------------- 1 | # Change this to set the number of comments the watcher should comment on a given PR. 2 | commentLimit: 20 3 | # The message the bot will post on any lines containing a eslint disable comment. 4 | commentMessage: "Please don't disable eslint rules :pray:" 5 | # A optional regular expression that will match against the branch name and not comment on it if it matches. 6 | skipBranchMatching: null 7 | -------------------------------------------------------------------------------- /.github/issue-states.yml: -------------------------------------------------------------------------------- 1 | # Configuration for issue-states - https://github.com/dessant/issue-states 2 | 3 | # Open issues that are moved to these project columns. Set to `[]` to disable 4 | openIssueColumns: 5 | - To do 6 | - In Progress 7 | - Needs review 8 | - Reviewer approved 9 | 10 | # Close issues that are moved to these project columns. Set to `[]` to disable 11 | closedIssueColumns: 12 | - Closed 13 | - Done 14 | # Repository to extend settings from 15 | # _extends: repo 16 | -------------------------------------------------------------------------------- /.github/issue_label_bot.yaml: -------------------------------------------------------------------------------- 1 | label-alias: 2 | bug: 'Type: Bug :bug:' 3 | feature_request: 'Type: Enhancement :bulb:' 4 | question: 'Type: Question :grey_question:' 5 | doc: 'Type: Documentation :book:' 6 | regression: 'Type: Regression :boom:' 7 | security: 'Type: Vulnerability :warning:' 8 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 60 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 14 9 | 10 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 11 | exemptLabels: 12 | - 'Status: On Hold :stop_sign:' 13 | - 'Type: Vulnerability :warning' 14 | - security 15 | - 'Status: Accepted :heavy_check_mark:' 16 | 17 | # Set to true to ignore issues in a project (defaults to false) 18 | exemptProjects: false 19 | 20 | # Set to true to ignore issues in a milestone (defaults to false) 21 | exemptMilestones: false 22 | 23 | # Label to use when marking as stale 24 | staleLabel: 'Status: Left Out :left_luggage:' 25 | 26 | # Comment to post when marking as stale. Set to `false` to disable 27 | markComment: > 28 | This issue has been automatically marked as stale because it has not had 29 | recent activity. It will be closed if no further activity occurs. Thank you 30 | for your contributions. 31 | 32 | # Comment to post when removing the stale label. 33 | unmarkComment: > 34 | This issue is no longer stale. 35 | 36 | # Comment to post when closing a stale Issue or Pull Request. 37 | closeComment: > 38 | This issue has been stale for 14 days so I'm closing it. 39 | 40 | # Limit the number of actions per hour, from 1-30. Default is 30 41 | limitPerRun: 30 42 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [master, dev] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: ['lts/*', 'node'] 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Node ${{ matrix.node-version }} using nvm 20 | uses: dcodeIO/setup-node-nvm@master 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - run: | 24 | npm ci 25 | npm run lint 26 | npm run build --if-present 27 | - run: npm t 28 | env: 29 | CI: true 30 | - name: Codecov 31 | uses: codecov/codecov-action@v1.0.7 32 | -------------------------------------------------------------------------------- /.github/workflows/semantic-pr.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: amannn/action-semantic-pull-request@v1.1.1 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /.github/workflows/semantic-release.yml: -------------------------------------------------------------------------------- 1 | name: Semantic Release 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | jobs: 8 | build-and-deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | - name: Setup Node 14 | uses: actions/setup-node@v1 15 | with: 16 | node-version: '12.x' 17 | - run: | 18 | npm ci 19 | npm run build 20 | - name: Semantic Release 21 | uses: cycjimmy/semantic-release-action@v2 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/snyk.yml: -------------------------------------------------------------------------------- 1 | name: So Now You Know 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | security: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@master 14 | - name: Run Snyk to check for vulnerabilities 15 | uses: snyk/actions/node@master 16 | env: 17 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} 18 | with: 19 | command: monitor 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # Editors 64 | .idea 65 | .vscode 66 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | .github 3 | .prettierignore 4 | .vscode 5 | **/*.spec.* 6 | coverage 7 | .nyc_output 8 | *.log 9 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 8.14.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | test/samples/*.json 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "semi": true, 6 | "trailingComma": "none", 7 | "useTabs": false, 8 | "bracketSpacing": true 9 | } -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | ["@semantic-release/changelog", { 6 | "changelogFile": "CHANGELOG.md" 7 | }], 8 | "@semantic-release/npm", 9 | "@semantic-release/github", 10 | ["@semantic-release/git", { 11 | "assets": ["src/*.{js,pjs}", "!src/test.utils.js", "index.js", "package.json", "package-lock.json", "LICENSE", "README.md", "CHANGELOG.md"], 12 | "message": "chore: release ${nextRelease.version} :tada: [skip ci]\n\n${nextRelease.notes}" 13 | }] 14 | ] 15 | } -------------------------------------------------------------------------------- /.remarkignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md -------------------------------------------------------------------------------- /.remarkrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "remark-preset-lint-recommended", 4 | "remark-preset-lint-consistent" 5 | ] 6 | } -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.14.1 3 | ignore: {} 4 | patch: {} 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.6.15](https://github.com/Berkmann18/json-fixer/compare/v1.6.14...v1.6.15) (2022-09-06) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * upgrade @babel/runtime from 7.17.9 to 7.18.9 ([85d95e5](https://github.com/Berkmann18/json-fixer/commit/85d95e5f5656a2a3783f507fd069c35d9f13f478)) 7 | 8 | ## [1.6.14](https://github.com/Berkmann18/json-fixer/compare/v1.6.13...v1.6.14) (2022-08-16) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * upgrade @babel/runtime from 7.14.6 to 7.17.9 ([18b13f3](https://github.com/Berkmann18/json-fixer/commit/18b13f38c76e2972221aaa83145b3ff76fadfadf)) 14 | 15 | ## [1.6.13](https://github.com/Berkmann18/json-fixer/compare/v1.6.12...v1.6.13) (2021-11-29) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * upgrade chalk from 4.1.1 to 4.1.2 ([2e67a23](https://github.com/Berkmann18/json-fixer/commit/2e67a235950e18006f13b344deca56a47410689d)) 21 | 22 | ## [1.6.12](https://github.com/Berkmann18/json-fixer/compare/v1.6.11...v1.6.12) (2021-07-12) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * upgrade @babel/runtime from 7.14.5 to 7.14.6 ([daa5e08](https://github.com/Berkmann18/json-fixer/commit/daa5e0801998edb1a1f2b244eb7f0e024e99327d)) 28 | 29 | ## [1.6.11](https://github.com/Berkmann18/json-fixer/compare/v1.6.10...v1.6.11) (2021-07-07) 30 | 31 | 32 | ### Bug Fixes 33 | 34 | * upgrade @babel/runtime from 7.14.0 to 7.14.5 ([319709b](https://github.com/Berkmann18/json-fixer/commit/319709bc2d122d8c2c70ae4c01da7ffea1bcf9b6)) 35 | 36 | ## [1.6.10](https://github.com/Berkmann18/json-fixer/compare/v1.6.9...v1.6.10) (2021-06-03) 37 | 38 | 39 | ### Bug Fixes 40 | 41 | * upgrade @babel/runtime from 7.12.5 to 7.14.0 ([dbfd063](https://github.com/Berkmann18/json-fixer/commit/dbfd063ef5313fc707e982414423c6e0c8c99411)) 42 | 43 | ## [1.6.9](https://github.com/Berkmann18/json-fixer/compare/v1.6.8...v1.6.9) (2021-05-14) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * upgrade chalk from 4.1.0 to 4.1.1 ([549ea47](https://github.com/Berkmann18/json-fixer/commit/549ea4702a2ff3dc5bcb537385196720a2790c01)) 49 | 50 | ## [1.6.8](https://github.com/Berkmann18/json-fixer/compare/v1.6.7...v1.6.8) (2020-11-25) 51 | 52 | 53 | ### Bug Fixes 54 | 55 | * upgrade @babel/runtime from 7.12.1 to 7.12.5 ([d77dc09](https://github.com/Berkmann18/json-fixer/commit/d77dc09d01b936f6919f8f91d87662050056ec48)) 56 | 57 | ## [1.6.7](https://github.com/Berkmann18/json-fixer/compare/v1.6.6...v1.6.7) (2020-11-08) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * upgrade @babel/runtime from 7.12.0 to 7.12.1 ([116409f](https://github.com/Berkmann18/json-fixer/commit/116409fffa8b7ebf793e289c62910c6ab940833c)) 63 | 64 | ## [1.6.6](https://github.com/Berkmann18/json-fixer/compare/v1.6.5...v1.6.6) (2020-11-07) 65 | 66 | 67 | ### Bug Fixes 68 | 69 | * upgrade @babel/runtime from 7.11.2 to 7.12.0 ([5949534](https://github.com/Berkmann18/json-fixer/commit/594953453acacd14d77eab6402fb98c5ce302bc8)) 70 | 71 | ## [1.6.5](https://github.com/Berkmann18/json-fixer/compare/v1.6.4...v1.6.5) (2020-10-08) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * **fixer:** addressed DeepScan's issue ([2c5868d](https://github.com/Berkmann18/json-fixer/commit/2c5868d3d89fcde097ddbe7a5be9410f551701ee)) 77 | * **fixer:** removed futile LOC ([56f23a1](https://github.com/Berkmann18/json-fixer/commit/56f23a1cee0cfa6546dc212ee6b471b80a7e7529)) 78 | * fixes special characters ([4e804e5](https://github.com/Berkmann18/json-fixer/commit/4e804e5e041fd7e75d2a6a95dcedca6011acefea)) 79 | 80 | ## [1.6.4](https://github.com/Berkmann18/json-fixer/compare/v1.6.3...v1.6.4) (2020-10-08) 81 | 82 | 83 | ### Bug Fixes 84 | 85 | * upgrade @babel/runtime from 7.11.0 to 7.11.2 ([73e644e](https://github.com/Berkmann18/json-fixer/commit/73e644edde358afbd9a582cec5755a7797a64671)) 86 | 87 | ## [1.6.3](https://github.com/Berkmann18/json-fixer/compare/v1.6.2...v1.6.3) (2020-08-26) 88 | 89 | 90 | ### Bug Fixes 91 | 92 | * upgrade @babel/runtime from 7.10.5 to 7.11.0 ([4cc9017](https://github.com/Berkmann18/json-fixer/commit/4cc90175f75b230d28bb737c9d0cb6384f0ed7b6)) 93 | 94 | ## [1.6.2](https://github.com/Berkmann18/json-fixer/compare/v1.6.1...v1.6.2) (2020-08-26) 95 | 96 | 97 | ### Bug Fixes 98 | 99 | * **lockfile:** security update ([54c3bf0](https://github.com/Berkmann18/json-fixer/commit/54c3bf0532be98126e2f6b6b04707a7f5c2a8b73)) 100 | * **lockfile:** vulnerability fix ([4b501a8](https://github.com/Berkmann18/json-fixer/commit/4b501a8ee6c9c3b015f43651b43bef4f6a08056d)) 101 | 102 | ## [1.6.1](https://github.com/Berkmann18/json-fixer/compare/v1.6.0...v1.6.1) (2020-08-24) 103 | 104 | 105 | ### Bug Fixes 106 | 107 | * upgrade @babel/runtime from 7.10.4 to 7.10.5 ([cf9367b](https://github.com/Berkmann18/json-fixer/commit/cf9367b18e8551e47eee381b65103f920b81ed82)) 108 | 109 | # [1.6.0](https://github.com/Berkmann18/json-fixer/compare/v1.5.4...v1.6.0) (2020-08-24) 110 | 111 | 112 | ### Features 113 | 114 | * **extra-brackets:** fix extra brackets ([6958b4b](https://github.com/Berkmann18/json-fixer/commit/6958b4b7d209fd128c1241ab4868190195defaab)) 115 | 116 | ## [1.5.4](https://github.com/Berkmann18/json-fixer/compare/v1.5.3...v1.5.4) (2020-07-22) 117 | 118 | 119 | ### Bug Fixes 120 | 121 | * upgrade @babel/runtime from 7.10.3 to 7.10.4 ([11ec2a7](https://github.com/Berkmann18/json-fixer/commit/11ec2a7bafa7a945db0228f33cd191b3075528c4)) 122 | 123 | ## [1.5.3](https://github.com/Berkmann18/json-fixer/compare/v1.5.2...v1.5.3) (2020-07-11) 124 | 125 | 126 | ### Bug Fixes 127 | 128 | * upgrade @babel/runtime from 7.10.2 to 7.10.3 ([a643b9b](https://github.com/Berkmann18/json-fixer/commit/a643b9b49f6a3d6591c8700c7d3f1815e7d9c51a)) 129 | 130 | ## [1.5.2](https://github.com/Berkmann18/json-fixer/compare/v1.5.1...v1.5.2) (2020-07-01) 131 | 132 | 133 | ### Bug Fixes 134 | 135 | * upgrade chalk from 4.0.0 to 4.1.0 ([21f39eb](https://github.com/Berkmann18/json-fixer/commit/21f39ebd909f218aa59ef3320e9b4c2016207040)) 136 | 137 | ## [1.5.1](https://github.com/Berkmann18/json-fixer/compare/v1.5.0...v1.5.1) (2020-06-27) 138 | 139 | 140 | ### Bug Fixes 141 | 142 | * security fix ([a306d58](https://github.com/Berkmann18/json-fixer/commit/a306d586dcd4ac09611adbc02a270b3bc186c8cf)) 143 | 144 | # [1.5.0](https://github.com/Berkmann18/json-fixer/compare/v1.4.1...v1.5.0) (2020-06-27) 145 | 146 | 147 | ### Bug Fixes 148 | 149 | * **fixer:** fixing missing LHS quotes with 1-2 chars ([e2f8b9d](https://github.com/Berkmann18/json-fixer/commit/e2f8b9d2ae0f7c0f8bd79c11851a22628e0c5061)) 150 | * **fixer:** lint fix ([bbf3ed9](https://github.com/Berkmann18/json-fixer/commit/bbf3ed9947b568dda5ad44e3f976a0900a1b7d72)) 151 | * **fixer:** wrongly added missing quote ([2ee5e4f](https://github.com/Berkmann18/json-fixer/commit/2ee5e4f299b6d654a3066ed43066196054adaee9)), closes [#31](https://github.com/Berkmann18/json-fixer/issues/31) 152 | * **index:** not applying trailing-char fixes on LHS issues ([253ebfc](https://github.com/Berkmann18/json-fixer/commit/253ebfced66db18e883d22b63e019967629d1212)), closes [#38](https://github.com/Berkmann18/json-fixer/issues/38) 153 | * missing quote fixer failure ([60a5fff](https://github.com/Berkmann18/json-fixer/commit/60a5fff5be2683732a1996fe8c10179ac83f534c)) 154 | * security fix ([067bd46](https://github.com/Berkmann18/json-fixer/commit/067bd46695aa540b517b620987d4506b82050c25)) 155 | * **lockfile:** security fix ([cade206](https://github.com/Berkmann18/json-fixer/commit/cade206a43f05ebd3c16f96c2d44e22c368277b8)) 156 | 157 | 158 | ### Features 159 | 160 | * **fixer:** trailing char fixer simplification ([5899676](https://github.com/Berkmann18/json-fixer/commit/5899676ae39de659b1ccf77705a6161e22143b21)) 161 | 162 | ## [1.4.2](https://github.com/Berkmann18/json-fixer/compare/v1.4.1...v1.4.2) (2020-06-18) 163 | 164 | 165 | ### Bug Fixes 166 | 167 | * missing quote fixer failure ([60a5fff](https://github.com/Berkmann18/json-fixer/commit/60a5fff5be2683732a1996fe8c10179ac83f534c)) 168 | * **fixer:** lint fix ([bbf3ed9](https://github.com/Berkmann18/json-fixer/commit/bbf3ed9947b568dda5ad44e3f976a0900a1b7d72)) 169 | * security fix ([067bd46](https://github.com/Berkmann18/json-fixer/commit/067bd46695aa540b517b620987d4506b82050c25)) 170 | * **fixer:** wrongly added missing quote ([2ee5e4f](https://github.com/Berkmann18/json-fixer/commit/2ee5e4f299b6d654a3066ed43066196054adaee9)), closes [#31](https://github.com/Berkmann18/json-fixer/issues/31) 171 | * **lockfile:** security fix ([cade206](https://github.com/Berkmann18/json-fixer/commit/cade206a43f05ebd3c16f96c2d44e22c368277b8)) 172 | 173 | ## [1.4.2](https://github.com/Berkmann18/json-fixer/compare/v1.4.1...v1.4.2) (2020-06-17) 174 | 175 | 176 | ### Bug Fixes 177 | 178 | * missing quote fixer failure ([60a5fff](https://github.com/Berkmann18/json-fixer/commit/60a5fff5be2683732a1996fe8c10179ac83f534c)) 179 | * **fixer:** lint fix ([bbf3ed9](https://github.com/Berkmann18/json-fixer/commit/bbf3ed9947b568dda5ad44e3f976a0900a1b7d72)) 180 | * security fix ([067bd46](https://github.com/Berkmann18/json-fixer/commit/067bd46695aa540b517b620987d4506b82050c25)) 181 | * **fixer:** wrongly added missing quote ([2ee5e4f](https://github.com/Berkmann18/json-fixer/commit/2ee5e4f299b6d654a3066ed43066196054adaee9)), closes [#31](https://github.com/Berkmann18/json-fixer/issues/31) 182 | * **lockfile:** security fix ([cade206](https://github.com/Berkmann18/json-fixer/commit/cade206a43f05ebd3c16f96c2d44e22c368277b8)) 183 | 184 | ## [1.4.2](https://github.com/Berkmann18/json-fixer/compare/v1.4.1...v1.4.2) (2020-06-17) 185 | 186 | 187 | ### Bug Fixes 188 | 189 | * missing quote fixer failure ([60a5fff](https://github.com/Berkmann18/json-fixer/commit/60a5fff5be2683732a1996fe8c10179ac83f534c)) 190 | * **fixer:** lint fix ([bbf3ed9](https://github.com/Berkmann18/json-fixer/commit/bbf3ed9947b568dda5ad44e3f976a0900a1b7d72)) 191 | * security fix ([067bd46](https://github.com/Berkmann18/json-fixer/commit/067bd46695aa540b517b620987d4506b82050c25)) 192 | * **fixer:** wrongly added missing quote ([2ee5e4f](https://github.com/Berkmann18/json-fixer/commit/2ee5e4f299b6d654a3066ed43066196054adaee9)), closes [#31](https://github.com/Berkmann18/json-fixer/issues/31) 193 | * **lockfile:** security fix ([cade206](https://github.com/Berkmann18/json-fixer/commit/cade206a43f05ebd3c16f96c2d44e22c368277b8)) 194 | 195 | ## [1.4.3](https://github.com/Berkmann18/json-fixer/compare/v1.4.2...v1.4.3) (2020-06-17) 196 | 197 | 198 | ### Bug Fixes 199 | 200 | * missing quote fixer failure ([60a5fff](https://github.com/Berkmann18/json-fixer/commit/60a5fff5be2683732a1996fe8c10179ac83f534c)) 201 | * **fixer:** lint fix ([bbf3ed9](https://github.com/Berkmann18/json-fixer/commit/bbf3ed9947b568dda5ad44e3f976a0900a1b7d72)) 202 | 203 | ## ~[1.4.2](https://github.com/Berkmann18/json-fixer/compare/v1.4.1...v1.4.2)~ (2020-06-08) 204 | 205 | 206 | ### Bug Fixes 207 | 208 | * security fix ([067bd46](https://github.com/Berkmann18/json-fixer/commit/067bd46695aa540b517b620987d4506b82050c25)) 209 | 210 | ## [1.4.2](https://github.com/Berkmann18/json-fixer/compare/v1.4.1...v1.4.2) (2020-06-07) 211 | 212 | 213 | ### Bug Fixes 214 | 215 | * **fixer:** wrongly added missing quote ([2ee5e4f](https://github.com/Berkmann18/json-fixer/commit/2ee5e4f299b6d654a3066ed43066196054adaee9)), closes [#31](https://github.com/Berkmann18/json-fixer/issues/31) 216 | * **lockfile:** security fix ([cade206](https://github.com/Berkmann18/json-fixer/commit/cade206a43f05ebd3c16f96c2d44e22c368277b8)) 217 | 218 | ## [1.4.1](https://github.com/Berkmann18/json-fixer/compare/v1.4.0...v1.4.1) (2020-04-04) 219 | 220 | 221 | ### Bug Fixes 222 | 223 | * **package:** vulnerability fix ([7914f15](https://github.com/Berkmann18/json-fixer/commit/7914f156e9554000b1cb753aaccf07b77e3aadb7)) 224 | 225 | # [1.4.0](https://github.com/Berkmann18/json-fixer/compare/v1.3.2...v1.4.0) (2019-12-15) 226 | 227 | 228 | ### Bug Fixes 229 | 230 | * **fixer:** improved trailing character fixer ([d671f0c](https://github.com/Berkmann18/json-fixer/commit/d671f0c68d62bbb11919fdad3bf128f71fb20d84)), closes [#18](https://github.com/Berkmann18/json-fixer/issues/18) 231 | * **package-lock:** vulnerability fix ([a61b48a](https://github.com/Berkmann18/json-fixer/commit/a61b48abd7ebe3a6fb429e6934329a32e10d2100)) 232 | * **security:** bumped outdated packages + fixed vulnerabilities ([78bf487](https://github.com/Berkmann18/json-fixer/commit/78bf48760143eff21316faaa95ed8307a72f4d49)) 233 | 234 | 235 | ### Features 236 | 237 | * added options object with parse option ([#21](https://github.com/Berkmann18/json-fixer/issues/21)) ([22874df](https://github.com/Berkmann18/json-fixer/commit/22874dfa67135a2bf6e8d84e8d01b37a708e58eb)) 238 | 239 | ## [1.3.3](https://github.com/Berkmann18/json-fixer/compare/v1.3.2...v1.3.3) (2019-09-18) 240 | 241 | ### Bug Fixes 242 | 243 | - **fixer:** improved trailing character fixer ([d671f0c](https://github.com/Berkmann18/json-fixer/commit/d671f0c)) 244 | 245 | ## [1.3.2](https://github.com/Berkmann18/json-fixer/compare/v1.3.1...v1.3.2) (2019-09-02) 246 | 247 | ### Bug Fixes 248 | 249 | - **security:** vulnerability fix ([8dc1f81](https://github.com/Berkmann18/json-fixer/commit/8dc1f81)) 250 | 251 | ### Performance Improvements 252 | 253 | - **package:** reduce bundle size by 99.2% ([#15](https://github.com/Berkmann18/json-fixer/issues/15)) ([f915ee9](https://github.com/Berkmann18/json-fixer/commit/f915ee9)) 254 | 255 | ## [1.3.1](https://github.com/Berkmann18/json-fixer/compare/v1.3.0...v1.3.1) (2019-05-31) 256 | 257 | ### Bug Fixes 258 | 259 | - **security:** security update ([3083a68](https://github.com/Berkmann18/json-fixer/commit/3083a68)) 260 | 261 | # [1.3.0](https://github.com/Berkmann18/json-fixer/compare/v1.2.0...v1.3.0) (2019-05-19) 262 | 263 | ### Features 264 | 265 | - added concatenation support ([730d813](https://github.com/Berkmann18/json-fixer/commit/730d813)) 266 | - operations support + refactoring ([191a6b0](https://github.com/Berkmann18/json-fixer/commit/191a6b0)), closes [#10](https://github.com/Berkmann18/json-fixer/issues/10) 267 | - **index:** round fix + improved quote fixer ([6ecb55e](https://github.com/Berkmann18/json-fixer/commit/6ecb55e)) 268 | 269 | # [1.2.0](https://github.com/Berkmann18/json-fixer/compare/v1.1.0...v1.2.0) (2019-05-17) 270 | 271 | ### Features 272 | 273 | - **index:** added comment removers ([12bd10d](https://github.com/Berkmann18/json-fixer/commit/12bd10d)) 274 | 275 | # [1.1.0](https://github.com/Berkmann18/json-fixer/compare/v1.0.0...v1.1.0) (2019-05-17) 276 | 277 | ### Features 278 | 279 | - **index:** added a square->curly brackets fixer ([9017579](https://github.com/Berkmann18/json-fixer/commit/9017579)) 280 | - added verbosity and _LHS no quote_ support ([5b1504f](https://github.com/Berkmann18/json-fixer/commit/5b1504f)) 281 | 282 | # 1.0.0 (2019-05-17) 283 | 284 | ### Features 285 | 286 | - **index:** add a _missing comma_ fixer ([1f8a535](https://github.com/Berkmann18/json-fixer/commit/1f8a535)) 287 | - **index:** add a _missing quote_ fixer ([bc53b96](https://github.com/Berkmann18/json-fixer/commit/bc53b96)) 288 | - **index:** added a single->double quote fixer ([b39844a](https://github.com/Berkmann18/json-fixer/commit/b39844a)) 289 | - **index:** added a trailing dot fixer ([13f4931](https://github.com/Berkmann18/json-fixer/commit/13f4931)) 290 | - **index:** generalised trailing dot ([280b845](https://github.com/Berkmann18/json-fixer/commit/280b845)) 291 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Maximilian Berkmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | - [json-fixer](#json-fixer) 6 | - [Usage](#usage) 7 | - [Contributors ✨](#contributors-) 8 | 9 | 10 | 11 | # json-fixer 12 | 13 | [![NPM](https://nodei.co/npm/json-fixer.png)](https://nodei.co/npm/json-fixer/) 14 | 15 | [![GitHub package version](https://img.shields.io/github/package-json/v/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer) 16 | [![devDependencies Status](https://david-dm.org/berkmann18/json-fixer/dev-status.svg)](https://david-dm.org/berkmann18/json-fixer?type=dev) 17 | [![dependencies Status](https://david-dm.org/berkmann18/json-fixer/status.svg)](https://david-dm.org/berkmann18/json-fixer) 18 | 19 | [![GH Downloads](https://img.shields.io/github/downloads/Berkmann18/json-fixer/total.svg)](https://github.com/Berkmann18/json-fixer/network/members) 20 | [![GitHub commit activity the past year](https://img.shields.io/github/commit-activity/y/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer/graphs/commit-activity) 21 | [![GitHub contributors](https://img.shields.io/github/contributors/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer/graphs/contributors) 22 | [![Github search hit counter](https://img.shields.io/github/search/Berkmann18/json-fixer/goto.svg)](https://github.com/Berkmann18/json-fixer/graphs/traffic) 23 | 24 | [![Build Status](https://travis-ci.org/Berkmann18/json-fixer.svg?branch=master)](https://travis-ci.org/Berkmann18/json-fixer) 25 | [![codecov.io Code Coverage](https://img.shields.io/codecov/c/github/Berkmann18/json-fixer.svg?maxAge=2592000)](https://codecov.io/github/Berkmann18/json-fixer?branch=master) 26 | [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest) 27 | [![Known Vulnerabilities](https://snyk.io/test/github/Berkmann18/json-fixer/badge.svg?targetFile=package.json)](https://snyk.io/test/github/Berkmann18/json-fixer?targetFile=package.json) 28 | 29 | [![GitHub](https://img.shields.io/github/license/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer/blob/master/LICENSE) 30 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/Berkmann18/json-fixer/issues) 31 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) 32 | 33 | [![GitHub top language](https://img.shields.io/github/languages/top/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer) 34 | [![GitHub language count](https://img.shields.io/github/languages/count/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer) 35 | [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/Berkmann18/json-fixer.svg)](https://github.com/Berkmann18/json-fixer) 36 | 37 | [![BCH compliance](https://bettercodehub.com/edge/badge/Berkmann18/json-fixer?branch=master)](https://bettercodehub.com/results/Berkmann18/json-fixer) 38 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/81690e927e4f49db939033daae75b2eb)](https://app.codacy.com/manual/maxieberkmann/json-fixer?utm_source=github.com&utm_medium=referral&utm_content=Berkmann18/json-fixer&utm_campaign=Badge_Grade_Dashboard) 39 | 40 | A JSON file fixer primarly focused to be used in a NodeJS file. 41 | 42 | ## Usage 43 | 44 | - In NodeJS 45 | 46 | ```js 47 | const jsonFix = require('json-fixer') 48 | const fs = require('fs') 49 | 50 | // Get the (potentially malformed) JSON data ready 51 | const jsonContent = fs.readFileSync('config.json', 'utf-8') 52 | 53 | const {data, changed} = jsonFix(jsonContent) // Lint (and fix) it 54 | 55 | if (changed) { 56 | // Do something with `data` which is the fixed JSON parsed data from `jsonContent` 57 | // e.g. `fs.writeFileSync(configPath, JSON.stringify(data, null, 2))` 58 | } 59 | ``` 60 | 61 | - In the CLI
62 | _Not supported yet_ (PR welcome). 63 | 64 | ## Contributors ✨ 65 | 66 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |

Maximilian Berkmann

💻 📖 🤔 🚧 ⚠️ 🛡️

Semantic Release Bot

📦 📖

all-contributors[bot]

📖

Ben Kucera

💻

Svetozar Mateev

🐛 💻

André Paulo

🐛

Erkin Matkaziev

🐛

Codacy Badger

🚇 📖

GiraffeKey

💻 ⚠️

jonasmaertens

🐛

George Tsotsos

💻
88 | 89 | 90 | 91 | 92 | 93 | 94 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 95 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const { parse } = require('./src/json.pjs'); 3 | const { psw, removeLinebreak, verboseLog } = require('./src/utils'); 4 | const fixer = require('./src/fixer'); 5 | 6 | let fixRounds = 0; 7 | let roundThreshold = 20; 8 | 9 | const setFixThreshold = (data) => { 10 | const lineCount = data.split('\n').length; 11 | roundThreshold = Math.max(data.length / lineCount, lineCount); 12 | }; 13 | 14 | const doubleCheck = (data, options = {}) => { 15 | /* eslint-disable no-console */ 16 | const verbose = options.verbose; 17 | try { 18 | const res = parse(data); 19 | if (verbose) psw(`\n${chalk.cyan('The JSON data was fixed!')}`); 20 | if (res) return options.parse ? res : data; 21 | } catch (err) { 22 | if (verbose) { 23 | psw('Nearly fixed data:'); 24 | data.split('\n').forEach((l, i) => psw(`${chalk.yellow(i)} ${l}`)); 25 | } 26 | // eslint-disable-next-line no-use-before-define 27 | if (fixRounds < roundThreshold) return fixJson(err, data, options); 28 | console.error(chalk.red("There's still an error!")); 29 | throw new Error(err.message); 30 | } 31 | /* eslint-enable no-console */ 32 | }; 33 | 34 | const extraChar = (err) => err.expected[0].type === 'other' && ['}', ']'].includes(err.found); 35 | 36 | const trailingChar = (err) => { 37 | const literal = err.expected[0].type === 'literal' && err.expected[0].text !== ':'; 38 | return ['.', ',', 'x', 'b', 'o'].includes(err.found) && literal; 39 | }; 40 | 41 | const missingChar = (err) => err.expected[0].text === ',' && ['"', '[', '{'].includes(err.found); 42 | 43 | const singleQuotes = (err) => err.found === "'"; 44 | 45 | const missingQuotes = (err) => 46 | /\w/.test(err.found) && err.expected.find((el) => el.description === 'string'); 47 | 48 | const notSquare = (err) => err.found === ':' && [',', ']'].includes(err.expected[0].text); 49 | 50 | const notCurly = (err) => err.found === ',' && err.expected[0].text === ':'; 51 | 52 | const comment = (err) => err.found === '/'; 53 | 54 | const ops = (err) => ['+', '-', '*', '/', '>', '<', '~', '|', '&', '^'].includes(err.found); 55 | 56 | const extraBrackets = (err) => err.found === '}'; 57 | 58 | const specialChar = (err) => err.found === '"'; 59 | 60 | const runFixer = ({ verbose, lines, start, err }) => { 61 | /* eslint-disable security/detect-object-injection */ 62 | let fixedData = [...lines]; 63 | const targetLine = start.line - 2; 64 | 65 | if (extraChar(err)) { 66 | fixedData = fixer.fixExtraChar({ fixedData, verbose, targetLine }); 67 | } else if (trailingChar(err)) { 68 | fixedData = fixer.fixTrailingChar({ start, fixedData, verbose }); 69 | } else if (missingChar(err)) { 70 | if (verbose) psw(chalk.magenta('Missing character')); 71 | const brokenLine = removeLinebreak(lines[targetLine]); 72 | fixedData[targetLine] = `${brokenLine},`; 73 | } else if (singleQuotes(err)) { 74 | fixedData = fixer.fixSingleQuotes({ start, fixedData, verbose }); 75 | } else if (missingQuotes(err)) { 76 | fixedData = fixer.fixMissingQuotes({ start, fixedData, verbose }); 77 | } else if (notSquare(err)) { 78 | fixedData = fixer.fixSquareBrackets({ start, fixedData, verbose, targetLine }); 79 | } else if (notCurly(err)) { 80 | fixedData = fixer.fixCurlyBrackets({ fixedData, verbose, targetLine }); 81 | } else if (comment(err)) { 82 | fixedData = fixer.fixComment({ start, fixedData, verbose }); 83 | } else if (ops(err)) { 84 | fixedData = fixer.fixOpConcat({ start, fixedData, verbose }); 85 | } else if (extraBrackets(err)) { 86 | fixedData = fixer.fixExtraCurlyBrackets({ start, fixedData, verbose }); 87 | } else if (specialChar(err)) { 88 | fixedData = fixer.fixSpecialChar({ start, fixedData, verbose }); 89 | } else throw new Error(`Unsupported issue: ${err.message} (please open an issue at the repo)`); 90 | return fixedData; 91 | }; 92 | 93 | /*eslint-disable no-console */ 94 | const fixJson = (err, data, options) => { 95 | ++fixRounds; 96 | const lines = data.split('\n'); 97 | const verbose = options.verbose; 98 | verboseLog({ verbose, lines, err }); 99 | 100 | const start = err.location.start; 101 | const fixedData = runFixer({ verbose, lines, start, err }); 102 | 103 | return doubleCheck(fixedData.join('\n'), options); 104 | }; 105 | /*eslint-enable no-console */ 106 | 107 | const fixingTime = ({ data, err, optionsCopy }) => { 108 | fixRounds = 0; 109 | setFixThreshold(data); 110 | return { 111 | data: fixJson(err, data, optionsCopy), 112 | changed: true 113 | }; 114 | }; 115 | 116 | /** 117 | * @param {string} data JSON string data to check (and fix). 118 | * @param {{verbose:boolean, parse:boolean}} options configuration object which specifies verbosity and whether the object should be parsed or returned as fixed string 119 | * @returns {{data: (Object|string|Array), changed: boolean}} Result 120 | */ 121 | const checkJson = (data, options) => { 122 | //inspired by https://jsontuneup.com/ 123 | let optionsCopy; 124 | if (!options || typeof options === 'boolean') { 125 | optionsCopy = {}; 126 | optionsCopy.verbose = options; 127 | } else { 128 | optionsCopy = JSON.parse(JSON.stringify(options)); 129 | } 130 | 131 | if (optionsCopy.parse === undefined || optionsCopy.parse === null) { 132 | optionsCopy.parse = true; 133 | } 134 | 135 | try { 136 | const res = parse(data); 137 | if (res) { 138 | return { 139 | data: optionsCopy.parse ? res : data, 140 | changed: false 141 | }; 142 | } 143 | } catch (err) { 144 | return fixingTime({ data, err, optionsCopy }); 145 | } 146 | }; 147 | 148 | module.exports = checkJson; 149 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-fixer", 3 | "version": "1.6.15", 4 | "description": "A JSON fixer", 5 | "main": "index.js", 6 | "repository": "https://github.com/Berkmann18/json-fixer.git", 7 | "files": [ 8 | "src" 9 | ], 10 | "engines": { 11 | "node": ">=10" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/Berkmann18/json-fixer/issues" 15 | }, 16 | "homepage": "https://github.com/Berkmann18/json-fixer#readme", 17 | "author": { 18 | "name": "Maximilian Berkmann", 19 | "email": "maxieberkmann@gmail.com" 20 | }, 21 | "license": "MIT", 22 | "private": false, 23 | "scripts": { 24 | "lint": "eslint . && npm run lint:lockfile && npm run lint:md", 25 | "lint:fix": "eslint . --fix", 26 | "lint:lockfile": "lockfile-lint --path package-lock.json --type npm --validate-https --allowed-hosts npm yarn", 27 | "lint:md": "remark . .github", 28 | "format": "prettier --write 'src/*.js' index.js", 29 | "test": "jest", 30 | "test:watch": "jest --watch", 31 | "sec": "snyk test", 32 | "commit": "git-cz", 33 | "generate": "pegjs src/json.pegjs", 34 | "prepare": "snyk protect", 35 | "sr": "semantic-release", 36 | "build": "echo 0", 37 | "sandbox": "node test/sandbox" 38 | }, 39 | "husky": { 40 | "hooks": { 41 | "commit-msg": "commitlint --env HUSKY_GIT_PARAMS", 42 | "pre-commit": "lint-staged", 43 | "post-merge": "npm i", 44 | "pre-push": "npm run lint && npm t" 45 | } 46 | }, 47 | "lint-staged": { 48 | "*.js": [ 49 | "npm run format" 50 | ], 51 | "*.md": [ 52 | "remark" 53 | ] 54 | }, 55 | "keywords": [ 56 | "json", 57 | "fix", 58 | "lint", 59 | "check" 60 | ], 61 | "dependencies": { 62 | "@babel/runtime": "^7.26.10", 63 | "chalk": "^4.1.2", 64 | "pegjs": "^0.10.0" 65 | }, 66 | "devDependencies": { 67 | "@commitlint/cli": "^8.3.5", 68 | "@commitlint/config-conventional": "^8.3.4", 69 | "@semantic-release/changelog": "^5.0.1", 70 | "@semantic-release/git": "^9.0.0", 71 | "@semantic-release/npm": "^7.0.5", 72 | "codecov": "^3.7.0", 73 | "cz-conventional-changelog": "^3.2.0", 74 | "eslint": "^7.2.0", 75 | "eslint-plugin-jest": "^23.13.2", 76 | "eslint-plugin-jquery": "^1.5.1", 77 | "eslint-plugin-node": "^11.0.0", 78 | "eslint-plugin-security": "^1.4.0", 79 | "eslint-plugin-standard": "^4.0.0", 80 | "eslint-plugin-you-dont-need-lodash-underscore": "^6.8.0", 81 | "git-cz": "^4.6.2", 82 | "husky": "^4.2.5", 83 | "jest": "^26.0.1", 84 | "lint-staged": "^10.2.9", 85 | "lockfile-lint": "^4.2.2", 86 | "prettier": "^2.0.5", 87 | "remark-cli": "^8.0.0", 88 | "remark-preset-lint-consistent": "^3.0.0", 89 | "remark-preset-lint-recommended": "^4.0.0", 90 | "semantic-release": "^17.0.8", 91 | "snyk": "^1.336.0" 92 | }, 93 | "config": { 94 | "commitizen": { 95 | "path": "cz-conventional-changelog" 96 | } 97 | }, 98 | "commitlint": { 99 | "extends": [ 100 | "@commitlint/config-conventional" 101 | ] 102 | }, 103 | "jest": { 104 | "testEnvironment": "node", 105 | "verbose": true, 106 | "notify": true, 107 | "collectCoverage": true, 108 | "coverageThreshold": { 109 | "global": { 110 | "branches": 50, 111 | "functions": 40, 112 | "lines": 50, 113 | "statements": 50 114 | } 115 | }, 116 | "testPathIgnorePatterns": [ 117 | "/__tests__/.*/__fixtures__/.*" 118 | ], 119 | "collectCoverageFrom": [ 120 | "index.js", 121 | "src/**/*.{js,ts}", 122 | "!src/test.utils.js" 123 | ] 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/__tests__/index.js: -------------------------------------------------------------------------------- 1 | const { exam } = require('../test.utils'); 2 | 3 | const shouldHaveChanged = (sampleName, expectedOutput, fixerOptions = {}) => { 4 | exam({ sampleName, expectedOutput, fixerOptions, expectedChange: true }); 5 | }; 6 | 7 | it('fix single quotes', () => { 8 | shouldHaveChanged('singleQuote', { 9 | name: 'sample #1', 10 | type: 'JSON', 11 | error: 'single quote', 12 | version: '1' 13 | }); 14 | }); 15 | 16 | describe('fix missing quotes', () => { 17 | it('RHS: one word', () => { 18 | shouldHaveChanged('noQuotes', { 19 | name: 'sample #10', 20 | type: 'JSON', 21 | error: 'missing quotes', 22 | version: 'one' 23 | }); 24 | }); 25 | 26 | it('RHS: one word (verbose)', () => { 27 | shouldHaveChanged( 28 | 'noQuotes', 29 | { 30 | name: 'sample #10', 31 | type: 'JSON', 32 | error: 'missing quotes', 33 | version: 'one' 34 | }, 35 | { verbose: true } 36 | ); 37 | }); 38 | 39 | it('RHS: several words', () => { 40 | shouldHaveChanged('missingQuotes', { 41 | name: 'sample #11', 42 | type: 'JSON', 43 | error: 'missing quotes', 44 | version: 'a string' 45 | }); 46 | }); 47 | 48 | it('LHS: one word', () => { 49 | shouldHaveChanged('noLHQuotes', { 50 | name: 'sample #13', 51 | type: 'JSON', 52 | error: 'missing quotes', 53 | version: 'a string' 54 | }); 55 | }); 56 | 57 | it('LHS: 2 chars', () => { 58 | shouldHaveChanged('lefty2', { 59 | ix: 1 60 | }); 61 | }); 62 | 63 | it('LHS: 1 char', () => { 64 | shouldHaveChanged('lefty1', { 65 | t: 42 66 | }); 67 | }); 68 | 69 | it('LHS: not an octet', () => { 70 | shouldHaveChanged('leftyO', { 71 | o: 1 72 | }); 73 | }); 74 | 75 | it('LHS: one word (verbose)', () => { 76 | shouldHaveChanged( 77 | 'noLHQuotes', 78 | { 79 | name: 'sample #13', 80 | type: 'JSON', 81 | error: 'missing quotes', 82 | version: 'a string' 83 | }, 84 | { verbose: true } 85 | ); 86 | }); 87 | 88 | it('LHS: several words', () => { 89 | shouldHaveChanged('missingLHQuotes', { 90 | name: 'sample #14', 91 | type: 'JSON', 92 | error: 'missing quotes', 93 | 'long content': 'a string' 94 | }); 95 | }); 96 | 97 | it('LHS: complicated RHS', () => { 98 | shouldHaveChanged('issue31', { 99 | something: 'string:string' 100 | }); 101 | }); 102 | 103 | it('Both sides', () => { 104 | shouldHaveChanged('doublyMissingQuotes', { 105 | field: 'value' 106 | }); 107 | }); 108 | 109 | it('Both sides (minified)', () => { 110 | shouldHaveChanged('doublyMissingQuotesMin', { 111 | field: 'value' 112 | }); 113 | }); 114 | }); 115 | 116 | describe('fix trailing characters', () => { 117 | it('dots', () => { 118 | shouldHaveChanged('trailingDot', { 119 | name: 'sample #3', 120 | type: 'JSON', 121 | error: 'trailing dot', 122 | version: 0.3 123 | }); 124 | }); 125 | 126 | it('commas', () => { 127 | shouldHaveChanged('trailingComma', { 128 | name: 'sample #6', 129 | type: 'JSON', 130 | error: 'trailing comma', 131 | version: 0.6 132 | }); 133 | }); 134 | 135 | it('chars', () => { 136 | shouldHaveChanged('trailingChar', [ 137 | { 138 | test1: '1', 139 | test2: { 140 | a: 'b', 141 | c: {} 142 | } 143 | } 144 | ]); 145 | }); 146 | 147 | it('hex\'s "x"', () => { 148 | shouldHaveChanged('x', { 149 | name: 'sample #7', 150 | type: 'JSON', 151 | error: 'trailing x', 152 | version: 0x7 153 | }); 154 | }); 155 | 156 | it('hex\'s "x" (verbose)', () => { 157 | shouldHaveChanged( 158 | 'x', 159 | { 160 | name: 'sample #7', 161 | type: 'JSON', 162 | error: 'trailing x', 163 | version: 0x7 164 | }, 165 | { verbose: true } 166 | ); 167 | }); 168 | 169 | it('hex\'s "0x"', () => { 170 | shouldHaveChanged('hex', { 171 | name: 'sample #22', 172 | type: 'JSON', 173 | error: 'hex number', 174 | version: 0x16 175 | }); 176 | }); 177 | 178 | it('hex\'s "0x" (verbose)', () => { 179 | shouldHaveChanged( 180 | 'hex', 181 | { 182 | name: 'sample #22', 183 | type: 'JSON', 184 | error: 'hex number', 185 | version: 0x16 186 | }, 187 | { verbose: true } 188 | ); 189 | }); 190 | 191 | it('binary\'s "b"', () => { 192 | shouldHaveChanged('b', { 193 | name: 'sample #8', 194 | type: 'JSON', 195 | error: 'trailing b', 196 | version: 0b1000 197 | }); 198 | }); 199 | 200 | it('binary\'s "0b"', () => { 201 | shouldHaveChanged('bin', { 202 | name: 'sample #23', 203 | type: 'JSON', 204 | error: 'binary number', 205 | version: 0b10111 206 | }); 207 | }); 208 | 209 | it('octal\'s "o"', () => { 210 | shouldHaveChanged('o', { 211 | name: 'sample #9', 212 | type: 'JSON', 213 | error: 'trailing o', 214 | version: 0o11 215 | }); 216 | }); 217 | 218 | it('octal\'s "0o"', () => { 219 | shouldHaveChanged('oct', { 220 | name: 'sample #24', 221 | type: 'JSON', 222 | error: 'octal number', 223 | version: 0o30 224 | }); 225 | }); 226 | }); 227 | 228 | it('fix extra characters', () => { 229 | shouldHaveChanged('extraChar', { 230 | name: 'sample #4', 231 | type: 'JSON', 232 | error: 'trailing error', 233 | version: 4 234 | }); 235 | }); 236 | 237 | it('fix missing commas', () => { 238 | shouldHaveChanged('missing', { 239 | name: 'sample #5', 240 | type: 'JSON', 241 | error: 'missing comma', 242 | version: 5 243 | }); 244 | }); 245 | 246 | describe('fix wrong brackets', () => { 247 | it('square brackets', () => { 248 | shouldHaveChanged('notSquare', { 249 | name: 'sample #12', 250 | error: 'wrong brackets', 251 | info: { 252 | type: 'JSON', 253 | version: 12 254 | } 255 | }); 256 | }); 257 | 258 | it('square brackets (verbose)', () => { 259 | shouldHaveChanged( 260 | 'notSquare', 261 | { 262 | name: 'sample #12', 263 | error: 'wrong brackets', 264 | info: { 265 | type: 'JSON', 266 | version: 12 267 | } 268 | }, 269 | { verbose: true } 270 | ); 271 | }); 272 | 273 | it('curly brackets', () => { 274 | shouldHaveChanged('notCurly', { 275 | name: 'sample #15', 276 | error: 'wrong brackets', 277 | info: ['one', 'two'] 278 | }); 279 | }); 280 | 281 | it('curly brackets (verbose)', () => { 282 | shouldHaveChanged( 283 | 'notCurly', 284 | { 285 | name: 'sample #15', 286 | error: 'wrong brackets', 287 | info: ['one', 'two'] 288 | }, 289 | { verbose: true } 290 | ); 291 | }); 292 | 293 | it('extra brackets', () => { 294 | shouldHaveChanged('extraBrackets', { 295 | error: 'extra brackets' 296 | }); 297 | }); 298 | }); 299 | 300 | describe('comments', () => { 301 | it('inline line', () => { 302 | shouldHaveChanged('comment', { 303 | name: 'sample #16', 304 | type: 'JSON', 305 | error: 'comment', 306 | version: '0x10' 307 | }); 308 | }); 309 | 310 | it('single line', () => { 311 | shouldHaveChanged('smComment', { 312 | name: 'sample #17', 313 | type: 'JSON', 314 | error: 'multi-comment', 315 | version: '0x10' 316 | }); 317 | }); 318 | 319 | it('multi line', () => { 320 | shouldHaveChanged('multiComment', { 321 | name: 'sample #18', 322 | type: 'JSON', 323 | error: 'multi-comment', 324 | version: 18 325 | }); 326 | }); 327 | }); 328 | 329 | describe('fix operations', () => { 330 | it('simple', () => { 331 | shouldHaveChanged('ops', { 332 | name: 'sample #20', 333 | type: 'JSON', 334 | error: 'operations', 335 | version: 20 336 | }); 337 | }); 338 | 339 | it('unary', () => { 340 | shouldHaveChanged('monOps', { 341 | name: 'sample #26', 342 | type: 'JSON', 343 | error: 'unary operations', 344 | version: -7 345 | }); 346 | }); 347 | 348 | it('multi', () => { 349 | shouldHaveChanged('multiOps', { 350 | name: 'sample #27', 351 | type: 'JSON', 352 | error: 'multi operations', 353 | version: 7 354 | }); 355 | }); 356 | }); 357 | 358 | describe('fix concatenations', () => { 359 | it('simple', () => { 360 | shouldHaveChanged('concat', { 361 | name: 'sample #25', 362 | type: 'JSON', 363 | error: 'concat', 364 | version: 25 365 | }); 366 | }); 367 | 368 | it('verbose', () => { 369 | shouldHaveChanged( 370 | 'concat', 371 | { 372 | name: 'sample #25', 373 | type: 'JSON', 374 | error: 'concat', 375 | version: 25 376 | }, 377 | { verbose: true } 378 | ); 379 | }); 380 | }); 381 | 382 | describe('multi rounds', () => { 383 | it('x2', () => { 384 | shouldHaveChanged('twoErrs', { 385 | name: 'sample #19', 386 | type: 'JSON', 387 | error: '2 errors', 388 | version: 19 389 | }); 390 | }); 391 | 392 | it('x2 (verbose)', () => { 393 | shouldHaveChanged( 394 | 'twoErrs', 395 | { 396 | name: 'sample #19', 397 | type: 'JSON', 398 | error: '2 errors', 399 | version: 19 400 | }, 401 | { verbose: true } 402 | ); 403 | }); 404 | 405 | it('x3', () => { 406 | shouldHaveChanged('threeErrs', { 407 | name: 'sample #21', 408 | type: 'JSON', 409 | error: '3 errors', 410 | version: 21 411 | }); 412 | }); 413 | }); 414 | 415 | describe('special chars', () => { 416 | it('tab', () => { 417 | shouldHaveChanged('tab', { 418 | Test: '\t' 419 | }); 420 | }); 421 | 422 | it('formatted tab', () => { 423 | shouldHaveChanged('tabs', { 424 | Test: '\t' 425 | }); 426 | }); 427 | 428 | it('new line', () => { 429 | shouldHaveChanged('newLines', { 430 | Broken: '\n' 431 | }); 432 | }); 433 | }); 434 | -------------------------------------------------------------------------------- /src/__tests__/intact.js: -------------------------------------------------------------------------------- 1 | const { exam } = require('../test.utils'); 2 | 3 | describe('keeps a correct file intact', () => { 4 | it('normal file', () => { 5 | exam({ 6 | sampleName: 'normal', 7 | expectedOutput: { 8 | name: 'sample #0', 9 | type: 'JSON', 10 | version: 0 11 | } 12 | }); 13 | }); 14 | 15 | it('floating points', () => { 16 | exam({ 17 | sampleName: 'fp', 18 | expectedOutput: { 19 | name: 'sample #2', 20 | type: 'JSON', 21 | version: 2.0 22 | } 23 | }); 24 | }); 25 | }); 26 | 27 | test('boolean option', () => { 28 | exam({ 29 | sampleName: 'normal', 30 | expectedOutput: { 31 | name: 'sample #0', 32 | type: 'JSON', 33 | version: 0 34 | }, 35 | fixerOptions: true 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/__tests__/more.js: -------------------------------------------------------------------------------- 1 | const { readFileSync } = require('fs'); 2 | const jf = require('../..'); 3 | 4 | describe('returns the json as fixed string', () => { 5 | it('normal file', () => { 6 | const json = readFileSync('./test/samples/normal.json', 'utf-8'); 7 | const { data } = jf(json, { parse: false }); 8 | expect(typeof data).toBe('string'); 9 | expect(typeof JSON.parse(data)).toBe('object'); 10 | }); 11 | }); 12 | 13 | test('Unsupported error', () => { 14 | const json = readFileSync('./test/samples/quoteInQuotes.json', 'utf-8'); 15 | expect(() => jf(json)).toThrowError( 16 | 'Unsupported issue: Expected "," or "}" but "M" found. (please open an issue at the repo)' 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /src/__tests__/utils.js: -------------------------------------------------------------------------------- 1 | const { removeLinebreak, replaceChar, curlyBracesIncluded } = require('../utils'); 2 | 3 | test('No line breaks', () => { 4 | expect(removeLinebreak(`a\nnew\nline`)).toEqual('anewline'); 5 | }); 6 | 7 | test('Spaces there', () => { 8 | expect(removeLinebreak('not the same ')).toEqual('not the same '); 9 | }); 10 | 11 | test('Char replaced', () => { 12 | expect(replaceChar('Hi$mate', 2, ' ')).toEqual('Hi mate'); 13 | }); 14 | 15 | test('Char !not replaced', () => { 16 | expect(replaceChar('Hi$mate', -1, ' ')).toEqual(' Hi$mate'); 17 | }); 18 | 19 | describe('Inlined braces', () => { 20 | it('{ ... }', () => { 21 | expect(curlyBracesIncluded('{ a: "thing }')).toBeTruthy(); 22 | }); 23 | 24 | it('[ ... ]', () => { 25 | expect(curlyBracesIncluded('[ 0, 1 ]')).toBeFalsy(); 26 | }); 27 | }); 28 | 29 | describe('Outlined braces', () => { 30 | it('{ ... }', () => { 31 | expect(curlyBracesIncluded('a: "thing\n')).toBeFalsy(); 32 | }); 33 | 34 | it('[ ... ]', () => { 35 | expect(curlyBracesIncluded('0, 1')).toBeFalsy(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/fixer.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const { psw, removeLinebreak, replaceChar, curlyBracesIncluded } = require('./utils'); 3 | const { quotify, numberify, baseNumify } = require('./transform'); 4 | const { parse } = require('./json.pjs'); 5 | 6 | const fixExtraChar = ({ fixedData, verbose, targetLine }) => { 7 | /* eslint-disable security/detect-object-injection */ 8 | if (verbose) psw(chalk.magenta('Extra character')); 9 | if (fixedData[targetLine] === '') --targetLine; 10 | const brokenLine = removeLinebreak(fixedData[targetLine]); 11 | 12 | let fixedLine = brokenLine.trimEnd(); 13 | fixedLine = fixedLine.substr(0, fixedLine.length - 1); 14 | fixedData[targetLine] = fixedLine; 15 | return fixedData; 16 | }; 17 | 18 | const fixSingleQuotes = ({ start, fixedData, verbose }) => { 19 | if (verbose) psw(chalk.magenta('Single quotes')); 20 | const targetLine = start.line - 1; 21 | const brokenLine = removeLinebreak(fixedData[targetLine]); 22 | const fixedLine = brokenLine.replace(/(":\s*)'(.*?)'/g, '$1"$2"'); 23 | fixedData[targetLine] = fixedLine; 24 | return fixedData; 25 | }; 26 | 27 | const fixTrailingChar = ({ start, fixedData, verbose }) => { 28 | if (verbose) psw(chalk.magenta('Trailing character')); 29 | const targetLine = start.line - 1; 30 | const brokenLine = removeLinebreak(fixedData[targetLine]); 31 | const fixedLine = brokenLine.replace(/(":\s*)[.,](\d*)/g, '$10.$2'); 32 | const unquotedWord = /(":\s*)(\S*)/g.exec(fixedLine); 33 | // if (unquotedWord === null) throw new Error('Unquoted word expected!'); 34 | const NN = Number.isNaN(Number(unquotedWord[2])); 35 | if (NN && !/([xbo][0-9a-fA-F]+)/.test(unquotedWord[2])) { 36 | return quotify({ fixedData, targetLine, fixedLine, verbose }); 37 | } 38 | if (!NN && !/\0([xbo][0-9a-fA-F]+)/.test(unquotedWord[2])) { 39 | return numberify({ fixedData, targetLine, fixedLine, unquotedWord, verbose }); 40 | } 41 | let baseNumber = fixedLine.replace(/(":\s*)([xbo][0-9a-fA-F]*)/g, '$1"0$2"'); 42 | if (baseNumber !== fixedLine) { 43 | baseNumber = baseNumify({ baseNumber, verbose }); 44 | } 45 | 46 | fixedData[targetLine] = baseNumber; 47 | return fixedData; 48 | }; 49 | 50 | const fixMissingQuotes = ({ start, fixedData, verbose }) => { 51 | /* eslint-disable security/detect-object-injection */ 52 | if (verbose) psw(chalk.magenta('Missing quotes')); 53 | const targetLine = start.line - 1; 54 | let brokenLine = removeLinebreak(fixedData[targetLine]); 55 | const seCurlyBraces = curlyBracesIncluded(brokenLine); 56 | if (seCurlyBraces) { 57 | brokenLine = brokenLine.substring(1, brokenLine.length - 1); 58 | } 59 | const NO_RH_QUOTES = /(":\s*)([^,{}[\]]+)/; 60 | const NO_LH_QUOTES = /(^[^"][\S\s]*)(:\s*["\w{[])/; 61 | const RH = NO_RH_QUOTES.test(brokenLine); 62 | let fixedLine = RH ? brokenLine.replace(NO_RH_QUOTES, '$1"$2"') : brokenLine; 63 | const leftSpace = fixedLine.match(/^(\s+)/); 64 | fixedLine = fixedLine.trimStart(); 65 | if (NO_LH_QUOTES.test(fixedLine)) { 66 | const firstColon = fixedLine.indexOf(':'); 67 | const leftHand = fixedLine.substring(0, firstColon); 68 | fixedLine = `"${leftHand}"${fixedLine.substring(firstColon)}`; 69 | } 70 | fixedData[targetLine] = `${leftSpace === null ? '' : leftSpace[0]}${fixedLine}`; 71 | if (seCurlyBraces) { 72 | fixedData[targetLine] = `{${fixedData[targetLine]}}`; 73 | } 74 | 75 | return fixedData; 76 | }; 77 | 78 | const fixSquareBrackets = ({ start, fixedData, verbose, targetLine }) => { 79 | /* eslint-disable security/detect-object-injection */ 80 | if (verbose) psw(chalk.magenta('Square brackets instead of curly ones')); 81 | const lineToChange = fixedData[targetLine].includes('[') 82 | ? fixedData[targetLine] 83 | : fixedData[++targetLine]; 84 | const brokenLine = removeLinebreak(lineToChange); 85 | const fixedLine = replaceChar(brokenLine, start.column - 1, '{'); 86 | fixedData[targetLine] = fixedLine; 87 | 88 | try { 89 | parse(fixedData.join('\n')); 90 | } catch (e) { 91 | targetLine = e.location.start.line - 1; 92 | const newLine = removeLinebreak(fixedData[targetLine]).replace(']', '}'); 93 | fixedData[targetLine] = newLine; 94 | } 95 | return fixedData; 96 | }; 97 | 98 | const fixCurlyBrackets = ({ fixedData, verbose, targetLine }) => { 99 | if (verbose) psw(chalk.magenta('Curly brackets instead of square ones')); 100 | const brokenLine = removeLinebreak( 101 | fixedData[targetLine].includes('{') ? fixedData[targetLine] : fixedData[++targetLine] 102 | ); 103 | const fixedLine = replaceChar(brokenLine, brokenLine.indexOf('{'), '['); 104 | fixedData[targetLine] = fixedLine; 105 | 106 | try { 107 | parse(fixedData.join('\n')); 108 | } catch (e) { 109 | targetLine = e.location.start.line - 1; 110 | const newLine = removeLinebreak(fixedData[targetLine]).replace('}', ']'); 111 | fixedData[targetLine] = newLine; 112 | } 113 | 114 | return fixedData; 115 | }; 116 | 117 | const fixMultilineComment = ({ fixedData, targetLine }) => { 118 | let end = targetLine + 1; 119 | while (end <= fixedData.length && !fixedData[end].includes('*/')) ++end; 120 | for (let i = targetLine + 1; i <= end; ++i) fixedData[i] = '#RM'; 121 | fixedData[targetLine] = fixedData[targetLine].replace(/\s*\/\*+.*/g, '#RM'); 122 | return fixedData.filter((l) => l !== '#RM'); 123 | }; 124 | 125 | const fixComment = ({ start, fixedData, verbose }) => { 126 | if (verbose) psw(chalk.magenta('Comment')); 127 | const targetLine = start.line - 1; 128 | const brokenLine = removeLinebreak(fixedData[targetLine]); 129 | const fixedLine = brokenLine.replace(/(\s*)(\/\/.*|\/\*+.*?\*+\/)/g, ''); 130 | if (fixedLine.includes('/*')) { 131 | return fixMultilineComment({ fixedData, targetLine }); 132 | } 133 | fixedData[targetLine] = fixedLine; 134 | return fixedData; 135 | }; 136 | 137 | const fixOpConcat = ({ start, fixedData, verbose }) => { 138 | if (verbose) psw(chalk.magenta('Operations/Concatenations')); 139 | psw( 140 | chalk.yellow( 141 | 'Please note: calculations made here may not be entirely correct on complex operations' 142 | ) 143 | ); 144 | const targetLine = start.line - 1; 145 | const brokenLine = removeLinebreak(fixedData[targetLine]); 146 | const fixedLine = brokenLine 147 | /* eslint-disable no-eval, security/detect-eval-with-expression */ 148 | .replace( 149 | /(\d+)\s*([+\-*/%&|^><]|\*\*|>{2,3}|<<|[=!><]=|[=!]==)\s*(\d+)\s*([+\-*/%&|^><]|\*\*|>{2,3}|<<|[=!><]=|[=!]==)*\s*(\d+)*/g, 150 | (eq) => eval(eq) 151 | ) 152 | .replace(/[~!+-]\(?(\d+)\)?/g, (eq) => eval(eq)) 153 | .replace(/(":\s*)"(.*?)"\s*\+\s*"(.*?)"/g, '$1"$2$3"'); 154 | /* eslint-enable no-eval */ 155 | fixedData[targetLine] = fixedLine; 156 | return fixedData; 157 | }; 158 | 159 | const fixExtraCurlyBrackets = ({ start, fixedData, verbose }) => { 160 | if (verbose) psw(chalk.magenta('Extra curly brackets')); 161 | 162 | const targetLine = start.line - 1; 163 | const fullData = fixedData.join('\n'); 164 | let fixedLine = removeLinebreak(fixedData[targetLine]); 165 | 166 | const data = fullData.split(''); 167 | const openingCount = data.filter((c) => c === '{').length; 168 | const closingCount = data.filter((c) => c === '}').length; 169 | const bracketDiff = closingCount - openingCount; 170 | 171 | for (let i = 0; i < bracketDiff; i++) { 172 | const index = fixedLine.lastIndexOf('}'); 173 | fixedLine = fixedLine.slice(0, index) + fixedLine.slice(index + 1); 174 | } 175 | 176 | fixedData[targetLine] = fixedLine; 177 | return fixedData; 178 | }; 179 | 180 | const fixSpecialChar = ({ start, fixedData, verbose }) => { 181 | if (verbose) psw(chalk.magenta('Special character')); 182 | const targetLine = start.line - 1; 183 | const brokenLine = fixedData[targetLine]; 184 | 185 | let fixedLine = brokenLine 186 | .replace(/\f/g, '\\f') 187 | .replace(/\n/g, '\\n') 188 | .replace(/\r/g, '\\r') 189 | .replace(/\t/g, '\\t'); 190 | 191 | if (brokenLine.endsWith('"') && brokenLine[start.column] === undefined) { 192 | if (verbose) psw(chalk.magenta('New line')); 193 | const removedIndex = targetLine + 1; 194 | const continuation = fixedData[removedIndex]; 195 | fixedLine = `${brokenLine}\\n${continuation}`; 196 | fixedData.splice(removedIndex, 1); 197 | } 198 | 199 | fixedData[targetLine] = fixedLine; 200 | return fixedData; 201 | }; 202 | 203 | module.exports = { 204 | fixExtraChar, 205 | fixSingleQuotes, 206 | fixTrailingChar, 207 | fixMissingQuotes, 208 | fixSquareBrackets, 209 | fixCurlyBrackets, 210 | fixComment, 211 | fixOpConcat, 212 | fixExtraCurlyBrackets, 213 | fixSpecialChar 214 | }; 215 | -------------------------------------------------------------------------------- /src/json.pegjs: -------------------------------------------------------------------------------- 1 | // JSON Grammar 2 | // ============ 3 | // 4 | // Based on the grammar from RFC 7159 [1]. 5 | // 6 | // Note that JSON is also specified in ECMA-262 [2], ECMA-404 [3], and on the 7 | // JSON website [4] (somewhat informally). The RFC seems the most authoritative 8 | // source, which is confirmed e.g. by [5]. 9 | // 10 | // [1] http://tools.ietf.org/html/rfc7159 11 | // [2] http://www.ecma-international.org/publications/standards/Ecma-262.htm 12 | // [3] http://www.ecma-international.org/publications/standards/Ecma-404.htm 13 | // [4] http://json.org/ 14 | // [5] https://www.tbray.org/ongoing/When/201x/2014/03/05/RFC7159-JSON 15 | 16 | // ----- 2. JSON Grammar ----- 17 | 18 | JSON_text 19 | = ws value:value ws { return value; } 20 | 21 | begin_array = ws "[" ws 22 | begin_object = ws "{" ws 23 | end_array = ws "]" ws 24 | end_object = ws "}" ws 25 | name_separator = ws ":" ws 26 | value_separator = ws "," ws 27 | 28 | ws "whitespace" = [ \t\n\r]* 29 | 30 | // ----- 3. Values ----- 31 | 32 | value 33 | = false 34 | / null 35 | / true 36 | / object 37 | / array 38 | / number 39 | / string 40 | 41 | false = "false" { return false; } 42 | null = "null" { return null; } 43 | true = "true" { return true; } 44 | 45 | // ----- 4. Objects ----- 46 | 47 | object 48 | = begin_object 49 | members:( 50 | head:member 51 | tail:(value_separator m:member { return m; })* 52 | { 53 | var result = {}; 54 | 55 | [head].concat(tail).forEach(function(element) { 56 | result[element.name] = element.value; 57 | }); 58 | 59 | return result; 60 | } 61 | )? 62 | end_object 63 | { return members !== null ? members: {}; } 64 | 65 | member 66 | = name:string name_separator value:value { 67 | return { name: name, value: value }; 68 | } 69 | 70 | // ----- 5. Arrays ----- 71 | 72 | array 73 | = begin_array 74 | values:( 75 | head:value 76 | tail:(value_separator v:value { return v; })* 77 | { return [head].concat(tail); } 78 | )? 79 | end_array 80 | { return values !== null ? values : []; } 81 | 82 | // ----- 6. Numbers ----- 83 | 84 | number "number" 85 | = minus? int frac? exp? { return parseFloat(text()); } 86 | 87 | decimal_point 88 | = "." 89 | 90 | digit1_9 91 | = [1-9] 92 | 93 | e 94 | = [eE] 95 | 96 | exp 97 | = e (minus / plus)? DIGIT+ 98 | 99 | frac 100 | = decimal_point DIGIT+ 101 | 102 | int 103 | = zero / (digit1_9 DIGIT*) 104 | 105 | minus 106 | = "-" 107 | 108 | plus 109 | = "+" 110 | 111 | zero 112 | = "0" 113 | 114 | // ----- 7. Strings ----- 115 | 116 | string "string" 117 | = quotation_mark chars:char* quotation_mark { return chars.join(""); } 118 | 119 | char 120 | = unescaped 121 | / escape 122 | sequence:( 123 | '"' 124 | / "\\" 125 | / "/" 126 | / "b" { return "\b"; } 127 | / "f" { return "\f"; } 128 | / "n" { return "\n"; } 129 | / "r" { return "\r"; } 130 | / "t" { return "\t"; } 131 | / "u" digits:$(HEXDIG HEXDIG HEXDIG HEXDIG) { 132 | return String.fromCharCode(parseInt(digits, 16)); 133 | } 134 | ) 135 | { return sequence; } 136 | 137 | escape 138 | = "\\" 139 | 140 | quotation_mark 141 | = '"' 142 | 143 | unescaped 144 | = [^\0-\x1F\x22\x5C] 145 | 146 | // ----- Core ABNF Rules ----- 147 | 148 | // See RFC 4234, Appendix B (http://tools.ietf.org/html/rfc4234). 149 | DIGIT = [0-9] 150 | HEXDIG = [0-9a-f]i 151 | -------------------------------------------------------------------------------- /src/json.pjs: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated by PEG.js 0.10.0. 3 | * 4 | * http://pegjs.org/ 5 | */ 6 | 7 | 'use strict' 8 | 9 | function peg$subclass(child, parent) { 10 | function ctor() { 11 | this.constructor = child 12 | } 13 | ctor.prototype = parent.prototype 14 | child.prototype = new ctor() 15 | } 16 | 17 | function peg$SyntaxError(message, expected, found, location) { 18 | this.message = message 19 | this.expected = expected 20 | this.found = found 21 | this.location = location 22 | this.name = 'SyntaxError' 23 | 24 | if (typeof Error.captureStackTrace === 'function') { 25 | Error.captureStackTrace(this, peg$SyntaxError) 26 | } 27 | } 28 | 29 | peg$subclass(peg$SyntaxError, Error) 30 | 31 | peg$SyntaxError.buildMessage = function(expected, found) { 32 | var DESCRIBE_EXPECTATION_FNS = { 33 | literal: function(expectation) { 34 | return '"' + literalEscape(expectation.text) + '"' 35 | }, 36 | 37 | class: function(expectation) { 38 | var escapedParts = '', 39 | i 40 | 41 | for (i = 0; i < expectation.parts.length; i++) { 42 | escapedParts += 43 | expectation.parts[i] instanceof Array 44 | ? classEscape(expectation.parts[i][0]) + 45 | '-' + 46 | classEscape(expectation.parts[i][1]) 47 | : classEscape(expectation.parts[i]) 48 | } 49 | 50 | return '[' + (expectation.inverted ? '^' : '') + escapedParts + ']' 51 | }, 52 | 53 | any: function(expectation) { 54 | return 'any character' 55 | }, 56 | 57 | end: function(expectation) { 58 | return 'end of input' 59 | }, 60 | 61 | other: function(expectation) { 62 | return expectation.description 63 | }, 64 | } 65 | 66 | function hex(ch) { 67 | return ch 68 | .charCodeAt(0) 69 | .toString(16) 70 | .toUpperCase() 71 | } 72 | 73 | function literalEscape(s) { 74 | return s 75 | .replace(/\\/g, '\\\\') 76 | .replace(/"/g, '\\"') 77 | .replace(/\0/g, '\\0') 78 | .replace(/\t/g, '\\t') 79 | .replace(/\n/g, '\\n') 80 | .replace(/\r/g, '\\r') 81 | .replace(/[\x00-\x0F]/g, function(ch) { 82 | return '\\x0' + hex(ch) 83 | }) 84 | .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { 85 | return '\\x' + hex(ch) 86 | }) 87 | } 88 | 89 | function classEscape(s) { 90 | return s 91 | .replace(/\\/g, '\\\\') 92 | .replace(/\]/g, '\\]') 93 | .replace(/\^/g, '\\^') 94 | .replace(/-/g, '\\-') 95 | .replace(/\0/g, '\\0') 96 | .replace(/\t/g, '\\t') 97 | .replace(/\n/g, '\\n') 98 | .replace(/\r/g, '\\r') 99 | .replace(/[\x00-\x0F]/g, function(ch) { 100 | return '\\x0' + hex(ch) 101 | }) 102 | .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { 103 | return '\\x' + hex(ch) 104 | }) 105 | } 106 | 107 | function describeExpectation(expectation) { 108 | return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation) 109 | } 110 | 111 | function describeExpected(expected) { 112 | var descriptions = new Array(expected.length), 113 | i, 114 | j 115 | 116 | for (i = 0; i < expected.length; i++) { 117 | descriptions[i] = describeExpectation(expected[i]) 118 | } 119 | 120 | descriptions.sort() 121 | 122 | if (descriptions.length > 0) { 123 | for (i = 1, j = 1; i < descriptions.length; i++) { 124 | if (descriptions[i - 1] !== descriptions[i]) { 125 | descriptions[j] = descriptions[i] 126 | j++ 127 | } 128 | } 129 | descriptions.length = j 130 | } 131 | 132 | switch (descriptions.length) { 133 | case 1: 134 | return descriptions[0] 135 | 136 | case 2: 137 | return descriptions[0] + ' or ' + descriptions[1] 138 | 139 | default: 140 | return ( 141 | descriptions.slice(0, -1).join(', ') + 142 | ', or ' + 143 | descriptions[descriptions.length - 1] 144 | ) 145 | } 146 | } 147 | 148 | function describeFound(found) { 149 | return found ? '"' + literalEscape(found) + '"' : 'end of input' 150 | } 151 | 152 | return ( 153 | 'Expected ' + 154 | describeExpected(expected) + 155 | ' but ' + 156 | describeFound(found) + 157 | ' found.' 158 | ) 159 | } 160 | 161 | function peg$parse(input, options) { 162 | options = options !== void 0 ? options : {} 163 | 164 | var peg$FAILED = {}, 165 | peg$startRuleFunctions = {JSON_text: peg$parseJSON_text}, 166 | peg$startRuleFunction = peg$parseJSON_text, 167 | peg$c0 = function(value) { 168 | return value 169 | }, 170 | peg$c1 = '[', 171 | peg$c2 = peg$literalExpectation('[', false), 172 | peg$c3 = '{', 173 | peg$c4 = peg$literalExpectation('{', false), 174 | peg$c5 = ']', 175 | peg$c6 = peg$literalExpectation(']', false), 176 | peg$c7 = '}', 177 | peg$c8 = peg$literalExpectation('}', false), 178 | peg$c9 = ':', 179 | peg$c10 = peg$literalExpectation(':', false), 180 | peg$c11 = ',', 181 | peg$c12 = peg$literalExpectation(',', false), 182 | peg$c13 = peg$otherExpectation('whitespace'), 183 | peg$c14 = /^[ \t\n\r]/, 184 | peg$c15 = peg$classExpectation([' ', '\t', '\n', '\r'], false, false), 185 | peg$c16 = 'false', 186 | peg$c17 = peg$literalExpectation('false', false), 187 | peg$c18 = function() { 188 | return false 189 | }, 190 | peg$c19 = 'null', 191 | peg$c20 = peg$literalExpectation('null', false), 192 | peg$c21 = function() { 193 | return null 194 | }, 195 | peg$c22 = 'true', 196 | peg$c23 = peg$literalExpectation('true', false), 197 | peg$c24 = function() { 198 | return true 199 | }, 200 | peg$c25 = function(head, m) { 201 | return m 202 | }, 203 | peg$c26 = function(head, tail) { 204 | var result = {} 205 | 206 | ;[head].concat(tail).forEach(function(element) { 207 | result[element.name] = element.value 208 | }) 209 | 210 | return result 211 | }, 212 | peg$c27 = function(members) { 213 | return members !== null ? members : {} 214 | }, 215 | peg$c28 = function(name, value) { 216 | return {name: name, value: value} 217 | }, 218 | peg$c29 = function(head, v) { 219 | return v 220 | }, 221 | peg$c30 = function(head, tail) { 222 | return [head].concat(tail) 223 | }, 224 | peg$c31 = function(values) { 225 | return values !== null ? values : [] 226 | }, 227 | peg$c32 = peg$otherExpectation('number'), 228 | peg$c33 = function() { 229 | return parseFloat(text()) 230 | }, 231 | peg$c34 = '.', 232 | peg$c35 = peg$literalExpectation('.', false), 233 | peg$c36 = /^[1-9]/, 234 | peg$c37 = peg$classExpectation([['1', '9']], false, false), 235 | peg$c38 = /^[eE]/, 236 | peg$c39 = peg$classExpectation(['e', 'E'], false, false), 237 | peg$c40 = '-', 238 | peg$c41 = peg$literalExpectation('-', false), 239 | peg$c42 = '+', 240 | peg$c43 = peg$literalExpectation('+', false), 241 | peg$c44 = '0', 242 | peg$c45 = peg$literalExpectation('0', false), 243 | peg$c46 = peg$otherExpectation('string'), 244 | peg$c47 = function(chars) { 245 | return chars.join('') 246 | }, 247 | peg$c48 = '"', 248 | peg$c49 = peg$literalExpectation('"', false), 249 | peg$c50 = '\\', 250 | peg$c51 = peg$literalExpectation('\\', false), 251 | peg$c52 = '/', 252 | peg$c53 = peg$literalExpectation('/', false), 253 | peg$c54 = 'b', 254 | peg$c55 = peg$literalExpectation('b', false), 255 | peg$c56 = function() { 256 | return '\b' 257 | }, 258 | peg$c57 = 'f', 259 | peg$c58 = peg$literalExpectation('f', false), 260 | peg$c59 = function() { 261 | return '\f' 262 | }, 263 | peg$c60 = 'n', 264 | peg$c61 = peg$literalExpectation('n', false), 265 | peg$c62 = function() { 266 | return '\n' 267 | }, 268 | peg$c63 = 'r', 269 | peg$c64 = peg$literalExpectation('r', false), 270 | peg$c65 = function() { 271 | return '\r' 272 | }, 273 | peg$c66 = 't', 274 | peg$c67 = peg$literalExpectation('t', false), 275 | peg$c68 = function() { 276 | return '\t' 277 | }, 278 | peg$c69 = 'u', 279 | peg$c70 = peg$literalExpectation('u', false), 280 | peg$c71 = function(digits) { 281 | return String.fromCharCode(parseInt(digits, 16)) 282 | }, 283 | peg$c72 = function(sequence) { 284 | return sequence 285 | }, 286 | peg$c73 = /^[^\0-\x1F"\\]/, 287 | peg$c74 = peg$classExpectation([['\0', '\x1F'], '"', '\\'], true, false), 288 | peg$c75 = /^[0-9]/, 289 | peg$c76 = peg$classExpectation([['0', '9']], false, false), 290 | peg$c77 = /^[0-9a-f]/i, 291 | peg$c78 = peg$classExpectation([['0', '9'], ['a', 'f']], false, true), 292 | peg$currPos = 0, 293 | peg$savedPos = 0, 294 | peg$posDetailsCache = [{line: 1, column: 1}], 295 | peg$maxFailPos = 0, 296 | peg$maxFailExpected = [], 297 | peg$silentFails = 0, 298 | peg$result 299 | 300 | if ('startRule' in options) { 301 | if (!(options.startRule in peg$startRuleFunctions)) { 302 | throw new Error( 303 | 'Can\'t start parsing from rule "' + options.startRule + '".', 304 | ) 305 | } 306 | 307 | peg$startRuleFunction = peg$startRuleFunctions[options.startRule] 308 | } 309 | 310 | function text() { 311 | return input.substring(peg$savedPos, peg$currPos) 312 | } 313 | 314 | function location() { 315 | return peg$computeLocation(peg$savedPos, peg$currPos) 316 | } 317 | 318 | function expected(description, location) { 319 | location = 320 | location !== void 0 321 | ? location 322 | : peg$computeLocation(peg$savedPos, peg$currPos) 323 | 324 | throw peg$buildStructuredError( 325 | [peg$otherExpectation(description)], 326 | input.substring(peg$savedPos, peg$currPos), 327 | location, 328 | ) 329 | } 330 | 331 | function error(message, location) { 332 | location = 333 | location !== void 0 334 | ? location 335 | : peg$computeLocation(peg$savedPos, peg$currPos) 336 | 337 | throw peg$buildSimpleError(message, location) 338 | } 339 | 340 | function peg$literalExpectation(text, ignoreCase) { 341 | return {type: 'literal', text: text, ignoreCase: ignoreCase} 342 | } 343 | 344 | function peg$classExpectation(parts, inverted, ignoreCase) { 345 | return { 346 | type: 'class', 347 | parts: parts, 348 | inverted: inverted, 349 | ignoreCase: ignoreCase, 350 | } 351 | } 352 | 353 | function peg$anyExpectation() { 354 | return {type: 'any'} 355 | } 356 | 357 | function peg$endExpectation() { 358 | return {type: 'end'} 359 | } 360 | 361 | function peg$otherExpectation(description) { 362 | return {type: 'other', description: description} 363 | } 364 | 365 | function peg$computePosDetails(pos) { 366 | var details = peg$posDetailsCache[pos], 367 | p 368 | 369 | if (details) { 370 | return details 371 | } else { 372 | p = pos - 1 373 | while (!peg$posDetailsCache[p]) { 374 | p-- 375 | } 376 | 377 | details = peg$posDetailsCache[p] 378 | details = { 379 | line: details.line, 380 | column: details.column, 381 | } 382 | 383 | while (p < pos) { 384 | if (input.charCodeAt(p) === 10) { 385 | details.line++ 386 | details.column = 1 387 | } else { 388 | details.column++ 389 | } 390 | 391 | p++ 392 | } 393 | 394 | peg$posDetailsCache[pos] = details 395 | return details 396 | } 397 | } 398 | 399 | function peg$computeLocation(startPos, endPos) { 400 | var startPosDetails = peg$computePosDetails(startPos), 401 | endPosDetails = peg$computePosDetails(endPos) 402 | 403 | return { 404 | start: { 405 | offset: startPos, 406 | line: startPosDetails.line, 407 | column: startPosDetails.column, 408 | }, 409 | end: { 410 | offset: endPos, 411 | line: endPosDetails.line, 412 | column: endPosDetails.column, 413 | }, 414 | } 415 | } 416 | 417 | function peg$fail(expected) { 418 | if (peg$currPos < peg$maxFailPos) { 419 | return 420 | } 421 | 422 | if (peg$currPos > peg$maxFailPos) { 423 | peg$maxFailPos = peg$currPos 424 | peg$maxFailExpected = [] 425 | } 426 | 427 | peg$maxFailExpected.push(expected) 428 | } 429 | 430 | function peg$buildSimpleError(message, location) { 431 | return new peg$SyntaxError(message, null, null, location) 432 | } 433 | 434 | function peg$buildStructuredError(expected, found, location) { 435 | return new peg$SyntaxError( 436 | peg$SyntaxError.buildMessage(expected, found), 437 | expected, 438 | found, 439 | location, 440 | ) 441 | } 442 | 443 | function peg$parseJSON_text() { 444 | var s0, s1, s2, s3 445 | 446 | s0 = peg$currPos 447 | s1 = peg$parsews() 448 | if (s1 !== peg$FAILED) { 449 | s2 = peg$parsevalue() 450 | if (s2 !== peg$FAILED) { 451 | s3 = peg$parsews() 452 | if (s3 !== peg$FAILED) { 453 | peg$savedPos = s0 454 | s1 = peg$c0(s2) 455 | s0 = s1 456 | } else { 457 | peg$currPos = s0 458 | s0 = peg$FAILED 459 | } 460 | } else { 461 | peg$currPos = s0 462 | s0 = peg$FAILED 463 | } 464 | } else { 465 | peg$currPos = s0 466 | s0 = peg$FAILED 467 | } 468 | 469 | return s0 470 | } 471 | 472 | function peg$parsebegin_array() { 473 | var s0, s1, s2, s3 474 | 475 | s0 = peg$currPos 476 | s1 = peg$parsews() 477 | if (s1 !== peg$FAILED) { 478 | if (input.charCodeAt(peg$currPos) === 91) { 479 | s2 = peg$c1 480 | peg$currPos++ 481 | } else { 482 | s2 = peg$FAILED 483 | if (peg$silentFails === 0) { 484 | peg$fail(peg$c2) 485 | } 486 | } 487 | if (s2 !== peg$FAILED) { 488 | s3 = peg$parsews() 489 | if (s3 !== peg$FAILED) { 490 | s1 = [s1, s2, s3] 491 | s0 = s1 492 | } else { 493 | peg$currPos = s0 494 | s0 = peg$FAILED 495 | } 496 | } else { 497 | peg$currPos = s0 498 | s0 = peg$FAILED 499 | } 500 | } else { 501 | peg$currPos = s0 502 | s0 = peg$FAILED 503 | } 504 | 505 | return s0 506 | } 507 | 508 | function peg$parsebegin_object() { 509 | var s0, s1, s2, s3 510 | 511 | s0 = peg$currPos 512 | s1 = peg$parsews() 513 | if (s1 !== peg$FAILED) { 514 | if (input.charCodeAt(peg$currPos) === 123) { 515 | s2 = peg$c3 516 | peg$currPos++ 517 | } else { 518 | s2 = peg$FAILED 519 | if (peg$silentFails === 0) { 520 | peg$fail(peg$c4) 521 | } 522 | } 523 | if (s2 !== peg$FAILED) { 524 | s3 = peg$parsews() 525 | if (s3 !== peg$FAILED) { 526 | s1 = [s1, s2, s3] 527 | s0 = s1 528 | } else { 529 | peg$currPos = s0 530 | s0 = peg$FAILED 531 | } 532 | } else { 533 | peg$currPos = s0 534 | s0 = peg$FAILED 535 | } 536 | } else { 537 | peg$currPos = s0 538 | s0 = peg$FAILED 539 | } 540 | 541 | return s0 542 | } 543 | 544 | function peg$parseend_array() { 545 | var s0, s1, s2, s3 546 | 547 | s0 = peg$currPos 548 | s1 = peg$parsews() 549 | if (s1 !== peg$FAILED) { 550 | if (input.charCodeAt(peg$currPos) === 93) { 551 | s2 = peg$c5 552 | peg$currPos++ 553 | } else { 554 | s2 = peg$FAILED 555 | if (peg$silentFails === 0) { 556 | peg$fail(peg$c6) 557 | } 558 | } 559 | if (s2 !== peg$FAILED) { 560 | s3 = peg$parsews() 561 | if (s3 !== peg$FAILED) { 562 | s1 = [s1, s2, s3] 563 | s0 = s1 564 | } else { 565 | peg$currPos = s0 566 | s0 = peg$FAILED 567 | } 568 | } else { 569 | peg$currPos = s0 570 | s0 = peg$FAILED 571 | } 572 | } else { 573 | peg$currPos = s0 574 | s0 = peg$FAILED 575 | } 576 | 577 | return s0 578 | } 579 | 580 | function peg$parseend_object() { 581 | var s0, s1, s2, s3 582 | 583 | s0 = peg$currPos 584 | s1 = peg$parsews() 585 | if (s1 !== peg$FAILED) { 586 | if (input.charCodeAt(peg$currPos) === 125) { 587 | s2 = peg$c7 588 | peg$currPos++ 589 | } else { 590 | s2 = peg$FAILED 591 | if (peg$silentFails === 0) { 592 | peg$fail(peg$c8) 593 | } 594 | } 595 | if (s2 !== peg$FAILED) { 596 | s3 = peg$parsews() 597 | if (s3 !== peg$FAILED) { 598 | s1 = [s1, s2, s3] 599 | s0 = s1 600 | } else { 601 | peg$currPos = s0 602 | s0 = peg$FAILED 603 | } 604 | } else { 605 | peg$currPos = s0 606 | s0 = peg$FAILED 607 | } 608 | } else { 609 | peg$currPos = s0 610 | s0 = peg$FAILED 611 | } 612 | 613 | return s0 614 | } 615 | 616 | function peg$parsename_separator() { 617 | var s0, s1, s2, s3 618 | 619 | s0 = peg$currPos 620 | s1 = peg$parsews() 621 | if (s1 !== peg$FAILED) { 622 | if (input.charCodeAt(peg$currPos) === 58) { 623 | s2 = peg$c9 624 | peg$currPos++ 625 | } else { 626 | s2 = peg$FAILED 627 | if (peg$silentFails === 0) { 628 | peg$fail(peg$c10) 629 | } 630 | } 631 | if (s2 !== peg$FAILED) { 632 | s3 = peg$parsews() 633 | if (s3 !== peg$FAILED) { 634 | s1 = [s1, s2, s3] 635 | s0 = s1 636 | } else { 637 | peg$currPos = s0 638 | s0 = peg$FAILED 639 | } 640 | } else { 641 | peg$currPos = s0 642 | s0 = peg$FAILED 643 | } 644 | } else { 645 | peg$currPos = s0 646 | s0 = peg$FAILED 647 | } 648 | 649 | return s0 650 | } 651 | 652 | function peg$parsevalue_separator() { 653 | var s0, s1, s2, s3 654 | 655 | s0 = peg$currPos 656 | s1 = peg$parsews() 657 | if (s1 !== peg$FAILED) { 658 | if (input.charCodeAt(peg$currPos) === 44) { 659 | s2 = peg$c11 660 | peg$currPos++ 661 | } else { 662 | s2 = peg$FAILED 663 | if (peg$silentFails === 0) { 664 | peg$fail(peg$c12) 665 | } 666 | } 667 | if (s2 !== peg$FAILED) { 668 | s3 = peg$parsews() 669 | if (s3 !== peg$FAILED) { 670 | s1 = [s1, s2, s3] 671 | s0 = s1 672 | } else { 673 | peg$currPos = s0 674 | s0 = peg$FAILED 675 | } 676 | } else { 677 | peg$currPos = s0 678 | s0 = peg$FAILED 679 | } 680 | } else { 681 | peg$currPos = s0 682 | s0 = peg$FAILED 683 | } 684 | 685 | return s0 686 | } 687 | 688 | function peg$parsews() { 689 | var s0, s1 690 | 691 | peg$silentFails++ 692 | s0 = [] 693 | if (peg$c14.test(input.charAt(peg$currPos))) { 694 | s1 = input.charAt(peg$currPos) 695 | peg$currPos++ 696 | } else { 697 | s1 = peg$FAILED 698 | if (peg$silentFails === 0) { 699 | peg$fail(peg$c15) 700 | } 701 | } 702 | while (s1 !== peg$FAILED) { 703 | s0.push(s1) 704 | if (peg$c14.test(input.charAt(peg$currPos))) { 705 | s1 = input.charAt(peg$currPos) 706 | peg$currPos++ 707 | } else { 708 | s1 = peg$FAILED 709 | if (peg$silentFails === 0) { 710 | peg$fail(peg$c15) 711 | } 712 | } 713 | } 714 | peg$silentFails-- 715 | if (s0 === peg$FAILED) { 716 | s1 = peg$FAILED 717 | if (peg$silentFails === 0) { 718 | peg$fail(peg$c13) 719 | } 720 | } 721 | 722 | return s0 723 | } 724 | 725 | function peg$parsevalue() { 726 | var s0 727 | 728 | s0 = peg$parsefalse() 729 | if (s0 === peg$FAILED) { 730 | s0 = peg$parsenull() 731 | if (s0 === peg$FAILED) { 732 | s0 = peg$parsetrue() 733 | if (s0 === peg$FAILED) { 734 | s0 = peg$parseobject() 735 | if (s0 === peg$FAILED) { 736 | s0 = peg$parsearray() 737 | if (s0 === peg$FAILED) { 738 | s0 = peg$parsenumber() 739 | if (s0 === peg$FAILED) { 740 | s0 = peg$parsestring() 741 | } 742 | } 743 | } 744 | } 745 | } 746 | } 747 | 748 | return s0 749 | } 750 | 751 | function peg$parsefalse() { 752 | var s0, s1 753 | 754 | s0 = peg$currPos 755 | if (input.substr(peg$currPos, 5) === peg$c16) { 756 | s1 = peg$c16 757 | peg$currPos += 5 758 | } else { 759 | s1 = peg$FAILED 760 | if (peg$silentFails === 0) { 761 | peg$fail(peg$c17) 762 | } 763 | } 764 | if (s1 !== peg$FAILED) { 765 | peg$savedPos = s0 766 | s1 = peg$c18() 767 | } 768 | s0 = s1 769 | 770 | return s0 771 | } 772 | 773 | function peg$parsenull() { 774 | var s0, s1 775 | 776 | s0 = peg$currPos 777 | if (input.substr(peg$currPos, 4) === peg$c19) { 778 | s1 = peg$c19 779 | peg$currPos += 4 780 | } else { 781 | s1 = peg$FAILED 782 | if (peg$silentFails === 0) { 783 | peg$fail(peg$c20) 784 | } 785 | } 786 | if (s1 !== peg$FAILED) { 787 | peg$savedPos = s0 788 | s1 = peg$c21() 789 | } 790 | s0 = s1 791 | 792 | return s0 793 | } 794 | 795 | function peg$parsetrue() { 796 | var s0, s1 797 | 798 | s0 = peg$currPos 799 | if (input.substr(peg$currPos, 4) === peg$c22) { 800 | s1 = peg$c22 801 | peg$currPos += 4 802 | } else { 803 | s1 = peg$FAILED 804 | if (peg$silentFails === 0) { 805 | peg$fail(peg$c23) 806 | } 807 | } 808 | if (s1 !== peg$FAILED) { 809 | peg$savedPos = s0 810 | s1 = peg$c24() 811 | } 812 | s0 = s1 813 | 814 | return s0 815 | } 816 | 817 | function peg$parseobject() { 818 | var s0, s1, s2, s3, s4, s5, s6, s7 819 | 820 | s0 = peg$currPos 821 | s1 = peg$parsebegin_object() 822 | if (s1 !== peg$FAILED) { 823 | s2 = peg$currPos 824 | s3 = peg$parsemember() 825 | if (s3 !== peg$FAILED) { 826 | s4 = [] 827 | s5 = peg$currPos 828 | s6 = peg$parsevalue_separator() 829 | if (s6 !== peg$FAILED) { 830 | s7 = peg$parsemember() 831 | if (s7 !== peg$FAILED) { 832 | peg$savedPos = s5 833 | s6 = peg$c25(s3, s7) 834 | s5 = s6 835 | } else { 836 | peg$currPos = s5 837 | s5 = peg$FAILED 838 | } 839 | } else { 840 | peg$currPos = s5 841 | s5 = peg$FAILED 842 | } 843 | while (s5 !== peg$FAILED) { 844 | s4.push(s5) 845 | s5 = peg$currPos 846 | s6 = peg$parsevalue_separator() 847 | if (s6 !== peg$FAILED) { 848 | s7 = peg$parsemember() 849 | if (s7 !== peg$FAILED) { 850 | peg$savedPos = s5 851 | s6 = peg$c25(s3, s7) 852 | s5 = s6 853 | } else { 854 | peg$currPos = s5 855 | s5 = peg$FAILED 856 | } 857 | } else { 858 | peg$currPos = s5 859 | s5 = peg$FAILED 860 | } 861 | } 862 | if (s4 !== peg$FAILED) { 863 | peg$savedPos = s2 864 | s3 = peg$c26(s3, s4) 865 | s2 = s3 866 | } else { 867 | peg$currPos = s2 868 | s2 = peg$FAILED 869 | } 870 | } else { 871 | peg$currPos = s2 872 | s2 = peg$FAILED 873 | } 874 | if (s2 === peg$FAILED) { 875 | s2 = null 876 | } 877 | if (s2 !== peg$FAILED) { 878 | s3 = peg$parseend_object() 879 | if (s3 !== peg$FAILED) { 880 | peg$savedPos = s0 881 | s1 = peg$c27(s2) 882 | s0 = s1 883 | } else { 884 | peg$currPos = s0 885 | s0 = peg$FAILED 886 | } 887 | } else { 888 | peg$currPos = s0 889 | s0 = peg$FAILED 890 | } 891 | } else { 892 | peg$currPos = s0 893 | s0 = peg$FAILED 894 | } 895 | 896 | return s0 897 | } 898 | 899 | function peg$parsemember() { 900 | var s0, s1, s2, s3 901 | 902 | s0 = peg$currPos 903 | s1 = peg$parsestring() 904 | if (s1 !== peg$FAILED) { 905 | s2 = peg$parsename_separator() 906 | if (s2 !== peg$FAILED) { 907 | s3 = peg$parsevalue() 908 | if (s3 !== peg$FAILED) { 909 | peg$savedPos = s0 910 | s1 = peg$c28(s1, s3) 911 | s0 = s1 912 | } else { 913 | peg$currPos = s0 914 | s0 = peg$FAILED 915 | } 916 | } else { 917 | peg$currPos = s0 918 | s0 = peg$FAILED 919 | } 920 | } else { 921 | peg$currPos = s0 922 | s0 = peg$FAILED 923 | } 924 | 925 | return s0 926 | } 927 | 928 | function peg$parsearray() { 929 | var s0, s1, s2, s3, s4, s5, s6, s7 930 | 931 | s0 = peg$currPos 932 | s1 = peg$parsebegin_array() 933 | if (s1 !== peg$FAILED) { 934 | s2 = peg$currPos 935 | s3 = peg$parsevalue() 936 | if (s3 !== peg$FAILED) { 937 | s4 = [] 938 | s5 = peg$currPos 939 | s6 = peg$parsevalue_separator() 940 | if (s6 !== peg$FAILED) { 941 | s7 = peg$parsevalue() 942 | if (s7 !== peg$FAILED) { 943 | peg$savedPos = s5 944 | s6 = peg$c29(s3, s7) 945 | s5 = s6 946 | } else { 947 | peg$currPos = s5 948 | s5 = peg$FAILED 949 | } 950 | } else { 951 | peg$currPos = s5 952 | s5 = peg$FAILED 953 | } 954 | while (s5 !== peg$FAILED) { 955 | s4.push(s5) 956 | s5 = peg$currPos 957 | s6 = peg$parsevalue_separator() 958 | if (s6 !== peg$FAILED) { 959 | s7 = peg$parsevalue() 960 | if (s7 !== peg$FAILED) { 961 | peg$savedPos = s5 962 | s6 = peg$c29(s3, s7) 963 | s5 = s6 964 | } else { 965 | peg$currPos = s5 966 | s5 = peg$FAILED 967 | } 968 | } else { 969 | peg$currPos = s5 970 | s5 = peg$FAILED 971 | } 972 | } 973 | if (s4 !== peg$FAILED) { 974 | peg$savedPos = s2 975 | s3 = peg$c30(s3, s4) 976 | s2 = s3 977 | } else { 978 | peg$currPos = s2 979 | s2 = peg$FAILED 980 | } 981 | } else { 982 | peg$currPos = s2 983 | s2 = peg$FAILED 984 | } 985 | if (s2 === peg$FAILED) { 986 | s2 = null 987 | } 988 | if (s2 !== peg$FAILED) { 989 | s3 = peg$parseend_array() 990 | if (s3 !== peg$FAILED) { 991 | peg$savedPos = s0 992 | s1 = peg$c31(s2) 993 | s0 = s1 994 | } else { 995 | peg$currPos = s0 996 | s0 = peg$FAILED 997 | } 998 | } else { 999 | peg$currPos = s0 1000 | s0 = peg$FAILED 1001 | } 1002 | } else { 1003 | peg$currPos = s0 1004 | s0 = peg$FAILED 1005 | } 1006 | 1007 | return s0 1008 | } 1009 | 1010 | function peg$parsenumber() { 1011 | var s0, s1, s2, s3, s4 1012 | 1013 | peg$silentFails++ 1014 | s0 = peg$currPos 1015 | s1 = peg$parseminus() 1016 | if (s1 === peg$FAILED) { 1017 | s1 = null 1018 | } 1019 | if (s1 !== peg$FAILED) { 1020 | s2 = peg$parseint() 1021 | if (s2 !== peg$FAILED) { 1022 | s3 = peg$parsefrac() 1023 | if (s3 === peg$FAILED) { 1024 | s3 = null 1025 | } 1026 | if (s3 !== peg$FAILED) { 1027 | s4 = peg$parseexp() 1028 | if (s4 === peg$FAILED) { 1029 | s4 = null 1030 | } 1031 | if (s4 !== peg$FAILED) { 1032 | peg$savedPos = s0 1033 | s1 = peg$c33() 1034 | s0 = s1 1035 | } else { 1036 | peg$currPos = s0 1037 | s0 = peg$FAILED 1038 | } 1039 | } else { 1040 | peg$currPos = s0 1041 | s0 = peg$FAILED 1042 | } 1043 | } else { 1044 | peg$currPos = s0 1045 | s0 = peg$FAILED 1046 | } 1047 | } else { 1048 | peg$currPos = s0 1049 | s0 = peg$FAILED 1050 | } 1051 | peg$silentFails-- 1052 | if (s0 === peg$FAILED) { 1053 | s1 = peg$FAILED 1054 | if (peg$silentFails === 0) { 1055 | peg$fail(peg$c32) 1056 | } 1057 | } 1058 | 1059 | return s0 1060 | } 1061 | 1062 | function peg$parsedecimal_point() { 1063 | var s0 1064 | 1065 | if (input.charCodeAt(peg$currPos) === 46) { 1066 | s0 = peg$c34 1067 | peg$currPos++ 1068 | } else { 1069 | s0 = peg$FAILED 1070 | if (peg$silentFails === 0) { 1071 | peg$fail(peg$c35) 1072 | } 1073 | } 1074 | 1075 | return s0 1076 | } 1077 | 1078 | function peg$parsedigit1_9() { 1079 | var s0 1080 | 1081 | if (peg$c36.test(input.charAt(peg$currPos))) { 1082 | s0 = input.charAt(peg$currPos) 1083 | peg$currPos++ 1084 | } else { 1085 | s0 = peg$FAILED 1086 | if (peg$silentFails === 0) { 1087 | peg$fail(peg$c37) 1088 | } 1089 | } 1090 | 1091 | return s0 1092 | } 1093 | 1094 | function peg$parsee() { 1095 | var s0 1096 | 1097 | if (peg$c38.test(input.charAt(peg$currPos))) { 1098 | s0 = input.charAt(peg$currPos) 1099 | peg$currPos++ 1100 | } else { 1101 | s0 = peg$FAILED 1102 | if (peg$silentFails === 0) { 1103 | peg$fail(peg$c39) 1104 | } 1105 | } 1106 | 1107 | return s0 1108 | } 1109 | 1110 | function peg$parseexp() { 1111 | var s0, s1, s2, s3, s4 1112 | 1113 | s0 = peg$currPos 1114 | s1 = peg$parsee() 1115 | if (s1 !== peg$FAILED) { 1116 | s2 = peg$parseminus() 1117 | if (s2 === peg$FAILED) { 1118 | s2 = peg$parseplus() 1119 | } 1120 | if (s2 === peg$FAILED) { 1121 | s2 = null 1122 | } 1123 | if (s2 !== peg$FAILED) { 1124 | s3 = [] 1125 | s4 = peg$parseDIGIT() 1126 | if (s4 !== peg$FAILED) { 1127 | while (s4 !== peg$FAILED) { 1128 | s3.push(s4) 1129 | s4 = peg$parseDIGIT() 1130 | } 1131 | } else { 1132 | s3 = peg$FAILED 1133 | } 1134 | if (s3 !== peg$FAILED) { 1135 | s1 = [s1, s2, s3] 1136 | s0 = s1 1137 | } else { 1138 | peg$currPos = s0 1139 | s0 = peg$FAILED 1140 | } 1141 | } else { 1142 | peg$currPos = s0 1143 | s0 = peg$FAILED 1144 | } 1145 | } else { 1146 | peg$currPos = s0 1147 | s0 = peg$FAILED 1148 | } 1149 | 1150 | return s0 1151 | } 1152 | 1153 | function peg$parsefrac() { 1154 | var s0, s1, s2, s3 1155 | 1156 | s0 = peg$currPos 1157 | s1 = peg$parsedecimal_point() 1158 | if (s1 !== peg$FAILED) { 1159 | s2 = [] 1160 | s3 = peg$parseDIGIT() 1161 | if (s3 !== peg$FAILED) { 1162 | while (s3 !== peg$FAILED) { 1163 | s2.push(s3) 1164 | s3 = peg$parseDIGIT() 1165 | } 1166 | } else { 1167 | s2 = peg$FAILED 1168 | } 1169 | if (s2 !== peg$FAILED) { 1170 | s1 = [s1, s2] 1171 | s0 = s1 1172 | } else { 1173 | peg$currPos = s0 1174 | s0 = peg$FAILED 1175 | } 1176 | } else { 1177 | peg$currPos = s0 1178 | s0 = peg$FAILED 1179 | } 1180 | 1181 | return s0 1182 | } 1183 | 1184 | function peg$parseint() { 1185 | var s0, s1, s2, s3 1186 | 1187 | s0 = peg$parsezero() 1188 | if (s0 === peg$FAILED) { 1189 | s0 = peg$currPos 1190 | s1 = peg$parsedigit1_9() 1191 | if (s1 !== peg$FAILED) { 1192 | s2 = [] 1193 | s3 = peg$parseDIGIT() 1194 | while (s3 !== peg$FAILED) { 1195 | s2.push(s3) 1196 | s3 = peg$parseDIGIT() 1197 | } 1198 | if (s2 !== peg$FAILED) { 1199 | s1 = [s1, s2] 1200 | s0 = s1 1201 | } else { 1202 | peg$currPos = s0 1203 | s0 = peg$FAILED 1204 | } 1205 | } else { 1206 | peg$currPos = s0 1207 | s0 = peg$FAILED 1208 | } 1209 | } 1210 | 1211 | return s0 1212 | } 1213 | 1214 | function peg$parseminus() { 1215 | var s0 1216 | 1217 | if (input.charCodeAt(peg$currPos) === 45) { 1218 | s0 = peg$c40 1219 | peg$currPos++ 1220 | } else { 1221 | s0 = peg$FAILED 1222 | if (peg$silentFails === 0) { 1223 | peg$fail(peg$c41) 1224 | } 1225 | } 1226 | 1227 | return s0 1228 | } 1229 | 1230 | function peg$parseplus() { 1231 | var s0 1232 | 1233 | if (input.charCodeAt(peg$currPos) === 43) { 1234 | s0 = peg$c42 1235 | peg$currPos++ 1236 | } else { 1237 | s0 = peg$FAILED 1238 | if (peg$silentFails === 0) { 1239 | peg$fail(peg$c43) 1240 | } 1241 | } 1242 | 1243 | return s0 1244 | } 1245 | 1246 | function peg$parsezero() { 1247 | var s0 1248 | 1249 | if (input.charCodeAt(peg$currPos) === 48) { 1250 | s0 = peg$c44 1251 | peg$currPos++ 1252 | } else { 1253 | s0 = peg$FAILED 1254 | if (peg$silentFails === 0) { 1255 | peg$fail(peg$c45) 1256 | } 1257 | } 1258 | 1259 | return s0 1260 | } 1261 | 1262 | function peg$parsestring() { 1263 | var s0, s1, s2, s3 1264 | 1265 | peg$silentFails++ 1266 | s0 = peg$currPos 1267 | s1 = peg$parsequotation_mark() 1268 | if (s1 !== peg$FAILED) { 1269 | s2 = [] 1270 | s3 = peg$parsechar() 1271 | while (s3 !== peg$FAILED) { 1272 | s2.push(s3) 1273 | s3 = peg$parsechar() 1274 | } 1275 | if (s2 !== peg$FAILED) { 1276 | s3 = peg$parsequotation_mark() 1277 | if (s3 !== peg$FAILED) { 1278 | peg$savedPos = s0 1279 | s1 = peg$c47(s2) 1280 | s0 = s1 1281 | } else { 1282 | peg$currPos = s0 1283 | s0 = peg$FAILED 1284 | } 1285 | } else { 1286 | peg$currPos = s0 1287 | s0 = peg$FAILED 1288 | } 1289 | } else { 1290 | peg$currPos = s0 1291 | s0 = peg$FAILED 1292 | } 1293 | peg$silentFails-- 1294 | if (s0 === peg$FAILED) { 1295 | s1 = peg$FAILED 1296 | if (peg$silentFails === 0) { 1297 | peg$fail(peg$c46) 1298 | } 1299 | } 1300 | 1301 | return s0 1302 | } 1303 | 1304 | function peg$parsechar() { 1305 | var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 1306 | 1307 | s0 = peg$parseunescaped() 1308 | if (s0 === peg$FAILED) { 1309 | s0 = peg$currPos 1310 | s1 = peg$parseescape() 1311 | if (s1 !== peg$FAILED) { 1312 | if (input.charCodeAt(peg$currPos) === 34) { 1313 | s2 = peg$c48 1314 | peg$currPos++ 1315 | } else { 1316 | s2 = peg$FAILED 1317 | if (peg$silentFails === 0) { 1318 | peg$fail(peg$c49) 1319 | } 1320 | } 1321 | if (s2 === peg$FAILED) { 1322 | if (input.charCodeAt(peg$currPos) === 92) { 1323 | s2 = peg$c50 1324 | peg$currPos++ 1325 | } else { 1326 | s2 = peg$FAILED 1327 | if (peg$silentFails === 0) { 1328 | peg$fail(peg$c51) 1329 | } 1330 | } 1331 | if (s2 === peg$FAILED) { 1332 | if (input.charCodeAt(peg$currPos) === 47) { 1333 | s2 = peg$c52 1334 | peg$currPos++ 1335 | } else { 1336 | s2 = peg$FAILED 1337 | if (peg$silentFails === 0) { 1338 | peg$fail(peg$c53) 1339 | } 1340 | } 1341 | if (s2 === peg$FAILED) { 1342 | s2 = peg$currPos 1343 | if (input.charCodeAt(peg$currPos) === 98) { 1344 | s3 = peg$c54 1345 | peg$currPos++ 1346 | } else { 1347 | s3 = peg$FAILED 1348 | if (peg$silentFails === 0) { 1349 | peg$fail(peg$c55) 1350 | } 1351 | } 1352 | if (s3 !== peg$FAILED) { 1353 | peg$savedPos = s2 1354 | s3 = peg$c56() 1355 | } 1356 | s2 = s3 1357 | if (s2 === peg$FAILED) { 1358 | s2 = peg$currPos 1359 | if (input.charCodeAt(peg$currPos) === 102) { 1360 | s3 = peg$c57 1361 | peg$currPos++ 1362 | } else { 1363 | s3 = peg$FAILED 1364 | if (peg$silentFails === 0) { 1365 | peg$fail(peg$c58) 1366 | } 1367 | } 1368 | if (s3 !== peg$FAILED) { 1369 | peg$savedPos = s2 1370 | s3 = peg$c59() 1371 | } 1372 | s2 = s3 1373 | if (s2 === peg$FAILED) { 1374 | s2 = peg$currPos 1375 | if (input.charCodeAt(peg$currPos) === 110) { 1376 | s3 = peg$c60 1377 | peg$currPos++ 1378 | } else { 1379 | s3 = peg$FAILED 1380 | if (peg$silentFails === 0) { 1381 | peg$fail(peg$c61) 1382 | } 1383 | } 1384 | if (s3 !== peg$FAILED) { 1385 | peg$savedPos = s2 1386 | s3 = peg$c62() 1387 | } 1388 | s2 = s3 1389 | if (s2 === peg$FAILED) { 1390 | s2 = peg$currPos 1391 | if (input.charCodeAt(peg$currPos) === 114) { 1392 | s3 = peg$c63 1393 | peg$currPos++ 1394 | } else { 1395 | s3 = peg$FAILED 1396 | if (peg$silentFails === 0) { 1397 | peg$fail(peg$c64) 1398 | } 1399 | } 1400 | if (s3 !== peg$FAILED) { 1401 | peg$savedPos = s2 1402 | s3 = peg$c65() 1403 | } 1404 | s2 = s3 1405 | if (s2 === peg$FAILED) { 1406 | s2 = peg$currPos 1407 | if (input.charCodeAt(peg$currPos) === 116) { 1408 | s3 = peg$c66 1409 | peg$currPos++ 1410 | } else { 1411 | s3 = peg$FAILED 1412 | if (peg$silentFails === 0) { 1413 | peg$fail(peg$c67) 1414 | } 1415 | } 1416 | if (s3 !== peg$FAILED) { 1417 | peg$savedPos = s2 1418 | s3 = peg$c68() 1419 | } 1420 | s2 = s3 1421 | if (s2 === peg$FAILED) { 1422 | s2 = peg$currPos 1423 | if (input.charCodeAt(peg$currPos) === 117) { 1424 | s3 = peg$c69 1425 | peg$currPos++ 1426 | } else { 1427 | s3 = peg$FAILED 1428 | if (peg$silentFails === 0) { 1429 | peg$fail(peg$c70) 1430 | } 1431 | } 1432 | if (s3 !== peg$FAILED) { 1433 | s4 = peg$currPos 1434 | s5 = peg$currPos 1435 | s6 = peg$parseHEXDIG() 1436 | if (s6 !== peg$FAILED) { 1437 | s7 = peg$parseHEXDIG() 1438 | if (s7 !== peg$FAILED) { 1439 | s8 = peg$parseHEXDIG() 1440 | if (s8 !== peg$FAILED) { 1441 | s9 = peg$parseHEXDIG() 1442 | if (s9 !== peg$FAILED) { 1443 | s6 = [s6, s7, s8, s9] 1444 | s5 = s6 1445 | } else { 1446 | peg$currPos = s5 1447 | s5 = peg$FAILED 1448 | } 1449 | } else { 1450 | peg$currPos = s5 1451 | s5 = peg$FAILED 1452 | } 1453 | } else { 1454 | peg$currPos = s5 1455 | s5 = peg$FAILED 1456 | } 1457 | } else { 1458 | peg$currPos = s5 1459 | s5 = peg$FAILED 1460 | } 1461 | if (s5 !== peg$FAILED) { 1462 | s4 = input.substring(s4, peg$currPos) 1463 | } else { 1464 | s4 = s5 1465 | } 1466 | if (s4 !== peg$FAILED) { 1467 | peg$savedPos = s2 1468 | s3 = peg$c71(s4) 1469 | s2 = s3 1470 | } else { 1471 | peg$currPos = s2 1472 | s2 = peg$FAILED 1473 | } 1474 | } else { 1475 | peg$currPos = s2 1476 | s2 = peg$FAILED 1477 | } 1478 | } 1479 | } 1480 | } 1481 | } 1482 | } 1483 | } 1484 | } 1485 | } 1486 | if (s2 !== peg$FAILED) { 1487 | peg$savedPos = s0 1488 | s1 = peg$c72(s2) 1489 | s0 = s1 1490 | } else { 1491 | peg$currPos = s0 1492 | s0 = peg$FAILED 1493 | } 1494 | } else { 1495 | peg$currPos = s0 1496 | s0 = peg$FAILED 1497 | } 1498 | } 1499 | 1500 | return s0 1501 | } 1502 | 1503 | function peg$parseescape() { 1504 | var s0 1505 | 1506 | if (input.charCodeAt(peg$currPos) === 92) { 1507 | s0 = peg$c50 1508 | peg$currPos++ 1509 | } else { 1510 | s0 = peg$FAILED 1511 | if (peg$silentFails === 0) { 1512 | peg$fail(peg$c51) 1513 | } 1514 | } 1515 | 1516 | return s0 1517 | } 1518 | 1519 | function peg$parsequotation_mark() { 1520 | var s0 1521 | 1522 | if (input.charCodeAt(peg$currPos) === 34) { 1523 | s0 = peg$c48 1524 | peg$currPos++ 1525 | } else { 1526 | s0 = peg$FAILED 1527 | if (peg$silentFails === 0) { 1528 | peg$fail(peg$c49) 1529 | } 1530 | } 1531 | 1532 | return s0 1533 | } 1534 | 1535 | function peg$parseunescaped() { 1536 | var s0 1537 | 1538 | if (peg$c73.test(input.charAt(peg$currPos))) { 1539 | s0 = input.charAt(peg$currPos) 1540 | peg$currPos++ 1541 | } else { 1542 | s0 = peg$FAILED 1543 | if (peg$silentFails === 0) { 1544 | peg$fail(peg$c74) 1545 | } 1546 | } 1547 | 1548 | return s0 1549 | } 1550 | 1551 | function peg$parseDIGIT() { 1552 | var s0 1553 | 1554 | if (peg$c75.test(input.charAt(peg$currPos))) { 1555 | s0 = input.charAt(peg$currPos) 1556 | peg$currPos++ 1557 | } else { 1558 | s0 = peg$FAILED 1559 | if (peg$silentFails === 0) { 1560 | peg$fail(peg$c76) 1561 | } 1562 | } 1563 | 1564 | return s0 1565 | } 1566 | 1567 | function peg$parseHEXDIG() { 1568 | var s0 1569 | 1570 | if (peg$c77.test(input.charAt(peg$currPos))) { 1571 | s0 = input.charAt(peg$currPos) 1572 | peg$currPos++ 1573 | } else { 1574 | s0 = peg$FAILED 1575 | if (peg$silentFails === 0) { 1576 | peg$fail(peg$c78) 1577 | } 1578 | } 1579 | 1580 | return s0 1581 | } 1582 | 1583 | peg$result = peg$startRuleFunction() 1584 | 1585 | if (peg$result !== peg$FAILED && peg$currPos === input.length) { 1586 | return peg$result 1587 | } else { 1588 | if (peg$result !== peg$FAILED && peg$currPos < input.length) { 1589 | peg$fail(peg$endExpectation()) 1590 | } 1591 | 1592 | throw peg$buildStructuredError( 1593 | peg$maxFailExpected, 1594 | peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, 1595 | peg$maxFailPos < input.length 1596 | ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) 1597 | : peg$computeLocation(peg$maxFailPos, peg$maxFailPos), 1598 | ) 1599 | } 1600 | } 1601 | 1602 | module.exports = { 1603 | SyntaxError: peg$SyntaxError, 1604 | parse: peg$parse, 1605 | } 1606 | -------------------------------------------------------------------------------- /src/test.utils.js: -------------------------------------------------------------------------------- 1 | const { readFileSync } = require('fs'); 2 | const jf = require('../'); 3 | 4 | const exam = ({ sampleName, expectedOutput, fixerOptions = {}, expectedChange = false } = {}) => { 5 | // eslint-disable-next-line security/detect-non-literal-fs-filename 6 | const json = readFileSync(`./test/samples/${sampleName}.json`, 'utf-8'); 7 | const { data, changed } = jf(json, fixerOptions); 8 | expect(changed).toEqual(expectedChange); 9 | expect(data).toEqual(expectedOutput); 10 | }; 11 | 12 | module.exports = { exam }; 13 | -------------------------------------------------------------------------------- /src/transform.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable security/detect-object-injection */ 2 | const { psw } = require('./utils'); 3 | const chalk = require('chalk'); 4 | 5 | const quotify = ({ fixedData, targetLine, fixedLine, verbose }) => { 6 | if (verbose) psw(chalk.magenta('Adding quotes...')); 7 | fixedData[targetLine] = fixedLine.replace(/(":\s*)(\S*)/g, '$1"$2"'); 8 | return fixedData; 9 | }; 10 | 11 | const numberify = ({ fixedData, targetLine, fixedLine, unquotedWord, verbose }) => { 12 | if (verbose) { 13 | psw( 14 | chalk.cyan( 15 | "Found a non base-10 number and since JSON doesn't support those numbers types. I will turn it into a base-10 number to keep the structure intact" 16 | ) 17 | ); 18 | } 19 | fixedData[targetLine] = fixedLine.replace(unquotedWord[2], Number(unquotedWord[2])); 20 | return fixedData; 21 | }; 22 | 23 | const baseNumify = ({ baseNumber, verbose }) => { 24 | if (verbose) { 25 | psw( 26 | chalk.cyan( 27 | "Found a non base-10 number and since JSON doesn't support those numbers types. I will turn it into a base-10 number to keep the structure intact" 28 | ) 29 | ); 30 | } 31 | return baseNumber.replace(/"(0[xbo][0-9a-fA-F]*)"/g, (_, num) => Number(num)); //base-(16|2|8) -> base-10 32 | }; 33 | 34 | module.exports = { 35 | quotify, 36 | numberify, 37 | baseNumify 38 | }; 39 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | const psw = (data) => process.stdout.write(`${data}\n`); 4 | 5 | const removeLinebreak = (line) => line.replace(/[\n\r]/g, ''); 6 | 7 | const replaceChar = (str, idx, chr) => str.substring(0, idx) + chr + str.substring(idx + 1); 8 | 9 | const verboseLog = ({ verbose = false, lines = [], err }) => { 10 | if (!verbose) return; 11 | psw('Data:'); 12 | lines.forEach((l, i) => psw(`${chalk.yellow(i)} ${l}`)); 13 | psw(chalk.red('err=')); 14 | console.dir(err); 15 | }; 16 | 17 | const curlyBracesIncluded = (line) => { 18 | const l = line.trim(); 19 | return l.startsWith('{') && l.endsWith('}'); 20 | }; 21 | 22 | module.exports = { psw, removeLinebreak, replaceChar, verboseLog, curlyBracesIncluded }; 23 | -------------------------------------------------------------------------------- /test/samples/b.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #8", 3 | "type": "JSON", 4 | "error": "trailing b", 5 | "version": b1000 6 | } -------------------------------------------------------------------------------- /test/samples/bin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #23", 3 | "type": "JSON", 4 | "error": "binary number", 5 | "version": 0b10111 6 | } -------------------------------------------------------------------------------- /test/samples/comment.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #16", 3 | "type": "JSON", 4 | "error": "comment", 5 | "version": "0x10" //16 6 | } -------------------------------------------------------------------------------- /test/samples/concat.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample " + "#25", 3 | "type": "JSON", 4 | "error": "concat", 5 | "version": 25 6 | } -------------------------------------------------------------------------------- /test/samples/doublyMissingQuotes.json: -------------------------------------------------------------------------------- 1 | { 2 | field: value 3 | } -------------------------------------------------------------------------------- /test/samples/doublyMissingQuotesMin.json: -------------------------------------------------------------------------------- 1 | {field: value} -------------------------------------------------------------------------------- /test/samples/exp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #28", 3 | "type": "JSON", 4 | "error": "exponents", 5 | "version": 1e3 6 | } -------------------------------------------------------------------------------- /test/samples/extraBrackets.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "extra brackets" 3 | }}} -------------------------------------------------------------------------------- /test/samples/extraChar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #4", 3 | "type": "JSON", 4 | "error": "trailing error", 5 | "version": 4, 6 | } -------------------------------------------------------------------------------- /test/samples/fp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #2", 3 | "type": "JSON", 4 | "version": 2.0 5 | } -------------------------------------------------------------------------------- /test/samples/hex.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #22", 3 | "type": "JSON", 4 | "error": "hex number", 5 | "version": 0x16 6 | } -------------------------------------------------------------------------------- /test/samples/issue31.json: -------------------------------------------------------------------------------- 1 | { 2 | something:"string:string" 3 | } -------------------------------------------------------------------------------- /test/samples/lefty1.json: -------------------------------------------------------------------------------- 1 | { t: 42 } -------------------------------------------------------------------------------- /test/samples/lefty2.json: -------------------------------------------------------------------------------- 1 | { 2 | ix: 1 3 | } -------------------------------------------------------------------------------- /test/samples/leftyO.json: -------------------------------------------------------------------------------- 1 | { 2 | o: 1 3 | } -------------------------------------------------------------------------------- /test/samples/missing.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #5", 3 | "type": "JSON", 4 | "error": "missing comma" 5 | "version": 5 6 | } -------------------------------------------------------------------------------- /test/samples/missingLHQuotes.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #14", 3 | "type": "JSON", 4 | "error": "missing quotes", 5 | long content: "a string" 6 | } -------------------------------------------------------------------------------- /test/samples/missingQuotes.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #11", 3 | "type": "JSON", 4 | "error": "missing quotes", 5 | "version": a string 6 | } -------------------------------------------------------------------------------- /test/samples/monOps.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #26", 3 | "type": "JSON", 4 | "error": "unary operations", 5 | "version": ~6 6 | } -------------------------------------------------------------------------------- /test/samples/multiComment.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #18", 3 | "type": "JSON", 4 | "error": "multi-comment", 5 | "version": 18 6 | /* 7 | lorem ipsum dolore sit amet 8 | */ 9 | } -------------------------------------------------------------------------------- /test/samples/multiOps.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #27", 3 | "type": "JSON", 4 | "error": "multi operations", 5 | "version": 1 + 2 * 3 6 | } -------------------------------------------------------------------------------- /test/samples/newLines.json: -------------------------------------------------------------------------------- 1 | {"Broken": " 2 | "} -------------------------------------------------------------------------------- /test/samples/noLHQuotes.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #13", 3 | "type": "JSON", 4 | "error": "missing quotes", 5 | version: "a string" 6 | } -------------------------------------------------------------------------------- /test/samples/noQuotes.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #10", 3 | "type": "JSON", 4 | "error": "missing quotes", 5 | "version": one 6 | } -------------------------------------------------------------------------------- /test/samples/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #0", 3 | "type": "JSON", 4 | "version": 0 5 | } -------------------------------------------------------------------------------- /test/samples/notCurly.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #15", 3 | "error": "wrong brackets", 4 | "info": { "one", "two" } 5 | } -------------------------------------------------------------------------------- /test/samples/notSquare.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #12", 3 | "error": "wrong brackets", 4 | "info": [ 5 | "type": "JSON", 6 | "version": 12 7 | ] 8 | } -------------------------------------------------------------------------------- /test/samples/o.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #9", 3 | "type": "JSON", 4 | "error": "trailing o", 5 | "version": o11 6 | } -------------------------------------------------------------------------------- /test/samples/oct.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #24", 3 | "type": "JSON", 4 | "error": "octal number", 5 | "version": 0o30 6 | } -------------------------------------------------------------------------------- /test/samples/ops.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #20", 3 | "type": "JSON", 4 | "error": "operations", 5 | "version": 2 * 10 6 | } -------------------------------------------------------------------------------- /test/samples/quoteInQuotes.json: -------------------------------------------------------------------------------- 1 | { "name": "Broadcast "Media" } -------------------------------------------------------------------------------- /test/samples/singleQuote.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #1", 3 | "type": "JSON", 4 | "error": "single quote", 5 | "version": '1' 6 | } -------------------------------------------------------------------------------- /test/samples/smComment.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #17", 3 | "type": "JSON", 4 | "error": "multi-comment", 5 | "version": "0x10" /* 16 in hex */ 6 | } -------------------------------------------------------------------------------- /test/samples/tab.json: -------------------------------------------------------------------------------- 1 | {"Test": " "} -------------------------------------------------------------------------------- /test/samples/tabs.json: -------------------------------------------------------------------------------- 1 | { 2 | "Test": " " 3 | } -------------------------------------------------------------------------------- /test/samples/threeErrs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #21", 3 | "type": JSON, 4 | "error": "3 errors" 5 | "version": x15 6 | } -------------------------------------------------------------------------------- /test/samples/trailingChar.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "test1": "1", 4 | "test2": { 5 | "a": "b", 6 | "c": { 7 | 8 | }, 9 | 10 | } 11 | } 12 | ] -------------------------------------------------------------------------------- /test/samples/trailingComma.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #6", 3 | "type": "JSON", 4 | "error": "trailing comma", 5 | "version": ,6 6 | } -------------------------------------------------------------------------------- /test/samples/trailingDot.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #3", 3 | "type": "JSON", 4 | "error": "trailing dot", 5 | "version": .3 6 | } -------------------------------------------------------------------------------- /test/samples/twoErrs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #19", 3 | "type": 'JSON', 4 | "error": "2 errors", 5 | "version": 19 //16 6 | } -------------------------------------------------------------------------------- /test/samples/x.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample #7", 3 | "type": "JSON", 4 | "error": "trailing x", 5 | "version": x7 6 | } -------------------------------------------------------------------------------- /test/sandbox.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const chalk = require('chalk') 3 | const jsonFix = require('../') 4 | const args = process.argv.slice(2) 5 | const files = args.length ? args : ['s4'] 6 | 7 | // Get the (potentially malformed) JSON data ready 8 | files.forEach(arg => { 9 | const file = `./test/samples/${arg}.json` 10 | const jsonContent = fs.readFileSync(file, 'utf-8') 11 | 12 | const {data, changed} = jsonFix(jsonContent, true) // Lint (and fix) it 13 | 14 | if (changed) { 15 | // Do something with `data` which is the fixed JSON data from `jsonContent` 16 | // e.g. `fs.writeFileSync(configPath, JSON.stringify(config, null, 2))` 17 | console.log(chalk.underline(`${file} changed:`)) 18 | console.log(JSON.stringify(data, null, 2)) 19 | } else console.log(chalk.underline(file, 'is correct')) 20 | }) 21 | --------------------------------------------------------------------------------