diff --git a/package.json b/package.json index 77c0e058..5195f723 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,14 @@ "scripts": { "build-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2:v$VERSION -f docker/Dockerfile --label org.opencontainers.image.version=v$VERSION .", "build-docker-image-rules": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2-rules:v$VERSION -f docker/Dockerfile-rules --build-arg VERSION=v$VERSION --label org.opencontainers.image.version=v$VERSION .", - "ci": "npm-run-all --continue-on-error --parallel test-cover lint", + "ci": "npm-run-all --continue-on-error --parallel test-cover lint schema", "docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:latest npm install", "docker-npm-run-upgrade": "docker run --rm --tty --name npm-run-upgrade --volume $PWD:/home/workdir --workdir /home/workdir --user node node:latest npm run upgrade", "lint": "eslint --max-warnings 0 --no-eslintrc --config .eslintrc.json .", "lint-dockerfile": "docker run --rm -i hadolint/hadolint:latest-alpine < docker/Dockerfile", "lint-watch": "git ls-files | entr npm run lint", "publish-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker buildx build --platform linux/arm64,linux/amd64 -t davidanson/markdownlint-cli2:v$VERSION -t davidanson/markdownlint-cli2:latest -f docker/Dockerfile --push .", + "schema": "cpy ./node_modules/markdownlint/schema/markdownlint-config-schema.json ./schema --flat", "test": "ava --timeout=1m test/append-to-array-test.js test/fs-mock-test.js test/markdownlint-cli2-test.js test/markdownlint-cli2-test-exec.js test/markdownlint-cli2-test-fs.js test/markdownlint-cli2-test-main.js test/merge-options-test.js test/resolve-and-require-test.js", "test-cover": "c8 --100 npm test -- --concurrency=1", "test-docker-hub-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker image rm davidanson/markdownlint-cli2:v$VERSION davidanson/markdownlint-cli2:latest || true && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:v$VERSION \"*.md\" && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:latest \"*.md\"", @@ -62,7 +63,9 @@ "markdownlint-cli2-fix.js", "merge-options.js", "README.md", - "resolve-and-require.js" + "resolve-and-require.js", + "schema/markdownlint-cli2-config-schema.json", + "schema/markdownlint-config-schema.json" ], "dependencies": { "globby": "13.2.2", @@ -77,6 +80,7 @@ "ava": "5.3.1", "c8": "8.0.1", "cpy": "10.1.0", + "cpy-cli": "5.0.0", "del": "7.1.0", "eslint": "8.48.0", "eslint-plugin-n": "16.0.2", @@ -91,7 +95,8 @@ "markdownlint-cli2-formatter-sarif": "0.0.1", "markdownlint-cli2-formatter-summarize": "0.0.6", "markdownlint-rule-titlecase": "0.1.0", - "npm-run-all": "4.1.5" + "npm-run-all": "4.1.5", + "tv4": "1.3.0" }, "keywords": [ "markdown", diff --git a/schema/markdownlint-cli2-config-schema.json b/schema/markdownlint-cli2-config-schema.json new file mode 100644 index 00000000..93bbea49 --- /dev/null +++ b/schema/markdownlint-cli2-config-schema.json @@ -0,0 +1,109 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "markdownlint-cli2 configuration schema", + "type": "object", + "properties": { + "$schema": { + "description": "JSON Schema URI (used by some editors)", + "type": "string", + "default": "https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/main/schema/markdownlint-cli2-config-schema.json" + }, + "config": { + "description": "markdownlint-cli2 configuration schema", + "$ref": "./markdownlint-config-schema.json", + "default": {} + }, + "customRules": { + "description": "Module names or paths of custom rules to load and use when linting", + "type": "array", + "default": [], + "items": { + "description": "Module name or path of a custom rule", + "type": "string", + "minLength": 1 + } + }, + "fix": { + "description": "Whether to enable fixing of linting errors reported by rules that emit fix information", + "type": "boolean", + "default": false + }, + "frontMatter": { + "description": "Regular expression used to match and ignore any front matter at the beginning of a document", + "type": "string", + "minLength": 1, + "default": "" + }, + "globs": { + "description": "Glob expressions to include when linting (only valid at the root)", + "type": "array", + "default": [], + "items": { + "description": "Glob expression of files to lint", + "type": "string", + "minLength": 1 + } + }, + "ignores": { + "description": "Glob expressions to ignore when linting", + "type": "array", + "default": [], + "items": { + "description": "Glob expression of files to ignore", + "type": "string", + "minLength": 1 + } + }, + "markdownItPlugins": { + "description": "markdown-it plugins to load and use when linting", + "type": "array", + "default": [], + "items": { + "description": "Name or path of a markdown-it plugin followed by parameters", + "type": "array", + "items": [ + { + "description": "Name or path of a markdown-it plugin", + "type": "string", + "minLength": 1 + }, + { + "description": "Parameter(s) to pass to the markdown-it plugin" + } + ], + "minItems": 1 + } + }, + "noInlineConfig": { + "description": "Whether to disable support of HTML comments within Markdown content", + "type": "boolean", + "default": false + }, + "noProgress": { + "description": "Whether to disable the display of progress on stdout (only valid at the root)", + "type": "boolean", + "default": false + }, + "outputFormatters": { + "description": "Output formatters to load and use to customize markdownlint-cli2 output (only valid at the root)", + "type": "array", + "default": [], + "items": { + "description": "Name or path of an output formatter followed by parameters", + "type": "array", + "items": [ + { + "description": "Name or path of an output formatter", + "type": "string", + "minLength": 1 + }, + { + "description": "Parameter(s) to pass to the output formatter" + } + ], + "minItems": 1 + } + } + }, + "additionalProperties": false +} diff --git a/schema/markdownlint-config-schema.json b/schema/markdownlint-config-schema.json new file mode 100644 index 00000000..03fa000b --- /dev/null +++ b/schema/markdownlint-config-schema.json @@ -0,0 +1,1108 @@ +{ + "title": "Markdownlint configuration schema", + "type": "object", + "properties": { + "default": { + "description": "Default state for all rules", + "type": "boolean", + "default": true + }, + "extends": { + "description": "Path to configuration file to extend", + "type": [ + "string", + "null" + ], + "default": null + }, + "$schema": { + "description": "JSON Schema URI (used by some editors)", + "type": "string", + "default": "https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema.json" + }, + "MD001": { + "description": "MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time", + "type": "boolean", + "default": true + }, + "heading-increment": { + "$ref": "#/properties/MD001" + }, + "header-increment": { + "$ref": "#/properties/MD001" + }, + "MD002": { + "description": "MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "level": { + "description": "Heading level", + "type": "integer", + "minimum": 1, + "maximum": 6, + "default": 1 + } + }, + "additionalProperties": false + }, + "first-heading-h1": { + "$ref": "#/properties/MD002" + }, + "first-header-h1": { + "$ref": "#/properties/MD002" + }, + "MD003": { + "description": "MD003/heading-style/header-style - Heading style", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "Heading style", + "type": "string", + "enum": [ + "consistent", + "atx", + "atx_closed", + "setext", + "setext_with_atx", + "setext_with_atx_closed" + ], + "default": "consistent" + } + }, + "additionalProperties": false + }, + "heading-style": { + "$ref": "#/properties/MD003" + }, + "header-style": { + "$ref": "#/properties/MD003" + }, + "MD004": { + "description": "MD004/ul-style - Unordered list style", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "List style", + "type": "string", + "enum": [ + "consistent", + "asterisk", + "plus", + "dash", + "sublist" + ], + "default": "consistent" + } + }, + "additionalProperties": false + }, + "ul-style": { + "$ref": "#/properties/MD004" + }, + "MD005": { + "description": "MD005/list-indent - Inconsistent indentation for list items at the same level", + "type": "boolean", + "default": true + }, + "list-indent": { + "$ref": "#/properties/MD005" + }, + "MD006": { + "description": "MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line", + "type": "boolean", + "default": true + }, + "ul-start-left": { + "$ref": "#/properties/MD006" + }, + "MD007": { + "description": "MD007/ul-indent - Unordered list indentation", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "indent": { + "description": "Spaces for indent", + "type": "integer", + "minimum": 1, + "default": 2 + }, + "start_indented": { + "description": "Whether to indent the first level of the list", + "type": "boolean", + "default": false + }, + "start_indent": { + "description": "Spaces for first level indent (when start_indented is set)", + "type": "integer", + "minimum": 1, + "default": 2 + } + }, + "additionalProperties": false + }, + "ul-indent": { + "$ref": "#/properties/MD007" + }, + "MD009": { + "description": "MD009/no-trailing-spaces - Trailing spaces", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "br_spaces": { + "description": "Spaces for line break", + "type": "integer", + "minimum": 0, + "default": 2 + }, + "list_item_empty_lines": { + "description": "Allow spaces for empty lines in list items", + "type": "boolean", + "default": false + }, + "strict": { + "description": "Include unnecessary breaks", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "no-trailing-spaces": { + "$ref": "#/properties/MD009" + }, + "MD010": { + "description": "MD010/no-hard-tabs - Hard tabs", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "code_blocks": { + "description": "Include code blocks", + "type": "boolean", + "default": true + }, + "ignore_code_languages": { + "description": "Fenced code languages to ignore", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "spaces_per_tab": { + "description": "Number of spaces for each hard tab", + "type": "integer", + "minimum": 0, + "default": 1 + } + }, + "additionalProperties": false + }, + "no-hard-tabs": { + "$ref": "#/properties/MD010" + }, + "MD011": { + "description": "MD011/no-reversed-links - Reversed link syntax", + "type": "boolean", + "default": true + }, + "no-reversed-links": { + "$ref": "#/properties/MD011" + }, + "MD012": { + "description": "MD012/no-multiple-blanks - Multiple consecutive blank lines", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "maximum": { + "description": "Consecutive blank lines", + "type": "integer", + "minimum": 1, + "default": 1 + } + }, + "additionalProperties": false + }, + "no-multiple-blanks": { + "$ref": "#/properties/MD012" + }, + "MD013": { + "description": "MD013/line-length - Line length", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "line_length": { + "description": "Number of characters", + "type": "integer", + "minimum": 1, + "default": 80 + }, + "heading_line_length": { + "description": "Number of characters for headings", + "type": "integer", + "minimum": 1, + "default": 80 + }, + "code_block_line_length": { + "description": "Number of characters for code blocks", + "type": "integer", + "minimum": 1, + "default": 80 + }, + "code_blocks": { + "description": "Include code blocks", + "type": "boolean", + "default": true + }, + "tables": { + "description": "Include tables", + "type": "boolean", + "default": true + }, + "headings": { + "description": "Include headings", + "type": "boolean", + "default": true + }, + "headers": { + "description": "Include headings", + "type": "boolean", + "default": true + }, + "strict": { + "description": "Strict length checking", + "type": "boolean", + "default": false + }, + "stern": { + "description": "Stern length checking", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "line-length": { + "$ref": "#/properties/MD013" + }, + "MD014": { + "description": "MD014/commands-show-output - Dollar signs used before commands without showing output", + "type": "boolean", + "default": true + }, + "commands-show-output": { + "$ref": "#/properties/MD014" + }, + "MD018": { + "description": "MD018/no-missing-space-atx - No space after hash on atx style heading", + "type": "boolean", + "default": true + }, + "no-missing-space-atx": { + "$ref": "#/properties/MD018" + }, + "MD019": { + "description": "MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading", + "type": "boolean", + "default": true + }, + "no-multiple-space-atx": { + "$ref": "#/properties/MD019" + }, + "MD020": { + "description": "MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading", + "type": "boolean", + "default": true + }, + "no-missing-space-closed-atx": { + "$ref": "#/properties/MD020" + }, + "MD021": { + "description": "MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading", + "type": "boolean", + "default": true + }, + "no-multiple-space-closed-atx": { + "$ref": "#/properties/MD021" + }, + "MD022": { + "description": "MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "lines_above": { + "description": "Blank lines above heading", + "type": [ + "integer", + "array" + ], + "items": { + "type": "integer" + }, + "minimum": -1, + "default": 1 + }, + "lines_below": { + "description": "Blank lines below heading", + "type": [ + "integer", + "array" + ], + "items": { + "type": "integer" + }, + "minimum": -1, + "default": 1 + } + }, + "additionalProperties": false + }, + "blanks-around-headings": { + "$ref": "#/properties/MD022" + }, + "blanks-around-headers": { + "$ref": "#/properties/MD022" + }, + "MD023": { + "description": "MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line", + "type": "boolean", + "default": true + }, + "heading-start-left": { + "$ref": "#/properties/MD023" + }, + "header-start-left": { + "$ref": "#/properties/MD023" + }, + "MD024": { + "description": "MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "allow_different_nesting": { + "description": "Only check sibling headings", + "type": "boolean", + "default": false + }, + "siblings_only": { + "description": "Only check sibling headings", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "no-duplicate-heading": { + "$ref": "#/properties/MD024" + }, + "no-duplicate-header": { + "$ref": "#/properties/MD024" + }, + "MD025": { + "description": "MD025/single-title/single-h1 - Multiple top-level headings in the same document", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "level": { + "description": "Heading level", + "type": "integer", + "minimum": 1, + "maximum": 6, + "default": 1 + }, + "front_matter_title": { + "description": "RegExp for matching title in front matter", + "type": "string", + "default": "^\\s*title\\s*[:=]" + } + }, + "additionalProperties": false + }, + "single-title": { + "$ref": "#/properties/MD025" + }, + "single-h1": { + "$ref": "#/properties/MD025" + }, + "MD026": { + "description": "MD026/no-trailing-punctuation - Trailing punctuation in heading", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "punctuation": { + "description": "Punctuation characters", + "type": "string", + "default": ".,;:!。,;:!" + } + }, + "additionalProperties": false + }, + "no-trailing-punctuation": { + "$ref": "#/properties/MD026" + }, + "MD027": { + "description": "MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol", + "type": "boolean", + "default": true + }, + "no-multiple-space-blockquote": { + "$ref": "#/properties/MD027" + }, + "MD028": { + "description": "MD028/no-blanks-blockquote - Blank line inside blockquote", + "type": "boolean", + "default": true + }, + "no-blanks-blockquote": { + "$ref": "#/properties/MD028" + }, + "MD029": { + "description": "MD029/ol-prefix - Ordered list item prefix", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "List style", + "type": "string", + "enum": [ + "one", + "ordered", + "one_or_ordered", + "zero" + ], + "default": "one_or_ordered" + } + }, + "additionalProperties": false + }, + "ol-prefix": { + "$ref": "#/properties/MD029" + }, + "MD030": { + "description": "MD030/list-marker-space - Spaces after list markers", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "ul_single": { + "description": "Spaces for single-line unordered list items", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "ol_single": { + "description": "Spaces for single-line ordered list items", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "ul_multi": { + "description": "Spaces for multi-line unordered list items", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "ol_multi": { + "description": "Spaces for multi-line ordered list items", + "type": "integer", + "minimum": 1, + "default": 1 + } + }, + "additionalProperties": false + }, + "list-marker-space": { + "$ref": "#/properties/MD030" + }, + "MD031": { + "description": "MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "list_items": { + "description": "Include list items", + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + }, + "blanks-around-fences": { + "$ref": "#/properties/MD031" + }, + "MD032": { + "description": "MD032/blanks-around-lists - Lists should be surrounded by blank lines", + "type": "boolean", + "default": true + }, + "blanks-around-lists": { + "$ref": "#/properties/MD032" + }, + "MD033": { + "description": "MD033/no-inline-html - Inline HTML", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "allowed_elements": { + "description": "Allowed elements", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "additionalProperties": false + }, + "no-inline-html": { + "$ref": "#/properties/MD033" + }, + "MD034": { + "description": "MD034/no-bare-urls - Bare URL used", + "type": "boolean", + "default": true + }, + "no-bare-urls": { + "$ref": "#/properties/MD034" + }, + "MD035": { + "description": "MD035/hr-style - Horizontal rule style", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "Horizontal rule style", + "type": "string", + "default": "consistent" + } + }, + "additionalProperties": false + }, + "hr-style": { + "$ref": "#/properties/MD035" + }, + "MD036": { + "description": "MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "punctuation": { + "description": "Punctuation characters", + "type": "string", + "default": ".,;:!?。,;:!?" + } + }, + "additionalProperties": false + }, + "no-emphasis-as-heading": { + "$ref": "#/properties/MD036" + }, + "no-emphasis-as-header": { + "$ref": "#/properties/MD036" + }, + "MD037": { + "description": "MD037/no-space-in-emphasis - Spaces inside emphasis markers", + "type": "boolean", + "default": true + }, + "no-space-in-emphasis": { + "$ref": "#/properties/MD037" + }, + "MD038": { + "description": "MD038/no-space-in-code - Spaces inside code span elements", + "type": "boolean", + "default": true + }, + "no-space-in-code": { + "$ref": "#/properties/MD038" + }, + "MD039": { + "description": "MD039/no-space-in-links - Spaces inside link text", + "type": "boolean", + "default": true + }, + "no-space-in-links": { + "$ref": "#/properties/MD039" + }, + "MD040": { + "description": "MD040/fenced-code-language - Fenced code blocks should have a language specified", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "allowed_languages": { + "description": "List of languages", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "language_only": { + "description": "Require language only", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "fenced-code-language": { + "$ref": "#/properties/MD040" + }, + "MD041": { + "description": "MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "level": { + "description": "Heading level", + "type": "integer", + "minimum": 1, + "maximum": 6, + "default": 1 + }, + "front_matter_title": { + "description": "RegExp for matching title in front matter", + "type": "string", + "default": "^\\s*title\\s*[:=]" + } + }, + "additionalProperties": false + }, + "first-line-heading": { + "$ref": "#/properties/MD041" + }, + "first-line-h1": { + "$ref": "#/properties/MD041" + }, + "MD042": { + "description": "MD042/no-empty-links - No empty links", + "type": "boolean", + "default": true + }, + "no-empty-links": { + "$ref": "#/properties/MD042" + }, + "MD043": { + "description": "MD043/required-headings/required-headers - Required heading structure", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "headings": { + "description": "List of headings", + "type": "array", + "items": { + "type": "string", + "pattern": "^(\\*|\\+|#{1,6} .*)$" + }, + "default": [] + }, + "headers": { + "description": "List of headings", + "type": "array", + "items": { + "type": "string", + "pattern": "^(\\*|\\+|#{1,6} .*)$" + }, + "default": [] + }, + "match_case": { + "description": "Match case of headings", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "required-headings": { + "$ref": "#/properties/MD043" + }, + "required-headers": { + "$ref": "#/properties/MD043" + }, + "MD044": { + "description": "MD044/proper-names - Proper names should have the correct capitalization", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "names": { + "description": "List of proper names", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "code_blocks": { + "description": "Include code blocks", + "type": "boolean", + "default": true + }, + "html_elements": { + "description": "Include HTML elements", + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + }, + "proper-names": { + "$ref": "#/properties/MD044" + }, + "MD045": { + "description": "MD045/no-alt-text - Images should have alternate text (alt text)", + "type": "boolean", + "default": true + }, + "no-alt-text": { + "$ref": "#/properties/MD045" + }, + "MD046": { + "description": "MD046/code-block-style - Code block style", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "Block style", + "type": "string", + "enum": [ + "consistent", + "fenced", + "indented" + ], + "default": "consistent" + } + }, + "additionalProperties": false + }, + "code-block-style": { + "$ref": "#/properties/MD046" + }, + "MD047": { + "description": "MD047/single-trailing-newline - Files should end with a single newline character", + "type": "boolean", + "default": true + }, + "single-trailing-newline": { + "$ref": "#/properties/MD047" + }, + "MD048": { + "description": "MD048/code-fence-style - Code fence style", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "Code fence style", + "type": "string", + "enum": [ + "consistent", + "backtick", + "tilde" + ], + "default": "consistent" + } + }, + "additionalProperties": false + }, + "code-fence-style": { + "$ref": "#/properties/MD048" + }, + "MD049": { + "description": "MD049/emphasis-style - Emphasis style should be consistent", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "Emphasis style", + "type": "string", + "enum": [ + "consistent", + "asterisk", + "underscore" + ], + "default": "consistent" + } + }, + "additionalProperties": false + }, + "emphasis-style": { + "$ref": "#/properties/MD049" + }, + "MD050": { + "description": "MD050/strong-style - Strong style should be consistent", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "style": { + "description": "Strong style", + "type": "string", + "enum": [ + "consistent", + "asterisk", + "underscore" + ], + "default": "consistent" + } + }, + "additionalProperties": false + }, + "strong-style": { + "$ref": "#/properties/MD050" + }, + "MD051": { + "description": "MD051/link-fragments - Link fragments should be valid", + "type": "boolean", + "default": true + }, + "link-fragments": { + "$ref": "#/properties/MD051" + }, + "MD052": { + "description": "MD052/reference-links-images - Reference links and images should use a label that is defined", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "shortcut_syntax": { + "description": "Include shortcut syntax", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "reference-links-images": { + "$ref": "#/properties/MD052" + }, + "MD053": { + "description": "MD053/link-image-reference-definitions - Link and image reference definitions should be needed", + "type": [ + "boolean", + "object" + ], + "default": true, + "properties": { + "ignored_definitions": { + "description": "Ignored definitions", + "type": "array", + "items": { + "type": "string" + }, + "default": [ + "//" + ] + } + }, + "additionalProperties": false + }, + "link-image-reference-definitions": { + "$ref": "#/properties/MD053" + }, + "headings": { + "description": "headings - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043", + "type": "boolean", + "default": true + }, + "headers": { + "description": "headers - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043", + "type": "boolean", + "default": true + }, + "bullet": { + "description": "bullet - MD004, MD005, MD006, MD007, MD032", + "type": "boolean", + "default": true + }, + "ul": { + "description": "ul - MD004, MD005, MD006, MD007, MD030, MD032", + "type": "boolean", + "default": true + }, + "indentation": { + "description": "indentation - MD005, MD006, MD007, MD027", + "type": "boolean", + "default": true + }, + "whitespace": { + "description": "whitespace - MD009, MD010, MD012, MD027, MD028, MD030, MD037, MD038, MD039", + "type": "boolean", + "default": true + }, + "hard_tab": { + "description": "hard_tab - MD010", + "type": "boolean", + "default": true + }, + "links": { + "description": "links - MD011, MD034, MD039, MD042, MD051, MD052, MD053", + "type": "boolean", + "default": true + }, + "blank_lines": { + "description": "blank_lines - MD012, MD022, MD031, MD032, MD047", + "type": "boolean", + "default": true + }, + "line_length": { + "description": "line_length - MD013", + "type": "boolean", + "default": true + }, + "code": { + "description": "code - MD014, MD031, MD038, MD040, MD046, MD048", + "type": "boolean", + "default": true + }, + "atx": { + "description": "atx - MD018, MD019", + "type": "boolean", + "default": true + }, + "spaces": { + "description": "spaces - MD018, MD019, MD020, MD021, MD023", + "type": "boolean", + "default": true + }, + "atx_closed": { + "description": "atx_closed - MD020, MD021", + "type": "boolean", + "default": true + }, + "blockquote": { + "description": "blockquote - MD027, MD028", + "type": "boolean", + "default": true + }, + "ol": { + "description": "ol - MD029, MD030, MD032", + "type": "boolean", + "default": true + }, + "html": { + "description": "html - MD033", + "type": "boolean", + "default": true + }, + "url": { + "description": "url - MD034", + "type": "boolean", + "default": true + }, + "hr": { + "description": "hr - MD035", + "type": "boolean", + "default": true + }, + "emphasis": { + "description": "emphasis - MD036, MD037, MD049, MD050", + "type": "boolean", + "default": true + }, + "language": { + "description": "language - MD040", + "type": "boolean", + "default": true + }, + "spelling": { + "description": "spelling - MD044", + "type": "boolean", + "default": true + }, + "accessibility": { + "description": "accessibility - MD045", + "type": "boolean", + "default": true + }, + "images": { + "description": "images - MD045, MD052, MD053", + "type": "boolean", + "default": true + } + }, + "additionalProperties": { + "type": [ + "boolean", + "object" + ] + } +} \ No newline at end of file diff --git a/test/markdownlint-cli2-test.js b/test/markdownlint-cli2-test.js index c3e5a68a..b82d1a44 100644 --- a/test/markdownlint-cli2-test.js +++ b/test/markdownlint-cli2-test.js @@ -2,8 +2,10 @@ "use strict"; +const fs = require("node:fs/promises"); const path = require("node:path"); const test = require("ava").default; +const tv4 = require("tv4"); const { "main": markdownlintCli2 } = require("../markdownlint-cli2.js"); const FsMock = require("./fs-mock"); @@ -54,6 +56,58 @@ test("README files", (t) => { then((exitCode) => t.is(exitCode, 0)); }); +test("validateMarkdownlintConfigSchema", async (t) => { + t.plan(25); + const schema = require("../schema/markdownlint-config-schema.json"); + const { "default": stripJsonComments } = await import("strip-json-comments"); + const { globby } = await import("globby"); + const files = await globby( + [ + "**/*.markdownlint.(json|jsonc)", + "!**/*invalid*/**", + "!**/invalid*" + ], + { + "dot": true + } + ); + return Promise.all(files.map(async (file) => { + const content = await fs.readFile(file, "utf8"); + const json = JSON.parse(stripJsonComments(content)); + t.true( + // @ts-ignore + tv4.validate(json, schema), + `${file}\n${JSON.stringify(tv4.error, null, 2)}` + ); + })); +}); + +test("validateMarkdownlintCli2ConfigSchema", async (t) => { + t.plan(78); + const schema = require("../schema/markdownlint-cli2-config-schema.json"); + const { "default": stripJsonComments } = await import("strip-json-comments"); + const { globby } = await import("globby"); + const files = await globby( + [ + "**/*.markdownlint-cli2.(json|jsonc)", + "!**/*invalid*/**", + "!**/invalid*", + "!test/customRules/dir/subdir2/.markdownlint-cli2.jsonc" + ], + { + "dot": true + } + ); + return Promise.all(files.map(async (file) => { + const content = await fs.readFile(file, "utf8"); + const json = JSON.parse(stripJsonComments(content)); + t.true( + tv4.validate(json, schema), + `${file}\n${JSON.stringify(tv4.error, null, 2)}` + ); + })); +}); + test("absolute path to directory glob", async (t) => { t.plan(1); const argv = [ path.resolve("./test/no-config") ];