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,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ESLint rule: pasika/type-extraction
|
|
3
|
-
*
|
|
4
|
-
* A type or schema declared in a component MUST stay in that component file
|
|
5
|
-
* until another file imports it without the component where it is defined, and
|
|
6
|
-
* a type or schema declared outside a component MUST stay in its file until
|
|
7
|
-
* another file needs it without using the code in that file. Importing the
|
|
8
|
-
* type alongside the component that defines it never requires extraction.
|
|
9
|
-
*
|
|
10
|
-
* @see docs/code-organization-guide/rules/types-and-schemas-rule.md
|
|
11
|
-
*/
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
import { getProjectIndex, symbolKey } from "../project/index.js";
|
|
14
|
-
import { describeConsumers, segmentsOf } from "../project/ccf.js";
|
|
15
|
-
export const typeExtractionRule = {
|
|
16
|
-
meta: {
|
|
17
|
-
schema: [],
|
|
18
|
-
type: "problem",
|
|
19
|
-
docs: {
|
|
20
|
-
description: "Require a type or schema imported without its defining code to be extracted.",
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
create(context) {
|
|
24
|
-
const sourceRoot = path.resolve("src");
|
|
25
|
-
const file = path.resolve(context.filename);
|
|
26
|
-
const segments = segmentsOf(file, sourceRoot);
|
|
27
|
-
if (segments.length === 0)
|
|
28
|
-
return {};
|
|
29
|
-
const index = getProjectIndex(sourceRoot);
|
|
30
|
-
if (!index)
|
|
31
|
-
return {};
|
|
32
|
-
const module = index.modules.get(file);
|
|
33
|
-
if (!module)
|
|
34
|
-
return {};
|
|
35
|
-
const componentExport = module.exports.find((exp) => exp.kind === "component");
|
|
36
|
-
// The code a consumer can use from this file besides types: hooks,
|
|
37
|
-
// schemas, constants, and functions.
|
|
38
|
-
const codeExports = module.exports.filter((exp) => exp.kind !== "type" && exp.kind !== "other");
|
|
39
|
-
const findings = [];
|
|
40
|
-
for (const exp of module.exports) {
|
|
41
|
-
if (exp.kind !== "type" && exp.kind !== "schema")
|
|
42
|
-
continue;
|
|
43
|
-
const consumers = [...(index.symbolConsumers.get(symbolKey(file, exp.name)) ?? [])];
|
|
44
|
-
if (consumers.length === 0)
|
|
45
|
-
continue;
|
|
46
|
-
if (componentExport) {
|
|
47
|
-
// A consumer that also imports the component uses the code alongside
|
|
48
|
-
// the type, so extraction is not required.
|
|
49
|
-
const componentConsumers = index.symbolConsumers.get(symbolKey(file, componentExport.name)) ?? new Set();
|
|
50
|
-
const independent = consumers.filter((consumer) => !componentConsumers.has(consumer));
|
|
51
|
-
if (independent.length === 0)
|
|
52
|
-
continue;
|
|
53
|
-
findings.push({
|
|
54
|
-
line: exp.line,
|
|
55
|
-
message: `${exp.kind} "${exp.name}" is imported by ${describeConsumers(independent, sourceRoot)} without ` +
|
|
56
|
-
`the component "${componentExport.name}" that defines it. Extract it to a types/ or schemas/ folder. ` +
|
|
57
|
-
"See docs/code-organization-guide/rules/types-and-schemas-rule.md",
|
|
58
|
-
});
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (codeExports.length === 0)
|
|
62
|
-
continue;
|
|
63
|
-
// A consumer that imports any other code from this file uses the file as
|
|
64
|
-
// a whole; one that takes only the type needs it independently.
|
|
65
|
-
const independent = consumers.filter((consumer) => !codeExports.some((other) => index.symbolConsumers.get(symbolKey(file, other.name))?.has(consumer)));
|
|
66
|
-
if (independent.length === 0)
|
|
67
|
-
continue;
|
|
68
|
-
findings.push({
|
|
69
|
-
line: exp.line,
|
|
70
|
-
message: `${exp.kind} "${exp.name}" is imported by ${describeConsumers(independent, sourceRoot)} without using ` +
|
|
71
|
-
"the code in this file. Extract it to a types/ or schemas/ folder. " +
|
|
72
|
-
"See docs/code-organization-guide/rules/types-and-schemas-rule.md",
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
if (findings.length === 0)
|
|
76
|
-
return {};
|
|
77
|
-
return {
|
|
78
|
-
Program(node) {
|
|
79
|
-
for (const finding of findings) {
|
|
80
|
-
context.report({ node, loc: { line: finding.line, column: 0 }, message: finding.message });
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
},
|
|
85
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ESLint rule: pasika/ui-state
|
|
3
|
-
*
|
|
4
|
-
* Enforces native or ARIA state expression and Tailwind state variants.
|
|
5
|
-
*
|
|
6
|
-
* @see docs/styling-guide/rules/component-ui-state-rule.md
|
|
7
|
-
*/
|
|
8
|
-
import type { Rule } from "eslint";
|
|
9
|
-
export declare const uiStateRule: Rule.RuleModule;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ESLint rule: pasika/ui-state
|
|
3
|
-
*
|
|
4
|
-
* Enforces native or ARIA state expression and Tailwind state variants.
|
|
5
|
-
*
|
|
6
|
-
* @see docs/styling-guide/rules/component-ui-state-rule.md
|
|
7
|
-
*/
|
|
8
|
-
const STATE_PROPS = new Set([
|
|
9
|
-
"disabled",
|
|
10
|
-
"loading",
|
|
11
|
-
"selected",
|
|
12
|
-
"expanded",
|
|
13
|
-
"pressed",
|
|
14
|
-
"checked",
|
|
15
|
-
"busy",
|
|
16
|
-
"invalid",
|
|
17
|
-
"open",
|
|
18
|
-
]);
|
|
19
|
-
const STATE_ATTRIBUTES = new Set([
|
|
20
|
-
"disabled",
|
|
21
|
-
"aria-busy",
|
|
22
|
-
"aria-selected",
|
|
23
|
-
"aria-expanded",
|
|
24
|
-
"aria-pressed",
|
|
25
|
-
"aria-checked",
|
|
26
|
-
"aria-invalid",
|
|
27
|
-
"open",
|
|
28
|
-
]);
|
|
29
|
-
const STATE_CLASS_RE = /^(?:disabled|aria-(?:busy|selected|expanded|pressed|checked|invalid)|data-\[state)/;
|
|
30
|
-
function isComponentElement(node) {
|
|
31
|
-
const name = node.openingElement?.name;
|
|
32
|
-
return name?.type === "JSXIdentifier" && /^[A-Z]/.test(name.name);
|
|
33
|
-
}
|
|
34
|
-
function expressionName(node) {
|
|
35
|
-
if (node?.type !== "JSXExpressionContainer")
|
|
36
|
-
return undefined;
|
|
37
|
-
if (node.expression?.type === "Identifier")
|
|
38
|
-
return node.expression.name;
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
export const uiStateRule = {
|
|
42
|
-
meta: {
|
|
43
|
-
schema: [],
|
|
44
|
-
type: "problem",
|
|
45
|
-
docs: {
|
|
46
|
-
description: "Require semantic UI states and Tailwind state variants.",
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
create(context) {
|
|
50
|
-
return {
|
|
51
|
-
JSXElement(node) {
|
|
52
|
-
if (!isComponentElement(node))
|
|
53
|
-
return;
|
|
54
|
-
const attributes = node.openingElement?.attributes ?? [];
|
|
55
|
-
const names = new Set();
|
|
56
|
-
for (const attribute of attributes) {
|
|
57
|
-
names.add(String(attribute.name?.name));
|
|
58
|
-
}
|
|
59
|
-
for (const attribute of attributes) {
|
|
60
|
-
const name = String(attribute.name?.name);
|
|
61
|
-
const stateName = expressionName(attribute.value);
|
|
62
|
-
if (!stateName || !STATE_PROPS.has(stateName))
|
|
63
|
-
continue;
|
|
64
|
-
const hasNativeState = [...STATE_ATTRIBUTES].some((nativeName) => names.has(nativeName));
|
|
65
|
-
if (!hasNativeState) {
|
|
66
|
-
context.report({
|
|
67
|
-
node: attribute,
|
|
68
|
-
message: `UI state prop "${name}" should be expressed with a native or ARIA state attribute. ` +
|
|
69
|
-
"See docs/styling-guide/rules/component-ui-state-rule.md",
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
for (const attribute of attributes) {
|
|
74
|
-
if (String(attribute.name?.name) !== "className")
|
|
75
|
-
continue;
|
|
76
|
-
const value = attribute.value;
|
|
77
|
-
const text = value?.type === "Literal" ? String(value.value) : "";
|
|
78
|
-
if (value?.type === "JSXExpressionContainer" && value.expression.type === "ConditionalExpression") {
|
|
79
|
-
const consequent = value.expression.consequent;
|
|
80
|
-
const alternate = value.expression.alternate;
|
|
81
|
-
const classes = [consequent, alternate]
|
|
82
|
-
.filter((branch) => branch.type === "Literal" && typeof branch.value === "string")
|
|
83
|
-
.flatMap((branch) => String(branch.value).split(/\s+/));
|
|
84
|
-
if (classes.length > 0 && !classes.some((className) => STATE_CLASS_RE.test(className))) {
|
|
85
|
-
context.report({
|
|
86
|
-
node: attribute,
|
|
87
|
-
message: "Use a Tailwind state variant for a UI state instead of conditional replacement classes. " +
|
|
88
|
-
"See docs/styling-guide/rules/component-ui-state-rule.md",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (text.split(/\s+/).some((className) => className.includes("state-"))) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
},
|
|
99
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { parseModule } from "../project/parse-module.js";
|
|
3
|
-
function toKebabCase(value) {
|
|
4
|
-
return value
|
|
5
|
-
.replace(/(?<lower>[a-z0-9])(?<upper>[A-Z])/g, "$<lower>-$<upper>")
|
|
6
|
-
.replace(/(?<first>[A-Z])(?<rest>[A-Z][a-z])/g, "$<first>-$<rest>")
|
|
7
|
-
.toLowerCase();
|
|
8
|
-
}
|
|
9
|
-
export const utilFileNameRule = {
|
|
10
|
-
meta: {
|
|
11
|
-
schema: [],
|
|
12
|
-
type: "problem",
|
|
13
|
-
docs: {
|
|
14
|
-
description: "Require single-function utility files to use the function's kebab-case name.",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
create(context) {
|
|
18
|
-
const filename = path.resolve(context.filename);
|
|
19
|
-
const segments = filename.replace(/\\/g, "/").split("/");
|
|
20
|
-
if (!segments.includes("utils"))
|
|
21
|
-
return {};
|
|
22
|
-
let module;
|
|
23
|
-
try {
|
|
24
|
-
module = parseModule(filename);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return {};
|
|
28
|
-
}
|
|
29
|
-
const functions = module.exports.filter((entry) => entry.kind === "function");
|
|
30
|
-
if (functions.length !== 1 || module.exports.length !== 1)
|
|
31
|
-
return {};
|
|
32
|
-
const functionName = functions[0]?.name;
|
|
33
|
-
if (!functionName)
|
|
34
|
-
return {};
|
|
35
|
-
const expected = toKebabCase(functionName);
|
|
36
|
-
const actual = path.basename(filename, path.extname(filename));
|
|
37
|
-
if (!expected || actual === expected)
|
|
38
|
-
return {};
|
|
39
|
-
return {
|
|
40
|
-
Program(node) {
|
|
41
|
-
context.report({
|
|
42
|
-
node,
|
|
43
|
-
message: `A utility file exporting ${functionName} must be named ${expected}.${path.extname(filename).slice(1)}.`,
|
|
44
|
-
});
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ESLint rule: pasika/value-extraction
|
|
3
|
-
*
|
|
4
|
-
* A value MUST remain in its declaring component or file until another file
|
|
5
|
-
* imports it independently; it MUST then be extracted as a constant. A file
|
|
6
|
-
* under src/app/ is supposed to hold only framework-convention files, so a
|
|
7
|
-
* consumer outside src/app/ reaching into one means a value has crossed the
|
|
8
|
-
* independence threshold.
|
|
9
|
-
*
|
|
10
|
-
* @see docs/code-organization-guide/rules/constants-rule.md
|
|
11
|
-
*/
|
|
12
|
-
import type { Rule } from "eslint";
|
|
13
|
-
export declare const valueExtractionRule: Rule.RuleModule;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ESLint rule: pasika/value-extraction
|
|
3
|
-
*
|
|
4
|
-
* A value MUST remain in its declaring component or file until another file
|
|
5
|
-
* imports it independently; it MUST then be extracted as a constant. A file
|
|
6
|
-
* under src/app/ is supposed to hold only framework-convention files, so a
|
|
7
|
-
* consumer outside src/app/ reaching into one means a value has crossed the
|
|
8
|
-
* independence threshold.
|
|
9
|
-
*
|
|
10
|
-
* @see docs/code-organization-guide/rules/constants-rule.md
|
|
11
|
-
*/
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
import { getProjectIndex } from "../project/index.js";
|
|
14
|
-
import { describeConsumers, segmentsOf } from "../project/ccf.js";
|
|
15
|
-
export const valueExtractionRule = {
|
|
16
|
-
meta: {
|
|
17
|
-
schema: [],
|
|
18
|
-
type: "problem",
|
|
19
|
-
docs: {
|
|
20
|
-
description: "Require a value imported independently to be extracted as a constant.",
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
create(context) {
|
|
24
|
-
const sourceRoot = path.resolve("src");
|
|
25
|
-
const file = path.resolve(context.filename);
|
|
26
|
-
const segments = segmentsOf(file, sourceRoot);
|
|
27
|
-
if (segments.length === 0 || segments[0] !== "app")
|
|
28
|
-
return {};
|
|
29
|
-
const index = getProjectIndex(sourceRoot);
|
|
30
|
-
if (!index)
|
|
31
|
-
return {};
|
|
32
|
-
const consumers = [...(index.consumers.get(file) ?? [])];
|
|
33
|
-
const outsideApp = consumers.filter((consumer) => segmentsOf(consumer, sourceRoot)[0] !== "app");
|
|
34
|
-
if (outsideApp.length === 0)
|
|
35
|
-
return {};
|
|
36
|
-
return {
|
|
37
|
-
Program(node) {
|
|
38
|
-
context.report({
|
|
39
|
-
node,
|
|
40
|
-
loc: { line: 1, column: 0 },
|
|
41
|
-
message: `This file in src/app/ is imported by ${describeConsumers(outsideApp, sourceRoot)} ` +
|
|
42
|
-
"outside src/app/. Extract the value to a shared or feature folder so it can be " +
|
|
43
|
-
"imported independently. See docs/code-organization-guide/rules/constants-rule.md",
|
|
44
|
-
});
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
};
|