mirror of https://github.com/zulip/zulip.git
check-openapi: Use yaml library for better error messages.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
eeee095b10
commit
b7b4c033a5
|
@ -106,7 +106,6 @@
|
||||||
"eslint-import-resolver-webpack": "^0.13.0",
|
"eslint-import-resolver-webpack": "^0.13.0",
|
||||||
"eslint-plugin-import": "^2.22.0",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"eslint-plugin-unicorn": "^35.0.0",
|
"eslint-plugin-unicorn": "^35.0.0",
|
||||||
"js-yaml": "^4.0.0",
|
|
||||||
"jsdom": "^17.0.0",
|
"jsdom": "^17.0.0",
|
||||||
"mockdate": "^3.0.2",
|
"mockdate": "^3.0.2",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
@ -125,6 +124,7 @@
|
||||||
"vnu-jar": "^21.2.5",
|
"vnu-jar": "^21.2.5",
|
||||||
"webpack-dev-server": "^3.5.1",
|
"webpack-dev-server": "^3.5.1",
|
||||||
"xvfb": "^0.4.0",
|
"xvfb": "^0.4.0",
|
||||||
|
"yaml": "^2.0.0-8",
|
||||||
"yarn-deduplicate": "^3.0.0",
|
"yarn-deduplicate": "^3.0.0",
|
||||||
"zulip-js": "^2.0.8"
|
"zulip-js": "^2.0.8"
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,73 +4,79 @@
|
||||||
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
const jsyaml = require("js-yaml");
|
|
||||||
const ExampleValidator = require("openapi-examples-validator");
|
const ExampleValidator = require("openapi-examples-validator");
|
||||||
const SwaggerParser = require("swagger-parser");
|
const SwaggerParser = require("swagger-parser");
|
||||||
|
const {LineCounter, Scalar, YAMLMap, YAMLSeq, parseDocument, visit} = require("yaml");
|
||||||
|
|
||||||
|
async function checkFile(file) {
|
||||||
|
const yaml = await fs.promises.readFile(file, "utf8");
|
||||||
|
const lineCounter = new LineCounter();
|
||||||
|
const doc = parseDocument(yaml, {lineCounter});
|
||||||
|
if (doc.errors.length > 0) {
|
||||||
|
for (const error of doc.errors) {
|
||||||
|
console.error("%s: %s", file, error.message);
|
||||||
|
}
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = doc.contents;
|
||||||
|
if (!(root instanceof YAMLMap && root.has("openapi"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function checkRefSiblings(file, path, data) {
|
|
||||||
let ok = true;
|
let ok = true;
|
||||||
if (typeof data === "object" && data !== null) {
|
|
||||||
if (
|
visit(doc, {
|
||||||
"allOf" in data &&
|
Map(key, node) {
|
||||||
Object.values(data.allOf).filter((subschema) => !("$ref" in subschema)).length > 1
|
if (node.has("$ref") && node.items.length !== 1) {
|
||||||
) {
|
const {line, col} = lineCounter.linePos(node.range[0]);
|
||||||
console.error(
|
console.error("%s:%d:%d: Siblings of $ref have no effect", file, line, col);
|
||||||
`${file}: Too many inline allOf subschemas at ${JSON.stringify(
|
|
||||||
path,
|
|
||||||
)}: ${JSON.stringify(data, undefined, 2)}`,
|
|
||||||
);
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
if ("$ref" in data && Object.entries(data).length !== 1) {
|
|
||||||
console.error(
|
|
||||||
`${file}: Siblings of $ref have no effect at ${JSON.stringify(
|
|
||||||
path,
|
|
||||||
)}: ${JSON.stringify(data, undefined, 2)}`,
|
|
||||||
);
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
for (const [key, child] of Array.isArray(data) ? data.entries() : Object.entries(data)) {
|
|
||||||
if (!checkRefSiblings(file, [...path, key], child)) {
|
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
Pair(key, node) {
|
||||||
|
if (
|
||||||
|
node.key instanceof Scalar &&
|
||||||
|
node.key.value === "allOf" &&
|
||||||
|
node.value instanceof YAMLSeq &&
|
||||||
|
node.value.items.filter(
|
||||||
|
(subschema) => !(subschema instanceof YAMLMap && subschema.has("$ref")),
|
||||||
|
).length > 1
|
||||||
|
) {
|
||||||
|
const {line, col} = lineCounter.linePos(node.value.range[0]);
|
||||||
|
console.error("%s:%d:%d: Too many inline allOf subschemas", file, line, col);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await SwaggerParser.validate(file);
|
||||||
|
} catch (error) {
|
||||||
|
if (!(error instanceof SyntaxError)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
console.error("%s: %s", file, error.message);
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
const res = await ExampleValidator.validateFile(file);
|
||||||
|
if (!res.valid) {
|
||||||
|
for (const error of res.errors) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
process.exitCode = 1;
|
||||||
}
|
}
|
||||||
return ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// Iterate through the changed files, passed in the arguments.
|
|
||||||
// The two first arguments are the call to the Node interpreter and this
|
|
||||||
// script, hence the starting point at 2.
|
|
||||||
for (const file of process.argv.slice(2)) {
|
for (const file of process.argv.slice(2)) {
|
||||||
try {
|
await checkFile(file);
|
||||||
const data = jsyaml.load(await fs.promises.readFile(file, "utf8"), {
|
|
||||||
filename: file,
|
|
||||||
});
|
|
||||||
if (data.openapi !== undefined) {
|
|
||||||
if (!checkRefSiblings(file, [], data)) {
|
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
|
||||||
await SwaggerParser.validate(file);
|
|
||||||
const res = await ExampleValidator.validateFile(file);
|
|
||||||
if (!res.valid) {
|
|
||||||
for (const error of res.errors) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof jsyaml.YAMLException) {
|
|
||||||
console.error(error.message);
|
|
||||||
} else if (error instanceof SyntaxError) {
|
|
||||||
console.error(`${file}: ${error.message}`);
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})().catch((error) => {
|
})().catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
|
@ -48,4 +48,4 @@ API_FEATURE_LEVEL = 96
|
||||||
# historical commits sharing the same major version, in which case a
|
# historical commits sharing the same major version, in which case a
|
||||||
# minor version bump suffices.
|
# minor version bump suffices.
|
||||||
|
|
||||||
PROVISION_VERSION = "157.1"
|
PROVISION_VERSION = "157.2"
|
||||||
|
|
|
@ -8349,7 +8349,7 @@ js-yaml@^3.13.1:
|
||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
|
|
||||||
js-yaml@^4.0.0, js-yaml@^4.1.0:
|
js-yaml@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||||
|
@ -14926,6 +14926,11 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
|
||||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||||
|
|
||||||
|
yaml@^2.0.0-8:
|
||||||
|
version "2.0.0-8"
|
||||||
|
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-8.tgz#226365f0d804ba7fb8cc2b527a00a7a4a3d8ea5f"
|
||||||
|
integrity sha512-QaYgJZMfWD6fKN/EYMk6w1oLWPCr1xj9QaPSZW5qkDb3y8nGCXhy2Ono+AF4F+CSL/vGcqswcAT0BaS//pgD2A==
|
||||||
|
|
||||||
yargs-parser@^13.1.2:
|
yargs-parser@^13.1.2:
|
||||||
version "13.1.2"
|
version "13.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
|
||||||
|
|
Loading…
Reference in New Issue