diff --git a/.github/workflows/validate-branch.yaml b/.github/workflows/validate-branch.yaml index 04b6b9c..72092a9 100644 --- a/.github/workflows/validate-branch.yaml +++ b/.github/workflows/validate-branch.yaml @@ -41,7 +41,7 @@ jobs: - name: Check dependency vulnerabilities run: |- npm i -g npm-audit-resolver@3.0.0-7 - npx check-audit + npx check-audit --omit dev validate-code: runs-on: ubuntu-18.04 diff --git a/jest.config.js b/jest.config.js index 37c2359..946c791 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,4 +2,5 @@ module.exports = { transform: { '^.+\\.ts$': 'ts-jest', }, + setupFilesAfterEnv: ['jest-extended/all'], }; diff --git a/package-lock.json b/package-lock.json index 9a93b60..2a8b085 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,12 @@ "@croct/json": "^1.0.0" }, "devDependencies": { - "@croct/eslint-plugin": "^0.1", + "@croct/eslint-plugin": "^0.6.3", "@types/jest": "^27.4", "@typescript-eslint/parser": "^5.13", "eslint": "^8.10", "jest": "^27.5", + "jest-extended": "^3.2.1", "ts-jest": "^27.1", "typescript": "^4.6" } @@ -637,9 +638,9 @@ "dev": true }, "node_modules/@croct/eslint-plugin": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@croct/eslint-plugin/-/eslint-plugin-0.1.3.tgz", - "integrity": "sha512-ahFG8ynQk4C2puUnwS0Ll0WpDU3ug3gqN2pjLb0pVczbdDse4F1a90OqDrWHjDPuuMfjsxOO6YW/I0XmfmdigA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@croct/eslint-plugin/-/eslint-plugin-0.6.3.tgz", + "integrity": "sha512-L6ilO88AhjAGWX5CFVu8g6c2yA2DVJoJ0jgTDSvOvTo3hvRHSB6UckFIIOHfC44Ay83U3873tPxexzjnrvJxBw==", "dev": true, "dependencies": { "@rushstack/eslint-patch": "^1.1", @@ -648,11 +649,13 @@ "eslint-config-airbnb": "^19.0", "eslint-config-airbnb-base": "^15.0", "eslint-plugin-cypress": "^2.12", + "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.25", "eslint-plugin-import-newlines": "^1.1", - "eslint-plugin-jest": "^26.1", + "eslint-plugin-jest": "^27.0.0", "eslint-plugin-jest-dom": "^4.0", "eslint-plugin-jsx-a11y": "^6.5", + "eslint-plugin-newline-destructuring": "^1.0.1", "eslint-plugin-no-smart-quotes": "^1.3", "eslint-plugin-react": "^7.28", "eslint-plugin-react-hooks": "^4.3", @@ -986,6 +989,18 @@ } } }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/source-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", @@ -1160,6 +1175,12 @@ "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", "dev": true }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -1348,14 +1369,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.45.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.1.tgz", - "integrity": "sha512-cOizjPlKEh0bXdFrBLTrI/J6B/QMlhwE9auOov53tgB+qMukH6/h8YAK/qw+QJGct/PTbdh2lytGyipxCcEtAw==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz", + "integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.45.1", - "@typescript-eslint/type-utils": "5.45.1", - "@typescript-eslint/utils": "5.45.1", + "@typescript-eslint/scope-manager": "5.48.0", + "@typescript-eslint/type-utils": "5.48.0", + "@typescript-eslint/utils": "5.48.0", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -1380,6 +1401,106 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz", + "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", + "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", + "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz", + "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.0", + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/typescript-estree": "5.48.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", + "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/experimental-utils": { "version": "5.45.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.45.1.tgz", @@ -1444,13 +1565,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.45.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.1.tgz", - "integrity": "sha512-aosxFa+0CoYgYEl3aptLe1svP910DJq68nwEJzyQcrtRhC4BN0tJAvZGAe+D0tzjJmFXe+h4leSsiZhwBa2vrA==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz", + "integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.45.1", - "@typescript-eslint/utils": "5.45.1", + "@typescript-eslint/typescript-estree": "5.48.0", + "@typescript-eslint/utils": "5.48.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1470,6 +1591,106 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz", + "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", + "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", + "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz", + "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.0", + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/typescript-estree": "5.48.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", + "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/types": { "version": "5.45.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.1.tgz", @@ -2792,6 +3013,34 @@ "node": ">=4" } }, + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-eslint-comments/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/eslint-plugin-import": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", @@ -2862,19 +3111,19 @@ "dev": true }, "node_modules/eslint-plugin-jest": { - "version": "26.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.9.0.tgz", - "integrity": "sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.0.tgz", + "integrity": "sha512-KGIYtelk4rIhKocxRKUEeX+kJ0ZCab/CiSgS8BMcKD7AY7YxXhlg/d51oF5jq2rOrtuJEDYWRwXD95l6l2vtrA==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -2953,6 +3202,15 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-newline-destructuring": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-newline-destructuring/-/eslint-plugin-newline-destructuring-1.1.1.tgz", + "integrity": "sha512-NiVhKJUFfboks225J2W7J6FGtlguzAF64wApvZ+xhaHd5qpctbjFd56vNOCDhUE2yEtaJpw9OYQPHJikBcrHew==", + "dev": true, + "peerDependencies": { + "eslint": ">=7.2.0" + } + }, "node_modules/eslint-plugin-no-smart-quotes": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-plugin-no-smart-quotes/-/eslint-plugin-no-smart-quotes-1.3.0.tgz", @@ -4473,6 +4731,92 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-extended": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-3.2.1.tgz", + "integrity": "sha512-+c+jL/KI/3OsU+jTFa8HFtwBzWhFixFYfOEfFdPIACN97HdgEcjkzKnotQQPZidwU4B/VqgA7LTy0yhAxfSCIw==", + "dev": true, + "dependencies": { + "jest-diff": "^29.0.0", + "jest-get-type": "^29.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": ">=27.2.5" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "node_modules/jest-extended/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-extended/node_modules/diff-sequences": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", + "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-extended/node_modules/jest-diff": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", + "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-extended/node_modules/jest-get-type": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", + "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-extended/node_modules/pretty-format": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", + "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-extended/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/jest-get-type": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", @@ -7321,9 +7665,9 @@ "dev": true }, "@croct/eslint-plugin": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@croct/eslint-plugin/-/eslint-plugin-0.1.3.tgz", - "integrity": "sha512-ahFG8ynQk4C2puUnwS0Ll0WpDU3ug3gqN2pjLb0pVczbdDse4F1a90OqDrWHjDPuuMfjsxOO6YW/I0XmfmdigA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@croct/eslint-plugin/-/eslint-plugin-0.6.3.tgz", + "integrity": "sha512-L6ilO88AhjAGWX5CFVu8g6c2yA2DVJoJ0jgTDSvOvTo3hvRHSB6UckFIIOHfC44Ay83U3873tPxexzjnrvJxBw==", "dev": true, "requires": { "@rushstack/eslint-patch": "^1.1", @@ -7332,11 +7676,13 @@ "eslint-config-airbnb": "^19.0", "eslint-config-airbnb-base": "^15.0", "eslint-plugin-cypress": "^2.12", + "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.25", "eslint-plugin-import-newlines": "^1.1", - "eslint-plugin-jest": "^26.1", + "eslint-plugin-jest": "^27.0.0", "eslint-plugin-jest-dom": "^4.0", "eslint-plugin-jsx-a11y": "^6.5", + "eslint-plugin-newline-destructuring": "^1.0.1", "eslint-plugin-no-smart-quotes": "^1.3", "eslint-plugin-react": "^7.28", "eslint-plugin-react-hooks": "^4.3", @@ -7591,6 +7937,15 @@ "v8-to-istanbul": "^8.1.0" } }, + "@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, "@jest/source-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", @@ -7732,6 +8087,12 @@ "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", "dev": true }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, "@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -7914,20 +8275,79 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.45.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.1.tgz", - "integrity": "sha512-cOizjPlKEh0bXdFrBLTrI/J6B/QMlhwE9auOov53tgB+qMukH6/h8YAK/qw+QJGct/PTbdh2lytGyipxCcEtAw==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz", + "integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.45.1", - "@typescript-eslint/type-utils": "5.45.1", - "@typescript-eslint/utils": "5.45.1", + "@typescript-eslint/scope-manager": "5.48.0", + "@typescript-eslint/type-utils": "5.48.0", + "@typescript-eslint/utils": "5.48.0", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz", + "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0" + } + }, + "@typescript-eslint/types": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", + "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", + "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz", + "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.0", + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/typescript-estree": "5.48.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", + "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.0", + "eslint-visitor-keys": "^3.3.0" + } + } } }, "@typescript-eslint/experimental-utils": { @@ -7962,15 +8382,74 @@ } }, "@typescript-eslint/type-utils": { - "version": "5.45.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.1.tgz", - "integrity": "sha512-aosxFa+0CoYgYEl3aptLe1svP910DJq68nwEJzyQcrtRhC4BN0tJAvZGAe+D0tzjJmFXe+h4leSsiZhwBa2vrA==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz", + "integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.45.1", - "@typescript-eslint/utils": "5.45.1", + "@typescript-eslint/typescript-estree": "5.48.0", + "@typescript-eslint/utils": "5.48.0", "debug": "^4.3.4", "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz", + "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0" + } + }, + "@typescript-eslint/types": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", + "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", + "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/visitor-keys": "5.48.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz", + "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.0", + "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/typescript-estree": "5.48.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", + "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.0", + "eslint-visitor-keys": "^3.3.0" + } + } } }, "@typescript-eslint/types": { @@ -8978,6 +9457,24 @@ } } }, + "eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, "eslint-plugin-import": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", @@ -9033,9 +9530,9 @@ "requires": {} }, "eslint-plugin-jest": { - "version": "26.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.9.0.tgz", - "integrity": "sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.0.tgz", + "integrity": "sha512-KGIYtelk4rIhKocxRKUEeX+kJ0ZCab/CiSgS8BMcKD7AY7YxXhlg/d51oF5jq2rOrtuJEDYWRwXD95l6l2vtrA==", "dev": true, "requires": { "@typescript-eslint/utils": "^5.10.0" @@ -9091,6 +9588,13 @@ } } }, + "eslint-plugin-newline-destructuring": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-newline-destructuring/-/eslint-plugin-newline-destructuring-1.1.1.tgz", + "integrity": "sha512-NiVhKJUFfboks225J2W7J6FGtlguzAF64wApvZ+xhaHd5qpctbjFd56vNOCDhUE2yEtaJpw9OYQPHJikBcrHew==", + "dev": true, + "requires": {} + }, "eslint-plugin-no-smart-quotes": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-plugin-no-smart-quotes/-/eslint-plugin-no-smart-quotes-1.3.0.tgz", @@ -10172,6 +10676,65 @@ "jest-util": "^27.5.1" } }, + "jest-extended": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-3.2.1.tgz", + "integrity": "sha512-+c+jL/KI/3OsU+jTFa8HFtwBzWhFixFYfOEfFdPIACN97HdgEcjkzKnotQQPZidwU4B/VqgA7LTy0yhAxfSCIw==", + "dev": true, + "requires": { + "jest-diff": "^29.0.0", + "jest-get-type": "^29.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "diff-sequences": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", + "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "dev": true + }, + "jest-diff": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", + "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + } + }, + "jest-get-type": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", + "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "dev": true + }, + "pretty-format": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", + "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, "jest-get-type": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", diff --git a/package.json b/package.json index bc4db69..a796bdd 100644 --- a/package.json +++ b/package.json @@ -34,11 +34,12 @@ "@croct/json": "^1.0.0" }, "devDependencies": { - "@croct/eslint-plugin": "^0.1", + "@croct/eslint-plugin": "^0.6.3", "@types/jest": "^27.4", "@typescript-eslint/parser": "^5.13", "eslint": "^8.10", "jest": "^27.5", + "jest-extended": "^3.2.1", "ts-jest": "^27.1", "typescript": "^4.6" }, diff --git a/src/pointer.ts b/src/pointer.ts index be171c0..934cae8 100644 --- a/src/pointer.ts +++ b/src/pointer.ts @@ -167,7 +167,9 @@ export class JsonPointer implements JsonConvertible { ); } - return new JsonPointer(path.substring(1).split('/').map(JsonPointer.unescapeSegment)); + return new JsonPointer(path.substring(1) + .split('/') + .map(JsonPointer.unescapeSegment)); } /** @@ -545,7 +547,9 @@ export class JsonPointer implements JsonConvertible { return ''; } - return `/${this.segments.map(JsonPointer.escapeSegment).join('/')}`; + return `/${this.segments + .map(JsonPointer.escapeSegment) + .join('/')}`; } /** diff --git a/test/jestExtended.d.ts b/test/jestExtended.d.ts new file mode 100644 index 0000000..9e6c1db --- /dev/null +++ b/test/jestExtended.d.ts @@ -0,0 +1 @@ +import 'jest-extended'; diff --git a/test/pointer.test.ts b/test/pointer.test.ts index 8f9b607..b00566d 100644 --- a/test/pointer.test.ts +++ b/test/pointer.test.ts @@ -1,5 +1,13 @@ import {JsonStructure, JsonValue} from '@croct/json'; -import {Entry, JsonPointer, JsonPointerLike, JsonPointerSegments} from '../src'; +import { + Entry, + InvalidReferenceError, + InvalidSyntaxError, + JsonPointer, + JsonPointerError, + JsonPointerLike, + JsonPointerSegments, +} from '../src'; describe('A JSON Pointer', () => { function toArray(iterator: Iterator): any[] { @@ -49,8 +57,10 @@ describe('A JSON Pointer', () => { )( 'should fail to convert "%s" because "%s"', (pointer: JsonPointerLike, expectedError: string) => { - expect(() => JsonPointer.from(pointer)) - .toThrow(expectedError); + expect(() => JsonPointer.from(pointer)).toThrowWithMessage( + InvalidSyntaxError, + expectedError, + ); }, ); @@ -62,8 +72,10 @@ describe('A JSON Pointer', () => { ['~1/foo', 'A non-root pointer must start with a slash, actual "~1/foo".'], ], )('should fail to parse "%s" reporting %s', (input: string, expectedError: string) => { - expect(() => JsonPointer.parse(input)) - .toThrowError(expectedError); + expect(() => JsonPointer.parse(input)).toThrowWithMessage( + InvalidSyntaxError, + expectedError, + ); }); it.each( @@ -100,13 +112,14 @@ describe('A JSON Pointer', () => { }); it('should fail to return the parent of the root pointer', () => { - expect(() => JsonPointer.root().getParent()) - .toThrowError('Cannot get parent of root pointer.'); + expect(() => JsonPointer.root().getParent()).toThrowWithMessage( + JsonPointerError, + 'Cannot get parent of root pointer.', + ); }); it('should return the pointer segments', () => { - expect(JsonPointer.parse('/foo/0/baz').getSegments()) - .toStrictEqual(['foo', 0, 'baz']); + expect(JsonPointer.parse('/foo/0/baz').getSegments()).toStrictEqual(['foo', 0, 'baz']); }); it.each( @@ -135,11 +148,15 @@ describe('A JSON Pointer', () => { ); it('should fail to create a sub pointer if the depth is out of bounds', () => { - expect(() => JsonPointer.parse('/foo').truncatedAt(-1)) - .toThrow('Depth -1 is out of bounds.'); + expect(() => JsonPointer.parse('/foo').truncatedAt(-1)).toThrowWithMessage( + JsonPointerError, + 'Depth -1 is out of bounds.', + ); - expect(() => JsonPointer.parse('/foo').truncatedAt(2)) - .toThrow('Depth 2 is out of bounds.'); + expect(() => JsonPointer.parse('/foo').truncatedAt(2)).toThrowWithMessage( + JsonPointerError, + 'Depth 2 is out of bounds.', + ); }); it.each( @@ -314,7 +331,10 @@ describe('A JSON Pointer', () => { )( 'should fail to get value at "%s" from %s because "%s"', (pointer: JsonPointer, structure: JsonStructure, expectedError: string) => { - expect(() => pointer.get(structure)).toThrowError(expectedError); + expect(() => pointer.get(structure)).toThrowWithMessage( + InvalidReferenceError, + expectedError, + ); }, ); @@ -525,20 +545,33 @@ describe('A JSON Pointer', () => { it.each( [ [ - JsonPointer.root(), - {bar: 'foo'}, - 'Cannot set root value.', + JsonPointer.parse('/foo'), + [], + 'Expected an object at "", got an array.', + ], + [ + JsonPointer.parse('/0'), + {}, + 'Expected array at "", got object.', ], + ], + )( + 'should fail to set value at "%s" into %s because "%s"', + (pointer: JsonPointer, structure: JsonStructure, errorMessage: string) => { + expect(() => pointer.set(structure, null)).toThrowWithMessage( + Error, + errorMessage, + ); + }, + ); + + it.each( + [ [ JsonPointer.parse('/foo/bar'), {bar: 'foo'}, 'Property "foo" does not exist at "".', ], - [ - JsonPointer.parse('/foo'), - [], - 'Expected an object at "", got an array.', - ], [ JsonPointer.parse('/1'), [], @@ -554,10 +587,23 @@ describe('A JSON Pointer', () => { [], 'Index 1 is out of bounds at "".', ], + ], + )( + 'should fail to set value at "%s" into %s with invalid reference error because "%s"', + (pointer: JsonPointer, structure: JsonStructure, errorMessage: string) => { + expect(() => pointer.set(structure, null)).toThrowWithMessage( + InvalidReferenceError, + errorMessage, + ); + }, + ); + + it.each( + [ [ - JsonPointer.parse('/0'), - {}, - 'Expected array at "", got object.', + JsonPointer.root(), + {bar: 'foo'}, + 'Cannot set root value.', ], [ JsonPointer.parse('/foo/bar'), @@ -581,9 +627,12 @@ describe('A JSON Pointer', () => { ], ], )( - 'should fail to set value at "%s" into %s because "%s"', - (pointer: JsonPointer, structure: JsonStructure, expectedError: string) => { - expect(() => pointer.set(structure, null)).toThrowError(expectedError); + 'should fail to set value at "%s" into %s with json pointer error because "%s"', + (pointer: JsonPointer, structure: JsonStructure, errorMessage: string) => { + expect(() => pointer.set(structure, null)).toThrowWithMessage( + JsonPointerError, + errorMessage, + ); }, ); @@ -745,8 +794,10 @@ describe('A JSON Pointer', () => { ); it('should fail to unset the root value', () => { - expect(() => JsonPointer.root().unset({})) - .toThrow('Cannot unset the root value.'); + expect(() => JsonPointer.root().unset({})).toThrowWithMessage( + InvalidReferenceError, + 'Cannot unset the root value.', + ); }); it.each<[JsonPointer, JsonStructure, Entry[]]>( @@ -880,7 +931,7 @@ describe('A JSON Pointer', () => { )( 'should fail to traverse "%s" from %o because "%s"', (pointer: JsonPointer, structure: JsonStructure, expectedError: string) => { - expect(() => toArray(pointer.traverse(structure))).toThrowError(expectedError); + expect(() => toArray(pointer.traverse(structure))).toThrowWithMessage(InvalidReferenceError, expectedError); }, ); diff --git a/test/relativePointer.test.ts b/test/relativePointer.test.ts index 097a03f..a6013b5 100644 --- a/test/relativePointer.test.ts +++ b/test/relativePointer.test.ts @@ -1,5 +1,12 @@ import {JsonValue} from '@croct/json'; -import {JsonPointer, JsonPointerLike, JsonPointerSegments} from '../src'; +import { + InvalidReferenceError, + InvalidSyntaxError, + JsonPointer, + JsonPointerError, + JsonPointerLike, + JsonPointerSegments, +} from '../src'; import {JsonRelativePointer, JsonRelativePointerLike} from '../src/relativePointer'; describe('A JSON Relative Pointer', () => { @@ -44,30 +51,34 @@ describe('A JSON Relative Pointer', () => { )( 'should fail to convert "%s" because it does not start with a valid relative segment', (pointer: JsonRelativePointerLike) => { - expect(() => JsonRelativePointer.from(pointer)) - .toThrow( - 'A relative JSON pointer must start with a non-negative ' - + 'integer optionally followed by a hash character.', - ); + expect(() => JsonRelativePointer.from(pointer)).toThrowWithMessage( + InvalidSyntaxError, + 'A relative JSON pointer must start with a non-negative ' + + 'integer optionally followed by a hash character.', + ); }, ); it('should have at least one segment', () => { - expect(() => JsonRelativePointer.from([])) - .toThrowError('A relative pointer must have at least one segment.'); + expect(() => JsonRelativePointer.from([])).toThrowWithMessage( + InvalidSyntaxError, + 'A relative pointer must have at least one segment.', + ); }); it('should validate escape sequences', () => { - expect(() => JsonRelativePointer.parse('1/~a')) - .toThrowError('Invalid escape sequence in "/1/~a".'); + expect(() => JsonRelativePointer.parse('1/~a')).toThrowWithMessage( + InvalidSyntaxError, + 'Invalid escape sequence in "/1/~a".', + ); }); it('should fail to parse an empty string', () => { - expect(() => JsonRelativePointer.parse('')) - .toThrowError( - 'A relative JSON pointer must start with a non-negative ' - + 'integer optionally followed by a hash character.', - ); + expect(() => JsonRelativePointer.parse('')).toThrowWithMessage( + InvalidSyntaxError, + 'A relative JSON pointer must start with a non-negative ' + + 'integer optionally followed by a hash character.', + ); }); it.each( @@ -120,16 +131,17 @@ describe('A JSON Relative Pointer', () => { }); it('should fail to return the parent of a unresolved segment', () => { - expect(() => JsonRelativePointer.parse('1').getParent()) - .toThrowError('Cannot get the parent of a unresolved segment.'); + expect(() => JsonRelativePointer.parse('1').getParent()).toThrowWithMessage( + JsonPointerError, + 'Cannot get the parent of a unresolved segment.', + ); }); it('should return the pointer segments', () => { expect(JsonRelativePointer.parse('1/foo/0/baz').getSegments()) .toStrictEqual([1, 'foo', 0, 'baz']); - expect(JsonRelativePointer.parse('1#').getSegments()) - .toStrictEqual(['1#']); + expect(JsonRelativePointer.parse('1#').getSegments()).toStrictEqual(['1#']); }); it.each( @@ -169,8 +181,10 @@ describe('A JSON Relative Pointer', () => { }); it('should fail to join a relative key target with another pointer', () => { - expect(() => JsonRelativePointer.parse('1#').joinedWith(JsonPointer.root())) - .toThrowError('Cannot join a key pointer.'); + expect(() => JsonRelativePointer.parse('1#').joinedWith(JsonPointer.root())).toThrowWithMessage( + JsonPointerError, + 'Cannot join a key pointer.', + ); }); it("should determine whether it's logically equal to another pointer", () => { @@ -273,9 +287,12 @@ describe('A JSON Relative Pointer', () => { ( relativePointer: JsonRelativePointer, basePointer: JsonPointer, - error: string, + expectedError: string, ) => { - expect(() => relativePointer.resolve(basePointer)).toThrow(error); + expect(() => relativePointer.resolve(basePointer)).toThrowWithMessage( + JsonPointerError, + expectedError, + ); }, ); @@ -445,70 +462,96 @@ describe('A JSON Relative Pointer', () => { it.each( [ - [ - null, - JsonPointer.parse('/invalid'), - JsonRelativePointer.parse('0'), - 'Cannot read value at "".', - ], - [ - {nested: 'foo'}, - JsonPointer.parse('/nested'), - JsonRelativePointer.parse('2'), - 'The relative pointer is out of bounds.', - ], - [ - {nested: 'foo'}, - JsonPointer.parse('/nested'), - JsonRelativePointer.parse('1+1'), - 'An offset can only be applied to array elements', - ], - [ - {nested: 'foo'}, - JsonPointer.parse('/nested'), - JsonRelativePointer.parse('1+1#'), - 'An offset can only be applied to array elements', - ], - [ - {nested: 'foo'}, - JsonPointer.parse('/nested'), - JsonRelativePointer.parse('1-1'), - 'An offset can only be applied to array elements', - ], - [ - {nested: 'foo'}, - JsonPointer.parse('/nested'), - JsonRelativePointer.parse('1-1#'), - 'An offset can only be applied to array elements', - ], - [ - {nested: [0, 1]}, - JsonPointer.parse('/nested/0'), - JsonRelativePointer.parse('0-1#'), - 'The element index is out of bounds.', - ], - [ - {nested: [0, 1]}, - JsonPointer.parse('/nested/1'), - JsonRelativePointer.parse('0+1#'), - 'The element index is out of bounds.', - ], - [ - {nested: 'foo'}, - JsonPointer.parse('/nested'), - JsonRelativePointer.parse('1#'), - 'The root value has no key.', - ], + { + root: null, + basePointer: JsonPointer.parse('/invalid'), + relativePointer: JsonRelativePointer.parse('0'), + error: { + type: InvalidReferenceError, + message: 'Cannot read value at "".', + }, + }, + { + root: {nested: 'foo'}, + basePointer: JsonPointer.parse('/nested'), + relativePointer: JsonRelativePointer.parse('2'), + error: { + type: JsonPointerError, + message: 'The relative pointer is out of bounds.', + }, + }, + { + root: {nested: 'foo'}, + basePointer: JsonPointer.parse('/nested'), + relativePointer: JsonRelativePointer.parse('1+1'), + error: { + type: InvalidReferenceError, + message: 'An offset can only be applied to array elements.', + }, + }, + { + root: {nested: 'foo'}, + basePointer: JsonPointer.parse('/nested'), + relativePointer: JsonRelativePointer.parse('1+1#'), + error: { + type: InvalidReferenceError, + message: 'An offset can only be applied to array elements.', + }, + }, + { + root: {nested: 'foo'}, + basePointer: JsonPointer.parse('/nested'), + relativePointer: JsonRelativePointer.parse('1-1'), + error: { + type: InvalidReferenceError, + message: 'An offset can only be applied to array elements.', + }, + }, + { + root: {nested: 'foo'}, + basePointer: JsonPointer.parse('/nested'), + relativePointer: JsonRelativePointer.parse('1-1#'), + error: { + type: InvalidReferenceError, + message: 'An offset can only be applied to array elements.', + }, + }, + { + root: {nested: [0, 1]}, + basePointer: JsonPointer.parse('/nested/0'), + relativePointer: JsonRelativePointer.parse('0-1#'), + error: { + type: InvalidReferenceError, + message: 'The element index is out of bounds.', + }, + }, + { + root: {nested: [0, 1]}, + basePointer: JsonPointer.parse('/nested/1'), + relativePointer: JsonRelativePointer.parse('0+1#'), + error: { + type: InvalidReferenceError, + message: 'The element index is out of bounds.', + }, + }, + { + root: {nested: 'foo'}, + basePointer: JsonPointer.parse('/nested'), + relativePointer: JsonRelativePointer.parse('1#'), + error: { + type: InvalidReferenceError, + message: 'The root value has no key.', + }, + }, ], )( - 'should fail to get value from %o starting from %s with pointer %s reporting "%s"', - ( - root: JsonValue, - basePointer: JsonPointer, - relativePointer: JsonRelativePointer, - error: string, - ) => { - expect(() => relativePointer.get(root, basePointer)).toThrow(error); + // eslint-disable-next-line max-len -- Disabled for better readability + 'should fail to get value from $root starting from $basePointer with pointer $relativePointer reporting "error.message"', + ({root, basePointer, relativePointer, error: {type, message}}) => { + expect(() => relativePointer.get(root, basePointer)).toThrowWithMessage( + type, + message, + ); }, ); @@ -835,7 +878,10 @@ describe('A JSON Relative Pointer', () => { relativePointer: JsonRelativePointer, error: string, ) => { - expect(() => relativePointer.set(root, true, basePointer)).toThrow(error); + expect(() => relativePointer.set(root, true, basePointer)).toThrowWithMessage( + JsonPointerError, + error, + ); }, ); @@ -943,7 +989,10 @@ describe('A JSON Relative Pointer', () => { relativePointer: JsonRelativePointer, error: string, ) => { - expect(() => relativePointer.unset(root, basePointer)).toThrow(error); + expect(() => relativePointer.unset(root, basePointer)).toThrowWithMessage( + JsonPointerError, + error, + ); }, );