Create strict JSON Schema for configuration (standalone for ease of use) and corresponding strict TypeScript type (via extends for conciseness) (fixes #1248).

This commit is contained in:
David Anson 2024-08-27 20:47:33 -07:00
parent bbca3ad209
commit 9c8e7156e1
10 changed files with 3070 additions and 1207 deletions

View file

@ -3140,6 +3140,13 @@ module.exports = markdownlint;
* @typedef {import("./configuration").Configuration} Configuration * @typedef {import("./configuration").Configuration} Configuration
*/ */
/**
* Configuration object for linting rules strictly. For the JSON schema, see
* {@link ../schema/markdownlint-config-schema-strict.json}.
*
* @typedef {import("./configuration-strict").ConfigurationStrict} ConfigurationStrict
*/
/** /**
* Rule configuration object. * Rule configuration object.
* *

View file

@ -164,3 +164,20 @@ markdownlint(options, assertLintResultsCallback);
(async () => { (async () => {
assertLintResultsCallback(null, await markdownlint.promises.markdownlint(options)); assertLintResultsCallback(null, await markdownlint.promises.markdownlint(options));
})(); })();
const configuration: markdownlint.Configuration = {
"custom-rule": true,
"no-hard-tabs": false,
"heading-style": {
"style": "consistent"
}
};
assert(configuration);
const configurationStrict: markdownlint.ConfigurationStrict = {
// "custom-rule": true,
"no-hard-tabs": false,
"heading-style": {
"style": "consistent"
}
};
assert(configurationStrict);

1185
lib/configuration-strict.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

1184
lib/configuration.d.ts vendored

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ export = markdownlint;
*/ */
declare function markdownlint(options: Options | null, callback: LintCallback): void; declare function markdownlint(options: Options | null, callback: LintCallback): void;
declare namespace markdownlint { declare namespace markdownlint {
export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises, GetMarkdownIt, RuleFunction, RuleParams, MarkdownParsers, ParserMarkdownIt, ParserMicromark, MarkdownItToken, MicromarkTokenType, MicromarkToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintContentCallback, LintCallback, Configuration, RuleConfiguration, ConfigurationParser, ReadConfigCallback, ResolveConfigExtendsCallback }; export { markdownlintSync as sync, readConfig, readConfigSync, getVersion, promises, GetMarkdownIt, RuleFunction, RuleParams, MarkdownParsers, ParserMarkdownIt, ParserMicromark, MarkdownItToken, MicromarkTokenType, MicromarkToken, RuleOnError, RuleOnErrorInfo, RuleOnErrorFixInfo, Rule, Options, Plugin, ToStringCallback, LintResults, LintError, FixInfo, LintContentCallback, LintCallback, Configuration, ConfigurationStrict, RuleConfiguration, ConfigurationParser, ReadConfigCallback, ResolveConfigExtendsCallback };
} }
/** /**
* Lint specified Markdown files synchronously. * Lint specified Markdown files synchronously.
@ -439,6 +439,11 @@ type LintCallback = (error: Error | null, results?: LintResults) => void;
* {@link ../schema/markdownlint-config-schema.json}. * {@link ../schema/markdownlint-config-schema.json}.
*/ */
type Configuration = import("./configuration").Configuration; type Configuration = import("./configuration").Configuration;
/**
* Configuration object for linting rules strictly. For the JSON schema, see
* {@link ../schema/markdownlint-config-schema-strict.json}.
*/
type ConfigurationStrict = import("./configuration-strict").ConfigurationStrict;
/** /**
* Rule configuration. * Rule configuration.
*/ */

View file

