diff --git a/config.schema.json b/config.schema.json index c7ad582..09b5656 100644 --- a/config.schema.json +++ b/config.schema.json @@ -21,7 +21,7 @@ "type": "array", "items": { "type": "string", - "pattern": "^\\d+\\|((?:@[a-z\\d*~-][a-z\\d*._~-]*/)?[a-z\\d~-][a-z\\d._~-]*>)+((?:@[a-z\\d*~-][a-z\\d*._~-]*/)?[a-z\\d~-][a-z\\d._~-]*)$" + "pattern": "^\\d+\\|((?:@[a-z\\d*~-][a-z\\d*._~-]*/)?[a-z\\d~-][a-z\\d._~-]*>)*?((?:@[a-z\\d*~-][a-z\\d*._~-]*/)?[a-z\\d~-][a-z\\d._~-]*)$" } } }, diff --git a/package-lock.json b/package-lock.json index 9c3a77b..eb3a421 100644 --- a/package-lock.json +++ b/package-lock.json @@ -461,12 +461,30 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", @@ -1144,14 +1162,14 @@ "dev": true }, "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.0.tgz", + "integrity": "sha512-svS9uILze/cXbH0z2myCK2Brqprx/+JJYK5pHicT/GQiBfzzhUVAIT6MwqJg8y4xV/zoGsUeuPuwtoiKSGE15g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, @@ -2073,6 +2091,18 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -2089,6 +2119,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2960,6 +2996,26 @@ "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } } }, "has": { @@ -4186,9 +4242,9 @@ "dev": true }, "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "json-stable-stringify-without-jsonify": { diff --git a/package.json b/package.json index f774f0a..234a4a7 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@types/yargs": "^16.0.0", "@typescript-eslint/eslint-plugin": "^4.15.0", "@typescript-eslint/parser": "^4.15.0", + "ajv": "^7.1.0", "eslint": "^7.19.0", "eslint-config-ackama": "^2.0.1", "eslint-plugin-eslint-comments": "^3.2.0", diff --git a/test/src/schema.spec.ts b/test/src/schema.spec.ts new file mode 100644 index 0000000..201278a --- /dev/null +++ b/test/src/schema.spec.ts @@ -0,0 +1,87 @@ +import Ajv, { ErrorObject } from 'ajv'; +import schema from '../../config.schema.json'; +import { Options as ParsedArgs } from '../../src'; + +const ajv = new Ajv(); + +const validate = (data: Partial) => { + ajv.validate(schema, data); + + return ajv.errors ?? []; +}; + +type TestCase = [data: Partial, expectedErrors: ErrorObject[]]; + +describe('config schema', () => { + it.each([ + '|', + '|@commitlint/cli>@commitlint/lint>@commitlint/rules>@commitlint/ensure', + '|@commitlint/cli', + '|meow>@commitlint/cli', + '1|', + '1|>', + '1|a>', + '1|a>b>', + '1|a>>b>>c', + '1|abc> asasdf1|df>asdf>', + 'abc|gulp>vinyl-fs>glob-stream>glob>minimatch', + 'abc|ember-cli>testem>socket.io>socket.io-parser>debug', + 'abc|socket.io>socket.io-parser' + ])('fails "%s"', invalidPath => { + const invalidPathError: ErrorObject = { + keyword: 'pattern', + dataPath: '/ignore/0', + schemaPath: '#/properties/ignore/items/pattern', + params: { pattern: expect.any(String) as string }, + message: expect.stringContaining('should match pattern') as string + }; + + expect(validate({ ignore: [invalidPath] })).toStrictEqual([ + invalidPathError + ]); + }); + + it.each([ + '1|a', + '1|a>b', + '1|a>b>c', + '1|abc', + '1|abc>a', + '118|gulp>vinyl-fs>glob-stream>glob>minimatch', + '813|css-loader>cssnano>postcss-svgo>svgo>js-yaml', + '1084|webpack>yargs>os-locale>mem', + '1500|webpack>yargs>yargs-parser', + '1523|gulp>vinyl-fs>glob-watcher>gaze>globule>lodash', + '534|ember-cli>testem>socket.io>socket.io-parser>debug', + '577|ember-cli>ember-try>cli-table2>lodash', + '577|ember-cli>ember-try>cli-table2', + '577|cli-table2', + '534|ember-cli>testem>socket.io>socket.io-parser', + '534|socket.io>socket.io-parser', + '534|socket.io-parser', + '1523|@commitlint/cli>@commitlint/lint>@commitlint/rules>@commitlint/ensure', + '1523|@commitlint/cli', + '1523|meow>@commitlint/cli' + ])('allows "%s"', validPath => { + expect(validate({ ignore: [validPath] })).toStrictEqual([]); + }); + + // misc cases + it.each([ + [ + // @ts-expect-error this is not a supported value + { packageManager: 'invalid' }, + [ + { + keyword: 'enum', + dataPath: '/packageManager', + schemaPath: '#/definitions/SupportedPackageManagerOrAuto/enum', + params: { allowedValues: ['auto', 'npm', 'yarn', 'pnpm'] }, + message: 'should be equal to one of the allowed values' + } + ] + ] + ])('validates as expected', (data, expectedErrors) => { + expect(validate(data)).toStrictEqual(expectedErrors); + }); +});