pasika 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -20
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +4999 -103
- package/dist/eslint/pasika/index.d.ts +165 -53
- package/dist/eslint/pasika/index.js +4424 -89
- package/package.json +5 -6
- package/dist/cli/output.d.ts +0 -3
- package/dist/cli/output.js +0 -11
- package/dist/enforcement/coverage.d.ts +0 -51
- package/dist/enforcement/coverage.js +0 -206
- package/dist/enforcement/doctor.d.ts +0 -16
- package/dist/enforcement/doctor.js +0 -249
- package/dist/enforcement/normalize.d.ts +0 -11
- package/dist/enforcement/normalize.js +0 -21
- package/dist/enforcement/parse-docs.d.ts +0 -58
- package/dist/enforcement/parse-docs.js +0 -94
- package/dist/enforcement/types.d.ts +0 -54
- package/dist/enforcement/types.js +0 -50
- package/dist/eslint/pasika/ast-types.d.ts +0 -122
- package/dist/eslint/pasika/ast-types.js +0 -1
- package/dist/eslint/pasika/project/ccf.d.ts +0 -48
- package/dist/eslint/pasika/project/ccf.js +0 -119
- package/dist/eslint/pasika/project/index.d.ts +0 -21
- package/dist/eslint/pasika/project/index.js +0 -139
- package/dist/eslint/pasika/project/parse-module.d.ts +0 -27
- package/dist/eslint/pasika/project/parse-module.js +0 -128
- package/dist/eslint/pasika/rules/application-structure.d.ts +0 -2
- package/dist/eslint/pasika/rules/application-structure.js +0 -152
- package/dist/eslint/pasika/rules/component-conventions.d.ts +0 -16
- package/dist/eslint/pasika/rules/component-conventions.js +0 -145
- package/dist/eslint/pasika/rules/component-nesting.d.ts +0 -12
- package/dist/eslint/pasika/rules/component-nesting.js +0 -69
- package/dist/eslint/pasika/rules/component-placement.d.ts +0 -11
- package/dist/eslint/pasika/rules/component-placement.js +0 -75
- package/dist/eslint/pasika/rules/config-extraction.d.ts +0 -14
- package/dist/eslint/pasika/rules/config-extraction.js +0 -74
- package/dist/eslint/pasika/rules/cross-feature-import.d.ts +0 -2
- package/dist/eslint/pasika/rules/cross-feature-import.js +0 -75
- package/dist/eslint/pasika/rules/css/apply-usage.d.ts +0 -10
- package/dist/eslint/pasika/rules/css/apply-usage.js +0 -45
- package/dist/eslint/pasika/rules/css/base-layer-pair.d.ts +0 -10
- package/dist/eslint/pasika/rules/css/base-layer-pair.js +0 -49
- package/dist/eslint/pasika/rules/css/css-variable-naming.d.ts +0 -10
- package/dist/eslint/pasika/rules/css/css-variable-naming.js +0 -39
- package/dist/eslint/pasika/rules/css/custom-utility-apply.d.ts +0 -11
- package/dist/eslint/pasika/rules/css/custom-utility-apply.js +0 -52
- package/dist/eslint/pasika/rules/css/global-css-location.d.ts +0 -10
- package/dist/eslint/pasika/rules/css/global-css-location.js +0 -42
- package/dist/eslint/pasika/rules/css/helpers.d.ts +0 -29
- package/dist/eslint/pasika/rules/css/helpers.js +0 -93
- package/dist/eslint/pasika/rules/css/index.d.ts +0 -13
- package/dist/eslint/pasika/rules/css/index.js +0 -25
- package/dist/eslint/pasika/rules/css/root-variables.d.ts +0 -11
- package/dist/eslint/pasika/rules/css/root-variables.js +0 -53
- package/dist/eslint/pasika/rules/css/rule-tester.d.ts +0 -11
- package/dist/eslint/pasika/rules/css/rule-tester.js +0 -22
- package/dist/eslint/pasika/rules/css/stylesheet-ordering.d.ts +0 -11
- package/dist/eslint/pasika/rules/css/stylesheet-ordering.js +0 -76
- package/dist/eslint/pasika/rules/css/surface-utility.d.ts +0 -10
- package/dist/eslint/pasika/rules/css/surface-utility.js +0 -41
- package/dist/eslint/pasika/rules/css/theme-reset.d.ts +0 -9
- package/dist/eslint/pasika/rules/css/theme-reset.js +0 -36
- package/dist/eslint/pasika/rules/css/theme-variable-namespace.d.ts +0 -11
- package/dist/eslint/pasika/rules/css/theme-variable-namespace.js +0 -53
- package/dist/eslint/pasika/rules/cva-appearance-props.d.ts +0 -10
- package/dist/eslint/pasika/rules/cva-appearance-props.js +0 -77
- package/dist/eslint/pasika/rules/cva-boolean-variants.d.ts +0 -11
- package/dist/eslint/pasika/rules/cva-boolean-variants.js +0 -97
- package/dist/eslint/pasika/rules/data-testid-case.d.ts +0 -2
- package/dist/eslint/pasika/rules/data-testid-case.js +0 -76
- package/dist/eslint/pasika/rules/enforce-barrel-exports.d.ts +0 -9
- package/dist/eslint/pasika/rules/enforce-barrel-exports.js +0 -78
- package/dist/eslint/pasika/rules/enforce-cn-merge.d.ts +0 -21
- package/dist/eslint/pasika/rules/enforce-cn-merge.js +0 -86
- package/dist/eslint/pasika/rules/enforce-cva-variant-props.d.ts +0 -9
- package/dist/eslint/pasika/rules/enforce-cva-variant-props.js +0 -86
- package/dist/eslint/pasika/rules/filename-case.d.ts +0 -2
- package/dist/eslint/pasika/rules/filename-case.js +0 -123
- package/dist/eslint/pasika/rules/hook-complexity.d.ts +0 -12
- package/dist/eslint/pasika/rules/hook-complexity.js +0 -114
- package/dist/eslint/pasika/rules/hook-extraction.d.ts +0 -11
- package/dist/eslint/pasika/rules/hook-extraction.js +0 -55
- package/dist/eslint/pasika/rules/import-boundaries.d.ts +0 -2
- package/dist/eslint/pasika/rules/import-boundaries.js +0 -167
- package/dist/eslint/pasika/rules/import-through-index.d.ts +0 -2
- package/dist/eslint/pasika/rules/import-through-index.js +0 -52
- package/dist/eslint/pasika/rules/interactive-component.d.ts +0 -10
- package/dist/eslint/pasika/rules/interactive-component.js +0 -76
- package/dist/eslint/pasika/rules/json/index.d.ts +0 -5
- package/dist/eslint/pasika/rules/json/index.js +0 -9
- package/dist/eslint/pasika/rules/json/no-cache-flag.d.ts +0 -10
- package/dist/eslint/pasika/rules/json/no-cache-flag.js +0 -45
- package/dist/eslint/pasika/rules/json/no-vulyk-dependency.d.ts +0 -10
- package/dist/eslint/pasika/rules/json/no-vulyk-dependency.js +0 -41
- package/dist/eslint/pasika/rules/json/rule-tester.d.ts +0 -11
- package/dist/eslint/pasika/rules/json/rule-tester.js +0 -21
- package/dist/eslint/pasika/rules/jsx-hygiene.d.ts +0 -9
- package/dist/eslint/pasika/rules/jsx-hygiene.js +0 -108
- package/dist/eslint/pasika/rules/locale-dotted-path.d.ts +0 -10
- package/dist/eslint/pasika/rules/locale-dotted-path.js +0 -65
- package/dist/eslint/pasika/rules/locale-placement.d.ts +0 -13
- package/dist/eslint/pasika/rules/locale-placement.js +0 -163
- package/dist/eslint/pasika/rules/locales-location.d.ts +0 -11
- package/dist/eslint/pasika/rules/locales-location.js +0 -56
- package/dist/eslint/pasika/rules/md/doc-kind-suffix.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/doc-kind-suffix.js +0 -29
- package/dist/eslint/pasika/rules/md/example-heading-description.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/example-heading-description.js +0 -30
- package/dist/eslint/pasika/rules/md/glossary-term-linking.d.ts +0 -2
- package/dist/eslint/pasika/rules/md/glossary-term-linking.js +0 -99
- package/dist/eslint/pasika/rules/md/guide-folder-entry-point.d.ts +0 -2
- package/dist/eslint/pasika/rules/md/guide-folder-entry-point.js +0 -46
- package/dist/eslint/pasika/rules/md/guide-link-anchors.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/guide-link-anchors.js +0 -50
- package/dist/eslint/pasika/rules/md/guide-overview-no-links.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/guide-overview-no-links.js +0 -51
- package/dist/eslint/pasika/rules/md/guide-states-no-requirement.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/guide-states-no-requirement.js +0 -26
- package/dist/eslint/pasika/rules/md/guide-step-single-link.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/guide-step-single-link.js +0 -48
- package/dist/eslint/pasika/rules/md/guide-step-single-sentence.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/guide-step-single-sentence.js +0 -42
- package/dist/eslint/pasika/rules/md/helpers.d.ts +0 -25
- package/dist/eslint/pasika/rules/md/helpers.js +0 -37
- package/dist/eslint/pasika/rules/md/index.d.ts +0 -27
- package/dist/eslint/pasika/rules/md/index.js +0 -53
- package/dist/eslint/pasika/rules/md/no-cross-document-link.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/no-cross-document-link.js +0 -36
- package/dist/eslint/pasika/rules/md/no-nested-how-to.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/no-nested-how-to.js +0 -39
- package/dist/eslint/pasika/rules/md/no-template-prompt.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/no-template-prompt.js +0 -22
- package/dist/eslint/pasika/rules/md/overview-length.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/overview-length.js +0 -47
- package/dist/eslint/pasika/rules/md/overview-present.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/overview-present.js +0 -41
- package/dist/eslint/pasika/rules/md/policy-no-examples.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/policy-no-examples.js +0 -28
- package/dist/eslint/pasika/rules/md/policy-single-document.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/policy-single-document.js +0 -34
- package/dist/eslint/pasika/rules/md/policy-subject-headings.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/policy-subject-headings.js +0 -58
- package/dist/eslint/pasika/rules/md/project-index.d.ts +0 -17
- package/dist/eslint/pasika/rules/md/project-index.js +0 -67
- package/dist/eslint/pasika/rules/md/reference-block-headings.d.ts +0 -6
- package/dist/eslint/pasika/rules/md/reference-block-headings.js +0 -31
- package/dist/eslint/pasika/rules/md/reference-no-rfc-vocabulary.d.ts +0 -6
- package/dist/eslint/pasika/rules/md/reference-no-rfc-vocabulary.js +0 -26
- package/dist/eslint/pasika/rules/md/requirement-present.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/requirement-present.js +0 -41
- package/dist/eslint/pasika/rules/md/rfc-only-in-bullets.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/rfc-only-in-bullets.js +0 -46
- package/dist/eslint/pasika/rules/md/rule-paired-examples.d.ts +0 -5
- package/dist/eslint/pasika/rules/md/rule-paired-examples.js +0 -36
- package/dist/eslint/pasika/rules/md/rule-tester.d.ts +0 -11
- package/dist/eslint/pasika/rules/md/rule-tester.js +0 -21
- package/dist/eslint/pasika/rules/md/support-document-placement.d.ts +0 -2
- package/dist/eslint/pasika/rules/md/support-document-placement.js +0 -36
- package/dist/eslint/pasika/rules/md/title-matches-file-name.d.ts +0 -2
- package/dist/eslint/pasika/rules/md/title-matches-file-name.js +0 -46
- package/dist/eslint/pasika/rules/named-exports.d.ts +0 -2
- package/dist/eslint/pasika/rules/named-exports.js +0 -49
- package/dist/eslint/pasika/rules/no-arbitrary-tailwind.d.ts +0 -9
- package/dist/eslint/pasika/rules/no-arbitrary-tailwind.js +0 -97
- package/dist/eslint/pasika/rules/no-eslint-disable.d.ts +0 -10
- package/dist/eslint/pasika/rules/no-eslint-disable.js +0 -33
- package/dist/eslint/pasika/rules/no-mixed-concerns.d.ts +0 -9
- package/dist/eslint/pasika/rules/no-mixed-concerns.js +0 -71
- package/dist/eslint/pasika/rules/no-util-barrel.d.ts +0 -2
- package/dist/eslint/pasika/rules/no-util-barrel.js +0 -48
- package/dist/eslint/pasika/rules/pure-function-extract.d.ts +0 -9
- package/dist/eslint/pasika/rules/pure-function-extract.js +0 -92
- package/dist/eslint/pasika/rules/shared-style-dedup.d.ts +0 -13
- package/dist/eslint/pasika/rules/shared-style-dedup.js +0 -91
- package/dist/eslint/pasika/rules/stay-flat.d.ts +0 -12
- package/dist/eslint/pasika/rules/stay-flat.js +0 -81
- package/dist/eslint/pasika/rules/support-file-placement.d.ts +0 -15
- package/dist/eslint/pasika/rules/support-file-placement.js +0 -70
- package/dist/eslint/pasika/rules/support-folder-shape.d.ts +0 -2
- package/dist/eslint/pasika/rules/support-folder-shape.js +0 -59
- package/dist/eslint/pasika/rules/type-extraction.d.ts +0 -13
- package/dist/eslint/pasika/rules/type-extraction.js +0 -85
- package/dist/eslint/pasika/rules/ui-state.d.ts +0 -9
- package/dist/eslint/pasika/rules/ui-state.js +0 -99
- package/dist/eslint/pasika/rules/util-file-name.d.ts +0 -2
- package/dist/eslint/pasika/rules/util-file-name.js +0 -48
- package/dist/eslint/pasika/rules/value-extraction.d.ts +0 -13
- package/dist/eslint/pasika/rules/value-extraction.js +0 -48
- package/enforcement/registry.json +0 -1145
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { getFilename } from "./helpers.js";
|
|
2
|
-
/** Count document links in a subtree. */
|
|
3
|
-
function countDocLinks(node) {
|
|
4
|
-
if (node.type === "link" && node.url.endsWith(".md"))
|
|
5
|
-
return 1;
|
|
6
|
-
if ("children" in node) {
|
|
7
|
-
return node.children.reduce((sum, child) => sum + countDocLinks(child), 0);
|
|
8
|
-
}
|
|
9
|
-
return 0;
|
|
10
|
-
}
|
|
11
|
-
/** Visit every ordered-list item and run a check. */
|
|
12
|
-
function visitSteps(node, check) {
|
|
13
|
-
if (node.type === "list" && node.ordered) {
|
|
14
|
-
for (const child of node.children)
|
|
15
|
-
check(child);
|
|
16
|
-
}
|
|
17
|
-
if ("children" in node) {
|
|
18
|
-
for (const child of node.children)
|
|
19
|
-
visitSteps(child, check);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
export const guideStepSingleLinkRule = {
|
|
23
|
-
meta: {
|
|
24
|
-
type: "problem",
|
|
25
|
-
docs: {
|
|
26
|
-
description: "Each guide step must link at most one document total.",
|
|
27
|
-
recommended: true,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
create(context) {
|
|
31
|
-
return {
|
|
32
|
-
root(node) {
|
|
33
|
-
const filename = getFilename(context);
|
|
34
|
-
if (!filename.endsWith("-guide.md"))
|
|
35
|
-
return;
|
|
36
|
-
visitSteps(node, (item) => {
|
|
37
|
-
const links = countDocLinks(item);
|
|
38
|
-
if (links > 1) {
|
|
39
|
-
context.report({
|
|
40
|
-
node: item,
|
|
41
|
-
message: `step links ${String(links)} documents`,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { getFilename, getTextContent } from "./helpers.js";
|
|
2
|
-
function countSentences(text) {
|
|
3
|
-
return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
|
|
4
|
-
}
|
|
5
|
-
export const guideStepSingleSentenceRule = {
|
|
6
|
-
meta: {
|
|
7
|
-
type: "problem",
|
|
8
|
-
docs: {
|
|
9
|
-
description: "Each guide step must be concise and use one sentence.",
|
|
10
|
-
recommended: true,
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
create(context) {
|
|
14
|
-
// Walked list context, tracked via enter/exit so listItem can see its
|
|
15
|
-
// enclosing list without relying on a second visitor argument.
|
|
16
|
-
const listsOnPath = [];
|
|
17
|
-
return {
|
|
18
|
-
list(node) {
|
|
19
|
-
listsOnPath.push(node);
|
|
20
|
-
},
|
|
21
|
-
"list:exit"() {
|
|
22
|
-
listsOnPath.pop();
|
|
23
|
-
},
|
|
24
|
-
listItem(node) {
|
|
25
|
-
const filename = getFilename(context);
|
|
26
|
-
if (!filename.endsWith("-guide.md"))
|
|
27
|
-
return;
|
|
28
|
-
// Steps are ordered list items.
|
|
29
|
-
if (!listsOnPath.at(-1)?.ordered)
|
|
30
|
-
return;
|
|
31
|
-
const text = getTextContent(node).trim();
|
|
32
|
-
const sentenceCount = countSentences(text);
|
|
33
|
-
if (sentenceCount > 1) {
|
|
34
|
-
context.report({
|
|
35
|
-
node,
|
|
36
|
-
message: `step uses ${String(sentenceCount)} sentences`,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helpers for markdown ESLint rules operating on @eslint/markdown's AST.
|
|
3
|
-
*/
|
|
4
|
-
import type { Nodes } from "mdast";
|
|
5
|
-
/**
|
|
6
|
-
* Check if text contains RFC 2119 vocabulary.
|
|
7
|
-
* Returns the first keyword found, or null.
|
|
8
|
-
*/
|
|
9
|
-
export declare function containsRfcKeyword(text: string): string | null;
|
|
10
|
-
/**
|
|
11
|
-
* Get the file path being linted.
|
|
12
|
-
*
|
|
13
|
-
* Accepts the rule context structurally so any language plugin can pass it.
|
|
14
|
-
*/
|
|
15
|
-
export declare function getFilename(context: {
|
|
16
|
-
filename: string;
|
|
17
|
-
}): string;
|
|
18
|
-
/**
|
|
19
|
-
* Get the text content of an mdast node.
|
|
20
|
-
*/
|
|
21
|
-
export declare function getTextContent(node: Nodes): string;
|
|
22
|
-
/**
|
|
23
|
-
* Get the line number from a node's position.
|
|
24
|
-
*/
|
|
25
|
-
export declare function getLine(node: Nodes): number;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RFC 2119 keywords matched by word-boundary regex, longest first.
|
|
3
|
-
*/
|
|
4
|
-
const RFC_PATTERN = /\b(?<keyword>MUST NOT|MUST|SHALL NOT|SHALL|SHOULD NOT|SHOULD|MAY|RECOMMENDED|NOT RECOMMENDED|OPTIONAL|REQUIRED)\b/;
|
|
5
|
-
/**
|
|
6
|
-
* Check if text contains RFC 2119 vocabulary.
|
|
7
|
-
* Returns the first keyword found, or null.
|
|
8
|
-
*/
|
|
9
|
-
export function containsRfcKeyword(text) {
|
|
10
|
-
const match = RFC_PATTERN.exec(text);
|
|
11
|
-
return match?.groups?.keyword ?? null;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Get the file path being linted.
|
|
15
|
-
*
|
|
16
|
-
* Accepts the rule context structurally so any language plugin can pass it.
|
|
17
|
-
*/
|
|
18
|
-
export function getFilename(context) {
|
|
19
|
-
return context.filename;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Get the text content of an mdast node.
|
|
23
|
-
*/
|
|
24
|
-
export function getTextContent(node) {
|
|
25
|
-
if ("value" in node && typeof node.value === "string")
|
|
26
|
-
return node.value;
|
|
27
|
-
if ("children" in node) {
|
|
28
|
-
return node.children.map(getTextContent).join("");
|
|
29
|
-
}
|
|
30
|
-
return "";
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Get the line number from a node's position.
|
|
34
|
-
*/
|
|
35
|
-
export function getLine(node) {
|
|
36
|
-
return node.position?.start.line ?? 0;
|
|
37
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export declare const mdRules: {
|
|
2
|
-
"doc-kind-suffix": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
3
|
-
"title-matches-file-name": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
4
|
-
"overview-present": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
5
|
-
"overview-length": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
6
|
-
"guide-overview-no-links": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
7
|
-
"guide-step-single-sentence": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
8
|
-
"guide-step-single-link": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
9
|
-
"guide-states-no-requirement": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
10
|
-
"requirement-present": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
11
|
-
"rule-paired-examples": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
12
|
-
"example-heading-description": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
13
|
-
"policy-no-examples": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
14
|
-
"policy-single-document": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
15
|
-
"no-cross-document-link": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
16
|
-
"reference-no-rfc-vocabulary": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
17
|
-
"reference-block-headings": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
18
|
-
"support-document-placement": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
19
|
-
"no-template-prompt": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
20
|
-
"guide-folder-entry-point": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
21
|
-
"rfc-only-in-bullets": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
22
|
-
"policy-subject-headings": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
23
|
-
"guide-link-anchors": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
24
|
-
"no-nested-how-to": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
25
|
-
"glossary-term-linking": import("@eslint/markdown").MarkdownRuleDefinition;
|
|
26
|
-
};
|
|
27
|
-
export type MdRuleName = keyof typeof mdRules;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview All markdown ESLint rules for documentation checks.
|
|
3
|
-
*/
|
|
4
|
-
import { docKindSuffixRule } from "./doc-kind-suffix.js";
|
|
5
|
-
import { titleMatchesFileNameRule } from "./title-matches-file-name.js";
|
|
6
|
-
import { overviewPresentRule } from "./overview-present.js";
|
|
7
|
-
import { overviewLengthRule } from "./overview-length.js";
|
|
8
|
-
import { guideOverviewNoLinksRule } from "./guide-overview-no-links.js";
|
|
9
|
-
import { guideStepSingleSentenceRule } from "./guide-step-single-sentence.js";
|
|
10
|
-
import { guideStepSingleLinkRule } from "./guide-step-single-link.js";
|
|
11
|
-
import { guideStatesNoRequirementRule } from "./guide-states-no-requirement.js";
|
|
12
|
-
import { requirementPresentRule } from "./requirement-present.js";
|
|
13
|
-
import { rulePairedExamplesRule } from "./rule-paired-examples.js";
|
|
14
|
-
import { exampleHeadingDescriptionRule } from "./example-heading-description.js";
|
|
15
|
-
import { policyNoExamplesRule } from "./policy-no-examples.js";
|
|
16
|
-
import { policySingleDocumentRule } from "./policy-single-document.js";
|
|
17
|
-
import { noCrossDocumentLinkRule } from "./no-cross-document-link.js";
|
|
18
|
-
import { referenceNoRfcVocabularyRule } from "./reference-no-rfc-vocabulary.js";
|
|
19
|
-
import { referenceBlockHeadingsRule } from "./reference-block-headings.js";
|
|
20
|
-
import { supportDocumentPlacementRule } from "./support-document-placement.js";
|
|
21
|
-
import { noTemplatePromptRule } from "./no-template-prompt.js";
|
|
22
|
-
import { guideFolderEntryPointRule } from "./guide-folder-entry-point.js";
|
|
23
|
-
import { rfcOnlyInBulletsRule } from "./rfc-only-in-bullets.js";
|
|
24
|
-
import { policySubjectHeadingsRule } from "./policy-subject-headings.js";
|
|
25
|
-
import { guideLinkAnchorsRule } from "./guide-link-anchors.js";
|
|
26
|
-
import { noNestedHowToRule } from "./no-nested-how-to.js";
|
|
27
|
-
import { glossaryTermLinkingRule } from "./glossary-term-linking.js";
|
|
28
|
-
export const mdRules = {
|
|
29
|
-
"doc-kind-suffix": docKindSuffixRule,
|
|
30
|
-
"title-matches-file-name": titleMatchesFileNameRule,
|
|
31
|
-
"overview-present": overviewPresentRule,
|
|
32
|
-
"overview-length": overviewLengthRule,
|
|
33
|
-
"guide-overview-no-links": guideOverviewNoLinksRule,
|
|
34
|
-
"guide-step-single-sentence": guideStepSingleSentenceRule,
|
|
35
|
-
"guide-step-single-link": guideStepSingleLinkRule,
|
|
36
|
-
"guide-states-no-requirement": guideStatesNoRequirementRule,
|
|
37
|
-
"requirement-present": requirementPresentRule,
|
|
38
|
-
"rule-paired-examples": rulePairedExamplesRule,
|
|
39
|
-
"example-heading-description": exampleHeadingDescriptionRule,
|
|
40
|
-
"policy-no-examples": policyNoExamplesRule,
|
|
41
|
-
"policy-single-document": policySingleDocumentRule,
|
|
42
|
-
"no-cross-document-link": noCrossDocumentLinkRule,
|
|
43
|
-
"reference-no-rfc-vocabulary": referenceNoRfcVocabularyRule,
|
|
44
|
-
"reference-block-headings": referenceBlockHeadingsRule,
|
|
45
|
-
"support-document-placement": supportDocumentPlacementRule,
|
|
46
|
-
"no-template-prompt": noTemplatePromptRule,
|
|
47
|
-
"guide-folder-entry-point": guideFolderEntryPointRule,
|
|
48
|
-
"rfc-only-in-bullets": rfcOnlyInBulletsRule,
|
|
49
|
-
"policy-subject-headings": policySubjectHeadingsRule,
|
|
50
|
-
"guide-link-anchors": guideLinkAnchorsRule,
|
|
51
|
-
"no-nested-how-to": noNestedHowToRule,
|
|
52
|
-
"glossary-term-linking": glossaryTermLinkingRule,
|
|
53
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { getFilename } from "./helpers.js";
|
|
2
|
-
/** The document kind for a filename, when the no-link rule applies to it. */
|
|
3
|
-
function linkedKind(filename) {
|
|
4
|
-
if (filename.endsWith("-rule.md"))
|
|
5
|
-
return "rule";
|
|
6
|
-
if (filename.endsWith("-reference.md"))
|
|
7
|
-
return "reference";
|
|
8
|
-
if (filename.endsWith("-policy.md"))
|
|
9
|
-
return "policy";
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
export const noCrossDocumentLinkRule = {
|
|
13
|
-
meta: {
|
|
14
|
-
type: "problem",
|
|
15
|
-
docs: {
|
|
16
|
-
description: "Rules, references, and policy must not link to other documents.",
|
|
17
|
-
recommended: true,
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
create(context) {
|
|
21
|
-
return {
|
|
22
|
-
link(node) {
|
|
23
|
-
const filename = getFilename(context);
|
|
24
|
-
const kind = linkedKind(filename);
|
|
25
|
-
if (!kind)
|
|
26
|
-
return;
|
|
27
|
-
if (node.url.endsWith(".md")) {
|
|
28
|
-
context.report({
|
|
29
|
-
node,
|
|
30
|
-
message: `${kind} links another document: ${node.url}`,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { getFilename, getLine, getTextContent } from "./helpers.js";
|
|
2
|
-
export const noNestedHowToRule = {
|
|
3
|
-
meta: {
|
|
4
|
-
type: "problem",
|
|
5
|
-
docs: {
|
|
6
|
-
description: "How To sections must not nest inside other How To sections.",
|
|
7
|
-
recommended: true,
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
create(context) {
|
|
11
|
-
return {
|
|
12
|
-
root(node) {
|
|
13
|
-
const filename = getFilename(context);
|
|
14
|
-
if (!filename.endsWith("-guide.md"))
|
|
15
|
-
return;
|
|
16
|
-
const howToHeadings = [];
|
|
17
|
-
for (const child of node.children) {
|
|
18
|
-
if (child.type !== "heading")
|
|
19
|
-
continue;
|
|
20
|
-
const text = getTextContent(child).trim();
|
|
21
|
-
if (!/^How To\b/.test(text))
|
|
22
|
-
continue;
|
|
23
|
-
howToHeadings.push({ line: getLine(child), depth: child.depth, text });
|
|
24
|
-
}
|
|
25
|
-
// A How To heading at greater depth than the previous How To heading nests inside it.
|
|
26
|
-
for (let i = 1; i < howToHeadings.length; i++) {
|
|
27
|
-
const prev = howToHeadings[i - 1];
|
|
28
|
-
const current = howToHeadings[i];
|
|
29
|
-
if (prev && current && current.depth > prev.depth) {
|
|
30
|
-
context.report({
|
|
31
|
-
node,
|
|
32
|
-
message: `How To section "${current.text}" nests inside another How To section`,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
},
|
|
39
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
const TEMPLATE_PROMPT = /^\s*\[[A-Z0-9].*\]\s*$/;
|
|
2
|
-
export const noTemplatePromptRule = {
|
|
3
|
-
meta: {
|
|
4
|
-
type: "problem",
|
|
5
|
-
docs: {
|
|
6
|
-
description: "No leftover bracketed template prompts.",
|
|
7
|
-
recommended: true,
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
create(context) {
|
|
11
|
-
return {
|
|
12
|
-
text(node) {
|
|
13
|
-
if (TEMPLATE_PROMPT.test(node.value)) {
|
|
14
|
-
context.report({
|
|
15
|
-
node,
|
|
16
|
-
message: "leftover bracketed template prompt",
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { getFilename, getLine, getTextContent } from "./helpers.js";
|
|
2
|
-
function countSentences(text) {
|
|
3
|
-
return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
|
|
4
|
-
}
|
|
5
|
-
export const overviewLengthRule = {
|
|
6
|
-
meta: {
|
|
7
|
-
type: "problem",
|
|
8
|
-
docs: {
|
|
9
|
-
description: "Overview must contain at most two sentences.",
|
|
10
|
-
recommended: true,
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
create(context) {
|
|
14
|
-
return {
|
|
15
|
-
root(node) {
|
|
16
|
-
const filename = getFilename(context);
|
|
17
|
-
if (!filename.endsWith(".md"))
|
|
18
|
-
return;
|
|
19
|
-
let titleLine = 0;
|
|
20
|
-
for (const child of node.children) {
|
|
21
|
-
if (child.type === "heading" && child.depth === 1) {
|
|
22
|
-
titleLine = getLine(child);
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (!titleLine)
|
|
27
|
-
return;
|
|
28
|
-
// Check only the first content paragraph after the title (the overview).
|
|
29
|
-
for (const child of node.children) {
|
|
30
|
-
if (child.type !== "paragraph" || getLine(child) <= titleLine)
|
|
31
|
-
continue;
|
|
32
|
-
const text = getTextContent(child).trim();
|
|
33
|
-
if (!text || text.startsWith("#"))
|
|
34
|
-
continue;
|
|
35
|
-
const sentenceCount = countSentences(text);
|
|
36
|
-
if (sentenceCount > 2) {
|
|
37
|
-
context.report({
|
|
38
|
-
node: child,
|
|
39
|
-
message: `overview uses ${String(sentenceCount)} sentences, at most two are allowed`,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
},
|
|
47
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { getFilename, getLine, getTextContent } from "./helpers.js";
|
|
2
|
-
export const overviewPresentRule = {
|
|
3
|
-
meta: {
|
|
4
|
-
type: "problem",
|
|
5
|
-
docs: {
|
|
6
|
-
description: "Overview must follow the title in a documentation file.",
|
|
7
|
-
recommended: true,
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
create(context) {
|
|
11
|
-
return {
|
|
12
|
-
root(node) {
|
|
13
|
-
const filename = getFilename(context);
|
|
14
|
-
if (!filename.endsWith(".md"))
|
|
15
|
-
return;
|
|
16
|
-
let titleLine = 0;
|
|
17
|
-
for (const child of node.children) {
|
|
18
|
-
if (child.type === "heading" && child.depth === 1) {
|
|
19
|
-
titleLine = getLine(child);
|
|
20
|
-
break;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (!titleLine)
|
|
24
|
-
return;
|
|
25
|
-
let hasOverview = false;
|
|
26
|
-
for (const child of node.children) {
|
|
27
|
-
if (child.type === "paragraph" && getLine(child) > titleLine && getTextContent(child).trim()) {
|
|
28
|
-
hasOverview = true;
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (!hasOverview) {
|
|
33
|
-
context.report({
|
|
34
|
-
node,
|
|
35
|
-
message: "no overview follows the title",
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { getFilename, getTextContent } from "./helpers.js";
|
|
2
|
-
export const policyNoExamplesRule = {
|
|
3
|
-
meta: {
|
|
4
|
-
type: "problem",
|
|
5
|
-
docs: {
|
|
6
|
-
description: "Policy document must not contain Incorrect/Correct examples.",
|
|
7
|
-
recommended: true,
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
create(context) {
|
|
11
|
-
return {
|
|
12
|
-
heading(node) {
|
|
13
|
-
const filename = getFilename(context);
|
|
14
|
-
if (!filename.endsWith("-policy.md"))
|
|
15
|
-
return;
|
|
16
|
-
if (node.depth !== 2)
|
|
17
|
-
return;
|
|
18
|
-
const text = getTextContent(node).trim();
|
|
19
|
-
if (/^(?:Incorrect|Correct)\b/.test(text)) {
|
|
20
|
-
context.report({
|
|
21
|
-
node,
|
|
22
|
-
message: `policy document contains an example: ${text}`,
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
},
|
|
28
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { getFilename } from "./helpers.js";
|
|
2
|
-
import { findDocsRoot, getProjectDocs } from "./project-index.js";
|
|
3
|
-
export const policySingleDocumentRule = {
|
|
4
|
-
meta: {
|
|
5
|
-
type: "problem",
|
|
6
|
-
docs: {
|
|
7
|
-
description: "A repository must not have more than one Policy document.",
|
|
8
|
-
recommended: true,
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
|
-
create(context) {
|
|
12
|
-
return {
|
|
13
|
-
root(node) {
|
|
14
|
-
const filename = getFilename(context);
|
|
15
|
-
if (!filename.endsWith("-policy.md"))
|
|
16
|
-
return;
|
|
17
|
-
const docsRoot = findDocsRoot(filename);
|
|
18
|
-
if (!docsRoot)
|
|
19
|
-
return;
|
|
20
|
-
const docs = getProjectDocs(docsRoot);
|
|
21
|
-
const policyDocs = docs.filter((d) => d.kind === "policy");
|
|
22
|
-
if (policyDocs.length > 1) {
|
|
23
|
-
// Only report on the first policy doc, so the issue is reported once.
|
|
24
|
-
if (policyDocs[0]?.filePath === filename) {
|
|
25
|
-
context.report({
|
|
26
|
-
node,
|
|
27
|
-
message: `${String(policyDocs.length)} policy documents exist`,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { getFilename, getLine } from "./helpers.js";
|
|
2
|
-
export const policySubjectHeadingsRule = {
|
|
3
|
-
meta: {
|
|
4
|
-
type: "problem",
|
|
5
|
-
docs: {
|
|
6
|
-
description: "Policy document must group its bullets under a heading per subject.",
|
|
7
|
-
recommended: true,
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
create(context) {
|
|
11
|
-
return {
|
|
12
|
-
root(node) {
|
|
13
|
-
const filename = getFilename(context);
|
|
14
|
-
if (!filename.endsWith("-policy.md"))
|
|
15
|
-
return;
|
|
16
|
-
// Collect headings and list items with their line numbers, in document order.
|
|
17
|
-
let titleLine = 0;
|
|
18
|
-
let firstSubjectLine = 0;
|
|
19
|
-
let overviewLine = 0;
|
|
20
|
-
let foundTitle = false;
|
|
21
|
-
let foundOverview = false;
|
|
22
|
-
for (const child of node.children) {
|
|
23
|
-
const line = getLine(child);
|
|
24
|
-
if (!foundTitle && child.type === "heading" && child.depth === 1) {
|
|
25
|
-
titleLine = line;
|
|
26
|
-
foundTitle = true;
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (!foundTitle)
|
|
30
|
-
continue;
|
|
31
|
-
if (!foundOverview && child.type === "paragraph" && line > titleLine) {
|
|
32
|
-
overviewLine = line;
|
|
33
|
-
foundOverview = true;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (!firstSubjectLine && child.type === "heading" && child.depth === 2 && line > titleLine) {
|
|
37
|
-
firstSubjectLine = line;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (!titleLine || !firstSubjectLine)
|
|
41
|
-
return;
|
|
42
|
-
// Any bullet before the first subject heading (and after the overview) is ungrouped.
|
|
43
|
-
const hasUngroupedBullet = node.children.some((child) => {
|
|
44
|
-
if (child.type !== "list")
|
|
45
|
-
return false;
|
|
46
|
-
const line = getLine(child);
|
|
47
|
-
return line > overviewLine && line < firstSubjectLine;
|
|
48
|
-
});
|
|
49
|
-
if (hasUngroupedBullet) {
|
|
50
|
-
context.report({
|
|
51
|
-
node,
|
|
52
|
-
message: "policy bullet appears before the first subject heading",
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
},
|
|
58
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export interface DocMeta {
|
|
2
|
-
/** Absolute path on disk. */
|
|
3
|
-
filePath: string;
|
|
4
|
-
/** Path relative to docs root. */
|
|
5
|
-
doc: string;
|
|
6
|
-
fileName: string;
|
|
7
|
-
kind?: "guide" | "rule" | "reference" | "policy";
|
|
8
|
-
title: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Get all documents in the docs folder. Results are cached per docsRoot.
|
|
12
|
-
*/
|
|
13
|
-
export declare function getProjectDocs(docsRoot: string): DocMeta[];
|
|
14
|
-
/**
|
|
15
|
-
* Try to find the docsRoot from a file path by walking up to find the docs/ directory.
|
|
16
|
-
*/
|
|
17
|
-
export declare function findDocsRoot(filePath: string): string | undefined;
|