@ -1532,6 +1532,13 @@ module.exports = markdownlint;
* @typedef {import("./configuration").Configuration} Configuration * @typedef {import("./configuration").Configuration} Configuration
*/ */
/**
* Configuration object for linting rules strictly. For the JSON schema, see
* {@link ../schema/markdownlint-config-schema-strict.json}.
*
* @typedef {import("./configuration-strict").ConfigurationStrict} ConfigurationStrict
*/
/** /**
* Rule configuration object. * Rule configuration object.
* *

View file

@ -1,7 +1,7 @@
# Validating Configuration # Validating Configuration
A [JSON Schema][json-schema] is provided to enable validating configuration A [JSON Schema][json-schema] is provided to enable validating configuration
objects: [`markdownlint-config-schema.json`][markdownlint-config-schema] objects: [`markdownlint-config-schema.json`][markdownlint-config-schema].
Some editors automatically use a JSON Schema with files that reference it. For Some editors automatically use a JSON Schema with files that reference it. For
example, a `.markdownlint.json` file with: example, a `.markdownlint.json` file with:
@ -16,13 +16,11 @@ A JSON Schema validator can be used to check configuration files like so:
npx ajv-cli validate -s ./markdownlint/schema/markdownlint-config-schema.json -d "**/.markdownlint.{json,yaml}" --strict=false npx ajv-cli validate -s ./markdownlint/schema/markdownlint-config-schema.json -d "**/.markdownlint.{json,yaml}" --strict=false
``` ```
By default, any rule name is valid in order to allow for custom rules. To ensure By default, any rule name is valid because of custom rules. To allow only
that only built-in rules are used, change the value of `#/additionalProperties` built-in rules, use the
(at the bottom of the schema file) to `false` before validating: [`markdownlint-config-schema-strict.json`][markdownlint-config-schema-strict]
JSON Schema instead.
```json
"additionalProperties": false
```
[json-schema]: https://json-schema.org [json-schema]: https://json-schema.org
[markdownlint-config-schema]: markdownlint-config-schema.json [markdownlint-config-schema]: markdownlint-config-schema.json
[markdownlint-config-schema-strict]: markdownlint-config-schema-strict.json

View file

@ -9,7 +9,10 @@ const rules = require("../lib/rules");
const jsonSchemaToTypeScript = require("json-schema-to-typescript"); const jsonSchemaToTypeScript = require("json-schema-to-typescript");
const { version } = require("../lib/constants"); const { version } = require("../lib/constants");
const schemaUri = `https://raw.githubusercontent.com/DavidAnson/markdownlint/v${version}/schema/markdownlint-config-schema.json`; const schemaName = "markdownlint-config-schema.json";
const schemaUri = `https://raw.githubusercontent.com/DavidAnson/markdownlint/v${version}/schema/${schemaName}`;
const schemaStrictName = "markdownlint-config-schema-strict.json";
const schemaStrictUri = `https://raw.githubusercontent.com/DavidAnson/markdownlint/v${version}/schema/${schemaStrictName}`;
// Schema scaffolding // Schema scaffolding
const schema = { const schema = {
@ -574,20 +577,24 @@ for (const [ tag, tagTags ] of Object.entries(tags)) {
} }
// Write schema // Write schema
const schemaFile = path.join(__dirname, "markdownlint-config-schema.json"); const schemaFile = path.join(__dirname, schemaName);
fs.writeFileSync(schemaFile, JSON.stringify(schema, null, " ")); fs.writeFileSync(schemaFile, JSON.stringify(schema, null, " "));
// Write TypeScript declaration // Create and write strict schema
// See https://github.com/bcherny/json-schema-to-typescript/issues/356 for why const schemaStrict = {
// additionalProperties is deleted ...schema,
const schemaDeclaration = "$id": schemaStrictUri,
path.join(__dirname, "..", "lib", "configuration.d.ts"); "additionalProperties": false
// @ts-ignore };
delete schema.additionalProperties; const schemaFileStrict = path.join(__dirname, schemaStrictName);
schema.title = "Configuration"; fs.writeFileSync(schemaFileStrict, JSON.stringify(schemaStrict, null, " "));
// Write TypeScript declaration file
const declarationStrictName = path.join(__dirname, "..", "lib", "configuration-strict.d.ts");
schemaStrict.title = "ConfigurationStrict";
jsonSchemaToTypeScript.compile( jsonSchemaToTypeScript.compile(
// @ts-ignore // @ts-ignore
schema, schemaStrict,
"UNUSED" "UNUSED"
// eslint-disable-next-line unicorn/prefer-top-level-await // eslint-disable-next-line unicorn/prefer-top-level-await
).then((declaration) => fs.writeFileSync(schemaDeclaration, declaration)); ).then((declaration) => fs.writeFileSync(declarationStrictName, declaration));

File diff suppressed because it is too large Load diff

View file

@ -18,13 +18,9 @@ const constants = require("../lib/constants");
const rules = require("../lib/rules"); 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 configSchemaStrict = require("../schema/markdownlint-config-schema-strict.json");
const deprecatedRuleNames = new Set(constants.deprecatedRuleNames); const deprecatedRuleNames = new Set(constants.deprecatedRuleNames);
const configSchemaStrict = {
...configSchema,
"$id": `${configSchema.$id}-strict`,
"additionalProperties": false
};
const ajvOptions = { const ajvOptions = {
"allowUnionTypes": true "allowUnionTypes": true
}; };