mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Convert JSON schema validation to use @hyperjump/json-schema, validate against specific schema version, newly validate schema definition, add missing "$schema" property.
This commit is contained in:
parent
e07eb4bf73
commit
dd6fe21ac7
4 changed files with 84 additions and 45 deletions
|
@ -70,6 +70,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.23.0",
|
"@babel/core": "7.23.0",
|
||||||
"@babel/preset-env": "7.22.20",
|
"@babel/preset-env": "7.22.20",
|
||||||
|
"@hyperjump/json-schema": "1.6.0",
|
||||||
"ava": "5.3.1",
|
"ava": "5.3.1",
|
||||||
"babel-loader": "9.1.3",
|
"babel-loader": "9.1.3",
|
||||||
"c8": "8.0.1",
|
"c8": "8.0.1",
|
||||||
|
@ -91,7 +92,6 @@
|
||||||
"strip-json-comments": "5.0.1",
|
"strip-json-comments": "5.0.1",
|
||||||
"terser-webpack-plugin": "5.3.9",
|
"terser-webpack-plugin": "5.3.9",
|
||||||
"toml": "3.0.0",
|
"toml": "3.0.0",
|
||||||
"tv4": "1.3.0",
|
|
||||||
"typescript": "5.2.2",
|
"typescript": "5.2.2",
|
||||||
"webpack": "5.88.2",
|
"webpack": "5.88.2",
|
||||||
"webpack-cli": "5.1.4",
|
"webpack-cli": "5.1.4",
|
||||||
|
|
|
@ -8,7 +8,8 @@ const rules = require("../lib/rules");
|
||||||
|
|
||||||
// Schema scaffolding
|
// Schema scaffolding
|
||||||
const schema = {
|
const schema = {
|
||||||
"title": "Markdownlint configuration schema",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "markdownlint configuration schema",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"default": {
|
"default": {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"title": "Markdownlint configuration schema",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "markdownlint configuration schema",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"default": {
|
"default": {
|
||||||
|
|
|
@ -10,7 +10,6 @@ const pluginInline = require("markdown-it-for-inline");
|
||||||
const pluginSub = require("markdown-it-sub");
|
const pluginSub = require("markdown-it-sub");
|
||||||
const pluginSup = require("markdown-it-sup");
|
const pluginSup = require("markdown-it-sup");
|
||||||
const test = require("ava").default;
|
const test = require("ava").default;
|
||||||
const tv4 = require("tv4");
|
|
||||||
const { "exports": packageExports, homepage, version } =
|
const { "exports": packageExports, homepage, version } =
|
||||||
require("../package.json");
|
require("../package.json");
|
||||||
const markdownlint = require("../lib/markdownlint");
|
const markdownlint = require("../lib/markdownlint");
|
||||||
|
@ -19,6 +18,9 @@ const rules = require("../lib/rules");
|
||||||
const customRules = require("./rules/rules.js");
|
const customRules = require("./rules/rules.js");
|
||||||
const configSchema = require("../schema/markdownlint-config-schema.json");
|
const configSchema = require("../schema/markdownlint-config-schema.json");
|
||||||
|
|
||||||
|
const jsonSchemaVersion = "http://json-schema.org/draft-07/schema#";
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const markdownlintConfigSchemaUri = "https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema.json";
|
||||||
const deprecatedRuleNames = new Set(constants.deprecatedRuleNames);
|
const deprecatedRuleNames = new Set(constants.deprecatedRuleNames);
|
||||||
const configSchemaStrict = {
|
const configSchemaStrict = {
|
||||||
...configSchema,
|
...configSchema,
|
||||||
|
@ -911,8 +913,13 @@ test("readme", async(t) => {
|
||||||
t.true(!tagLeft, "Undocumented tag " + tagLeft + ".");
|
t.true(!tagLeft, "Undocumented tag " + tagLeft + ".");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("validateJsonUsingConfigSchemaStrict", (t) => {
|
test("validateJsonUsingConfigSchemaStrict", async(t) => {
|
||||||
t.plan(161);
|
t.plan(161);
|
||||||
|
const { addSchema, validate } =
|
||||||
|
// eslint-disable-next-line n/file-extension-in-import
|
||||||
|
await import("@hyperjump/json-schema/draft-07");
|
||||||
|
addSchema(configSchemaStrict, markdownlintConfigSchemaUri);
|
||||||
|
const validateConfigSchema = await validate(markdownlintConfigSchemaUri);
|
||||||
const configRe =
|
const configRe =
|
||||||
/^[\s\S]*<!-- markdownlint-configure-file ([\s\S]*) -->[\s\S]*$/;
|
/^[\s\S]*<!-- markdownlint-configure-file ([\s\S]*) -->[\s\S]*$/;
|
||||||
const ignoreFiles = new Set([
|
const ignoreFiles = new Set([
|
||||||
|
@ -922,32 +929,38 @@ test("validateJsonUsingConfigSchemaStrict", (t) => {
|
||||||
"test/invalid-ul-style-style.md",
|
"test/invalid-ul-style-style.md",
|
||||||
"test/wrong-types-in-config-file.md"
|
"test/wrong-types-in-config-file.md"
|
||||||
]);
|
]);
|
||||||
return import("globby")
|
const { globby } = await import("globby");
|
||||||
.then((module) => module.globby([
|
const files = await globby([
|
||||||
"*.md",
|
"*.md",
|
||||||
"doc/*.md",
|
"doc/*.md",
|
||||||
"helpers/*.md",
|
"helpers/*.md",
|
||||||
"micromark/*.md",
|
"micromark/*.md",
|
||||||
"schema/*.md",
|
"schema/*.md",
|
||||||
"test/*.md"
|
"test/*.md"
|
||||||
]))
|
]);
|
||||||
.then((files) => {
|
const testFiles = files.filter((file) => !ignoreFiles.has(file));
|
||||||
const testFiles = files.filter((file) => !ignoreFiles.has(file));
|
for (const file of testFiles) {
|
||||||
for (const file of testFiles) {
|
const data = fs.readFileSync(file, "utf8");
|
||||||
const data = fs.readFileSync(file, "utf8");
|
if (configRe.test(data)) {
|
||||||
if (configRe.test(data)) {
|
const config = data.replace(configRe, "$1");
|
||||||
const config = data.replace(configRe, "$1");
|
const result = validateConfigSchema(JSON.parse(config), "BASIC");
|
||||||
t.true(
|
t.true(
|
||||||
// @ts-ignore
|
result.valid,
|
||||||
tv4.validate(JSON.parse(config), configSchemaStrict),
|
`${file}\n${JSON.stringify(result, null, 2)}`
|
||||||
file + "\n" + JSON.stringify(tv4.error, null, 2));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("validateConfigSchemaAllowsUnknownProperties", (t) => {
|
test("validateConfigSchemaAllowsUnknownProperties", async(t) => {
|
||||||
t.plan(4);
|
t.plan(4);
|
||||||
|
const { addSchema, validate } =
|
||||||
|
// eslint-disable-next-line n/file-extension-in-import
|
||||||
|
await import("@hyperjump/json-schema/draft-07");
|
||||||
|
const configSchemaUri = "https://example.com/configSchema";
|
||||||
|
addSchema(configSchema, configSchemaUri);
|
||||||
|
const configSchemaStrictUri = "https://example.com/configSchemaStrict";
|
||||||
|
addSchema(configSchemaStrict, configSchemaStrictUri);
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
"property": true
|
"property": true
|
||||||
|
@ -959,36 +972,56 @@ test("validateConfigSchemaAllowsUnknownProperties", (t) => {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
for (const testCase of testCases) {
|
for (const testCase of testCases) {
|
||||||
|
const defaultResult =
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await validate(configSchemaUri, testCase, "BASIC");
|
||||||
t.true(
|
t.true(
|
||||||
// @ts-ignore
|
defaultResult.valid,
|
||||||
tv4.validate(testCase, configSchema),
|
"Unknown property blocked by default: " + JSON.stringify(testCase)
|
||||||
"Unknown property blocked by default: " + JSON.stringify(testCase));
|
);
|
||||||
|
const strictResult =
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await validate(configSchemaStrictUri, testCase, "BASIC");
|
||||||
t.false(
|
t.false(
|
||||||
// @ts-ignore
|
strictResult.valid,
|
||||||
tv4.validate(testCase, configSchemaStrict),
|
"Unknown property allowed when strict: " + JSON.stringify(testCase)
|
||||||
"Unknown property allowed when strict: " + JSON.stringify(testCase));
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("validateConfigSchemaAppliesToUnknownProperties", (t) => {
|
test("validateConfigSchemaAppliesToUnknownProperties", async(t) => {
|
||||||
t.plan(4);
|
t.plan(4);
|
||||||
|
const { addSchema, validate } =
|
||||||
|
// eslint-disable-next-line n/file-extension-in-import
|
||||||
|
await import("@hyperjump/json-schema/draft-07");
|
||||||
|
addSchema(configSchema, markdownlintConfigSchemaUri);
|
||||||
|
const validateConfigSchema = await validate(markdownlintConfigSchemaUri);
|
||||||
for (const allowed of [ true, {} ]) {
|
for (const allowed of [ true, {} ]) {
|
||||||
t.true(
|
t.true(
|
||||||
// @ts-ignore
|
validateConfigSchema({ "property": allowed }, "BASIC").valid,
|
||||||
tv4.validate({ "property": allowed }, configSchema),
|
`Unknown property value ${allowed} blocked`
|
||||||
`Unknown property value ${allowed} blocked`);
|
);
|
||||||
}
|
}
|
||||||
for (const blocked of [ 2, "string" ]) {
|
for (const blocked of [ 2, "string" ]) {
|
||||||
t.false(
|
t.false(
|
||||||
// @ts-ignore
|
validateConfigSchema({ "property": blocked }, "BASIC").valid,
|
||||||
tv4.validate({ "property": blocked }, configSchema),
|
`Unknown property value ${blocked} allowed`
|
||||||
`Unknown property value ${blocked} allowed`);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("validateConfigExampleJson", async(t) => {
|
test("validateConfigExampleJson", async(t) => {
|
||||||
t.plan(2);
|
t.plan(3);
|
||||||
const { "default": stripJsonComments } = await import("strip-json-comments");
|
const { "default": stripJsonComments } = await import("strip-json-comments");
|
||||||
|
|
||||||
|
// Validate schema
|
||||||
|
const { addSchema, validate } =
|
||||||
|
// eslint-disable-next-line n/file-extension-in-import
|
||||||
|
await import("@hyperjump/json-schema/draft-07");
|
||||||
|
const schemaResult =
|
||||||
|
await validate(jsonSchemaVersion, configSchema, "BASIC");
|
||||||
|
t.true(schemaResult.valid);
|
||||||
|
|
||||||
// Validate JSONC
|
// Validate JSONC
|
||||||
const fileJson = ".markdownlint.jsonc";
|
const fileJson = ".markdownlint.jsonc";
|
||||||
const dataJson = fs.readFileSync(
|
const dataJson = fs.readFileSync(
|
||||||
|
@ -996,10 +1029,14 @@ test("validateConfigExampleJson", async(t) => {
|
||||||
"utf8"
|
"utf8"
|
||||||
);
|
);
|
||||||
const jsonObject = JSON.parse(stripJsonComments(dataJson));
|
const jsonObject = JSON.parse(stripJsonComments(dataJson));
|
||||||
|
addSchema(configSchemaStrict, markdownlintConfigSchemaUri);
|
||||||
|
const result =
|
||||||
|
await validate(markdownlintConfigSchemaUri, jsonObject, "BASIC");
|
||||||
t.true(
|
t.true(
|
||||||
// @ts-ignore
|
result.valid,
|
||||||
tv4.validate(jsonObject, configSchemaStrict),
|
`${fileJson}\n${JSON.stringify(result, null, 2)}`
|
||||||
fileJson + "\n" + JSON.stringify(tv4.error, null, 2));
|
);
|
||||||
|
|
||||||
// Validate YAML
|
// Validate YAML
|
||||||
const fileYaml = ".markdownlint.yaml";
|
const fileYaml = ".markdownlint.yaml";
|
||||||
const dataYaml = fs.readFileSync(
|
const dataYaml = fs.readFileSync(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue