diff --git a/README.md b/README.md index d26999c..a7a9da1 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,19 @@ Additionally Speccy [doesn't support JS modules](https://github.com/wework/specc which is a pain if you like writing your API documents like that - the underlying `oas-linter` has no problem though. -Note that this module does not directly support YAML, but can by adding a wrapper -file that parses your YAML and linting that instead, e.g. install [yaml](https://www.npmjs.com/package/yaml) -and then create an `api.js` to lint, e.g. +Note that this module does not directly support YAML, but can support them by adding +a transformer to the jest config, e.g. ```javascript -const fs = require('fs') -const YAML = require('yaml') - -const file = fs.readFileSync('./file.yml', 'utf8') -module.exports = YAML.parse(file) +module.exports = { + runner: "oas-linter", + displayName: "oas-linter", + transform: { + "\\.yaml$": "jest-yaml-transform-not-flattened" + }, + testMatch: ["/api/*.yaml"], + moduleFileExtensions: ["yaml"] +}; ``` ## Warning @@ -30,7 +33,7 @@ This is very alpha; no tests have been written, no promises made, YMMV. ## Compatibility -This module is compatible with Node v8.x and upwards. Any incompatibilities with those versions should be reported as bugs. +This module is compatible with Node v8.x and upwards. Any incompatibilities with those versions should be reported as bugs. ## Usage @@ -48,7 +51,7 @@ yarn add --dev jest jest-runner-oas-linter ### Add your runner to Jest config -Once you have your Jest runner you can add it to your Jest config. You will almost +Once you have your Jest runner you can add it to your Jest config. You will almost certainly want to configure separate Jest [projects](https://jestjs.io/docs/en/configuration#projects-array-string-projectconfig) and only use this runner on modules that export an OpenAPI document. @@ -75,14 +78,14 @@ In your `jest-oas-linter.config.js` ```js module.exports = { - runner: 'oas-linter', - displayName: 'oas-linter', + runner: "oas-linter", + displayName: "oas-linter", testMatch: [ - '/path/to/your/api/doc.js', - '/path/to/another/api/doc.js', - '/path/to/another/api/doc/**/*.js', - ], -} + "/path/to/your/api/doc.js", + "/path/to/another/api/doc.js", + "/path/to/another/api/doc/**/*.js" + ] +}; ``` #### Minimal Steps @@ -104,8 +107,8 @@ Or in `jest.config.js` ```js module.exports = { - runner: 'oas-linter', - testMatch: ['/path/to/your/api/doc.js'], + runner: "oas-linter", + testMatch: ["/path/to/your/api/doc.js"] }; ``` @@ -115,8 +118,8 @@ Configuration can be specified in your project root in `.oaslintrc.json`, or in Currently the only two options are to specify whether the default rules should be loaded with `loadDefaultRules` and to specify additional rules to be applied. -* `loadDefaultRules` is boolean and defaults to true, [oas-linter default rules](https://github.com/Mermade/oas-kit/blob/master/packages/oas-linter/rules.yaml) can be seen over there -* `rules` is an array of objects, as per oas-linter's [applyRules](https://github.com/Mermade/oas-kit/blob/master/packages/oas-linter/index.js#L12). More details about the format of rules supported can be found over at `oas-kit`'s [linter rules](https://mermade.github.io/oas-kit/linter-rules.html) documentation and the default rules (link above) have many examples. +- `loadDefaultRules` is boolean and defaults to true, [oas-linter default rules](https://github.com/Mermade/oas-kit/blob/master/packages/oas-linter/rules.yaml) can be seen over there +- `rules` is an array of objects, as per oas-linter's [applyRules](https://github.com/Mermade/oas-kit/blob/master/packages/oas-linter/index.js#L12). More details about the format of rules supported can be found over at `oas-kit`'s [linter rules](https://mermade.github.io/oas-kit/linter-rules.html) documentation and the default rules (link above) have many examples. In your `package.json` diff --git a/package-lock.json b/package-lock.json index cff551e..910dd6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1679,7 +1679,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1697,11 +1698,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1714,15 +1717,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1825,7 +1831,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1835,6 +1842,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1847,17 +1855,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1874,6 +1885,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1946,7 +1958,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1956,6 +1969,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -2031,7 +2045,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -2061,6 +2076,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2078,6 +2094,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2116,11 +2133,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -3886,6 +3905,14 @@ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, + "node-eval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-eval/-/node-eval-2.0.0.tgz", + "integrity": "sha512-Ap+L9HznXAVeJj3TJ1op6M6bg5xtTq8L5CU/PJxtkhea/DrIxdTknGKIECKd/v/Lgql95iuMAYvIzBNd0pmcMg==", + "requires": { + "path-is-absolute": "1.0.1" + } + }, "node-fetch-h2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", diff --git a/package.json b/package.json index 5a201a7..73ef186 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "dependencies": { "create-jest-runner": "^0.5.3", "jest": "^24.6.0", + "node-eval": "^2.0.0", "oas-linter": "^3.0.1", "oas-validator": "^3.3.0", "pkg-dir": "^4.2.0" diff --git a/src/run.js b/src/run.js index 96f6fff..94f06b5 100644 --- a/src/run.js +++ b/src/run.js @@ -9,6 +9,7 @@ const { const validator = require('oas-validator') const linter = require('oas-linter') const pkgDir = require('pkg-dir') +const nodeEval = require('node-eval') const DEFAULT_CONFIG = { loadDefaultRules: true, @@ -17,13 +18,13 @@ const DEFAULT_CONFIG = { // Map an oas-linter warning to jest test result const warningToTest = (duration, testPath) => warning => { - const { ruleName, message, pointer } = warning + const { ruleName, pointer, rule } = warning return { duration, - errorMessage: message, // Does not seem to be used in reporters + errorMessage: `${rule.description} on ${pointer.replace(/~1/g, '/')}`, // Does not seem to be used in reporters testPath, - title: `${message} - ${pointer} (${ruleName})` + title: ruleName } } @@ -73,10 +74,25 @@ const loadConfig = testPath => // Run tests on a given file const run = ({ testPath, config, globalConfig }) => { - const schema = require(testPath) + const { transform } = config + + let schema + let fileContent = fs.readFileSync(testPath, { encoding: 'utf-8' }) + + if ( + !config.transformIgnorePatterns + .map(x => new RegExp(x)) + .find(x => x.test(testPath)) + ) { + const transformer = transform.find(x => new RegExp(x[0]).test(testPath)) + + if (transformer) { + const transformerObj = require(transformer[1]) + fileContent = transformerObj.process(fileContent, testPath, config) + } + } - // Avoid caching for `--watch` mode - delete delete require.cache[require.resolve(testPath)] + schema = nodeEval(fileContent, testPath) const test = { path: testPath, @@ -123,7 +139,7 @@ const run = ({ testPath, config, globalConfig }) => { return resolve( fail({ ...result, - errorMessage: 'Not a valid OpenAPI schema.' + errorMessage: 'Not a valider OpenAPI schema: ' + error.message }) ) } @@ -133,6 +149,7 @@ const run = ({ testPath, config, globalConfig }) => { toTestResult({ errorMessage: 'Schema is valid, but linting errors were present.', + skipped: false, stats: { failures: warnings.length, pending: 0,