@master/eslint-plugin-css 2.0.0-rc.8 → 2.0.0-rc.80
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/LICENSE +21 -0
- package/README.md +228 -7
- package/dist/configs/base.d.ts +6 -0
- package/dist/configs/base.js +5 -0
- package/dist/configs/legacy.d.ts +6 -0
- package/dist/configs/legacy.js +9 -0
- package/dist/configs/recommended.d.ts +6 -14
- package/dist/configs/recommended.js +13 -1
- package/dist/configs/stylesheet.d.ts +6 -0
- package/dist/configs/stylesheet.js +11 -0
- package/dist/create-rule.d.ts +12 -0
- package/dist/create-rule.js +5 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.js +19 -1
- package/dist/plugin.d.ts +6 -3
- package/dist/plugin.js +26 -1
- package/dist/rules/no-conflicting-classes.d.ts +6 -0
- package/dist/rules/no-conflicting-classes.js +37 -0
- package/dist/rules/no-invalid-classes.d.ts +6 -0
- package/dist/rules/no-invalid-classes.js +42 -0
- package/dist/rules/no-unapproved-raw-values.d.ts +10 -0
- package/dist/rules/no-unapproved-raw-values.js +59 -0
- package/dist/rules/prefer-canonical-classes.d.ts +8 -0
- package/dist/rules/prefer-canonical-classes.js +95 -0
- package/dist/rules/sort-classes.d.ts +6 -0
- package/dist/rules/sort-classes.js +44 -0
- package/dist/settings-schema.d.ts +7 -0
- package/dist/settings-schema.js +27 -0
- package/dist/settings.d.ts +17 -5
- package/dist/settings.js +8 -1
- package/dist/stylesheet-parser.d.ts +31 -0
- package/dist/stylesheet-parser.js +33 -0
- package/dist/utils/define-source-visitors.d.ts +21 -0
- package/dist/utils/define-source-visitors.js +52 -0
- package/dist/utils/define-visitors.d.ts +15 -5
- package/dist/utils/define-visitors.js +107 -1
- package/dist/utils/is-same-or-child-path.d.ts +4 -0
- package/dist/utils/is-same-or-child-path.js +8 -0
- package/dist/utils/master-css.d.ts +7 -0
- package/dist/utils/master-css.js +6 -0
- package/dist/utils/report-lint-diagnostics.d.ts +20 -0
- package/dist/utils/report-lint-diagnostics.js +46 -0
- package/dist/utils/resolve-class-node.d.ts +24 -0
- package/dist/utils/resolve-class-node.js +85 -0
- package/dist/utils/resolve-compose-directive-class-nodes.d.ts +11 -0
- package/dist/utils/resolve-compose-directive-class-nodes.js +157 -0
- package/dist/utils/resolve-context.d.ts +16 -3
- package/dist/utils/resolve-context.js +69 -1
- package/dist/utils/with-visit-class-node.d.ts +8 -0
- package/dist/utils/with-visit-class-node.js +51 -0
- package/package.json +78 -1
- package/dist/configs/config.d.ts +0 -13
- package/dist/configs/config.js +0 -1
- package/dist/configs/config.mjs +0 -1
- package/dist/configs/flat.d.ts +0 -16
- package/dist/configs/flat.js +0 -1
- package/dist/configs/flat.mjs +0 -1
- package/dist/configs/recommended.mjs +0 -1
- package/dist/index.mjs +0 -1
- package/dist/plugin.mjs +0 -1
- package/dist/rules/class-collision.d.ts +0 -3
- package/dist/rules/class-collision.js +0 -1
- package/dist/rules/class-collision.mjs +0 -1
- package/dist/rules/class-order.d.ts +0 -3
- package/dist/rules/class-order.js +0 -1
- package/dist/rules/class-order.mjs +0 -1
- package/dist/rules/class-validation.d.ts +0 -3
- package/dist/rules/class-validation.js +0 -1
- package/dist/rules/class-validation.mjs +0 -1
- package/dist/settings.mjs +0 -1
- package/dist/utils/are-declarations-equal.d.ts +0 -1
- package/dist/utils/are-declarations-equal.js +0 -1
- package/dist/utils/are-declarations-equal.mjs +0 -1
- package/dist/utils/define-visitors.mjs +0 -1
- package/dist/utils/extract-classnames-from-value.d.ts +0 -6
- package/dist/utils/extract-classnames-from-value.js +0 -1
- package/dist/utils/extract-classnames-from-value.mjs +0 -1
- package/dist/utils/extract-range-from-node.d.ts +0 -1
- package/dist/utils/extract-range-from-node.js +0 -1
- package/dist/utils/extract-range-from-node.mjs +0 -1
- package/dist/utils/extract-value-from-node.d.ts +0 -1
- package/dist/utils/extract-value-from-node.js +0 -1
- package/dist/utils/extract-value-from-node.mjs +0 -1
- package/dist/utils/find-loc.d.ts +0 -7
- package/dist/utils/find-loc.js +0 -1
- package/dist/utils/find-loc.mjs +0 -1
- package/dist/utils/get-mastercss.d.ts +0 -2
- package/dist/utils/get-mastercss.js +0 -1
- package/dist/utils/get-mastercss.mjs +0 -1
- package/dist/utils/get-template-element-body.d.ts +0 -1
- package/dist/utils/get-template-element-body.js +0 -1
- package/dist/utils/get-template-element-body.mjs +0 -1
- package/dist/utils/get-template-element-prefix.d.ts +0 -1
- package/dist/utils/get-template-element-prefix.js +0 -1
- package/dist/utils/get-template-element-prefix.mjs +0 -1
- package/dist/utils/get-template-element-suffix.d.ts +0 -1
- package/dist/utils/get-template-element-suffix.js +0 -1
- package/dist/utils/get-template-element-suffix.mjs +0 -1
- package/dist/utils/parse-node-recursive.d.ts +0 -13
- package/dist/utils/parse-node-recursive.js +0 -1
- package/dist/utils/parse-node-recursive.mjs +0 -1
- package/dist/utils/reorder-valid-classes-action.d.ts +0 -3
- package/dist/utils/reorder-valid-classes-action.js +0 -1
- package/dist/utils/reorder-valid-classes-action.mjs +0 -1
- package/dist/utils/resolve-context.mjs +0 -1
- package/dist/utils/valid-rules-action.d.ts +0 -3
- package/dist/utils/valid-rules-action.js +0 -1
- package/dist/utils/valid-rules-action.mjs +0 -1
- package/dist/utils/validate-action.d.ts +0 -3
- package/dist/utils/validate-action.js +0 -1
- package/dist/utils/validate-action.mjs +0 -1
- package/dist/utils/workers/reorder-valid-classes.d.ts +0 -2
- package/dist/utils/workers/reorder-valid-classes.js +0 -1
- package/dist/utils/workers/reorder-valid-classes.mjs +0 -1
- package/dist/utils/workers/valid-rules.d.ts +0 -2
- package/dist/utils/workers/valid-rules.js +0 -1
- package/dist/utils/workers/valid-rules.mjs +0 -1
- package/dist/utils/workers/validate.d.ts +0 -5
- package/dist/utils/workers/validate.js +0 -1
- package/dist/utils/workers/validate.mjs +0 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import create_rule_default from "../create-rule.js";
|
|
2
|
+
import defineVisitors from "../utils/define-visitors.js";
|
|
3
|
+
import resolveContext from "../utils/resolve-context.js";
|
|
4
|
+
import reportLintDiagnostics from "../utils/report-lint-diagnostics.js";
|
|
5
|
+
import defineSourceVisitors, { shouldUseSourceVisitors } from "../utils/define-source-visitors.js";
|
|
6
|
+
import resolveComposeDirectiveClassNodes from "../utils/resolve-compose-directive-class-nodes.js";
|
|
7
|
+
import { createCanonicalClassesReport, createCanonicalComposeDirectiveReport, defaultCanonicalClassNameOptions } from "@master/css-lint";
|
|
8
|
+
//#region src/rules/prefer-canonical-classes.ts
|
|
9
|
+
var prefer_canonical_classes_default = create_rule_default({
|
|
10
|
+
name: "prefer-canonical-classes",
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: { description: "Prefer canonical Master CSS classes" },
|
|
14
|
+
messages: { preferClass: "Prefer \"{{recommended}}\" over \"{{actual}}\"." },
|
|
15
|
+
fixable: "code",
|
|
16
|
+
schema: [{
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
preferStaticUtilities: { type: "boolean" },
|
|
20
|
+
preferThemeTokens: { type: "boolean" },
|
|
21
|
+
preferPropertyAliases: { type: "boolean" },
|
|
22
|
+
preferVariableReferences: { type: "boolean" },
|
|
23
|
+
preferMultiValueTokens: { type: "boolean" },
|
|
24
|
+
preferCompositionUtilities: { type: "boolean" },
|
|
25
|
+
preferConditionOrder: { type: "boolean" },
|
|
26
|
+
preferNativeDeclarationsInCompose: { type: "boolean" },
|
|
27
|
+
preferVariantBlocksInCompose: { type: "boolean" }
|
|
28
|
+
},
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
}]
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [defaultCanonicalClassNameOptions],
|
|
33
|
+
create(context) {
|
|
34
|
+
const { settings, css } = resolveContext(context);
|
|
35
|
+
const options = {
|
|
36
|
+
...defaultCanonicalClassNameOptions,
|
|
37
|
+
...context.options[0] || {}
|
|
38
|
+
};
|
|
39
|
+
if (shouldUseSourceVisitors(context)) return defineSourceVisitors({
|
|
40
|
+
context,
|
|
41
|
+
css,
|
|
42
|
+
ruleId: "prefer-canonical-classes",
|
|
43
|
+
ruleOptions: options
|
|
44
|
+
});
|
|
45
|
+
const reportCanonicalClassList = (node, { raw, start, end, unescape, classNodes, classValues }) => {
|
|
46
|
+
reportLintDiagnostics(context, node, {
|
|
47
|
+
raw,
|
|
48
|
+
start,
|
|
49
|
+
end,
|
|
50
|
+
unescape,
|
|
51
|
+
classNodes,
|
|
52
|
+
classValues,
|
|
53
|
+
nodes: [],
|
|
54
|
+
value: raw
|
|
55
|
+
}, createCanonicalClassesReport(raw, css, {
|
|
56
|
+
...options,
|
|
57
|
+
unescape
|
|
58
|
+
}).diagnostics);
|
|
59
|
+
};
|
|
60
|
+
const reportCanonicalComposeDirective = (node, classNode) => {
|
|
61
|
+
reportLintDiagnostics(context, node, classNode, createCanonicalComposeDirectiveReport(classNode.raw, css, options).diagnostics, { getFix(_, fix) {
|
|
62
|
+
if (fix.scope !== "directive") return {
|
|
63
|
+
range: [classNode.start + fix.range.start, classNode.start + fix.range.end],
|
|
64
|
+
text: fix.text
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
range: [classNode.directiveStart, classNode.directiveEnd],
|
|
68
|
+
text: formatComposeDirectiveReplacement(context.sourceCode.getText(), classNode.directiveStart, fix.text)
|
|
69
|
+
};
|
|
70
|
+
} });
|
|
71
|
+
};
|
|
72
|
+
const visitors = defineVisitors({
|
|
73
|
+
context,
|
|
74
|
+
settings
|
|
75
|
+
}, reportCanonicalClassList);
|
|
76
|
+
const visitProgram = visitors.Program;
|
|
77
|
+
return {
|
|
78
|
+
...visitors,
|
|
79
|
+
Program(node) {
|
|
80
|
+
if (typeof visitProgram === "function") visitProgram(node);
|
|
81
|
+
for (const classNode of resolveComposeDirectiveClassNodes(context)) reportCanonicalComposeDirective(node, classNode);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
function getLinePrefix(source, index) {
|
|
87
|
+
return source.slice(source.lastIndexOf("\n", index - 1) + 1, index);
|
|
88
|
+
}
|
|
89
|
+
function formatComposeDirectiveReplacement(source, index, replacement) {
|
|
90
|
+
const linePrefix = getLinePrefix(source, index);
|
|
91
|
+
if (/\S/.test(linePrefix)) return replacement.replace(/\n\s*/g, " ");
|
|
92
|
+
return replacement.replace(/\n/g, `\n${linePrefix}`);
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { prefer_canonical_classes_default as default };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/rules/sort-classes.d.ts
|
|
2
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidClassOrder", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
//#endregion
|
|
6
|
+
export { _default as default };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import create_rule_default from "../create-rule.js";
|
|
2
|
+
import defineVisitors from "../utils/define-visitors.js";
|
|
3
|
+
import resolveContext from "../utils/resolve-context.js";
|
|
4
|
+
import reportLintDiagnostics from "../utils/report-lint-diagnostics.js";
|
|
5
|
+
import defineSourceVisitors, { shouldUseSourceVisitors } from "../utils/define-source-visitors.js";
|
|
6
|
+
import { createSortClassesReport } from "@master/css-lint";
|
|
7
|
+
//#region src/rules/sort-classes.ts
|
|
8
|
+
var sort_classes_default = create_rule_default({
|
|
9
|
+
name: "sort-classes",
|
|
10
|
+
meta: {
|
|
11
|
+
type: "layout",
|
|
12
|
+
fixable: "code",
|
|
13
|
+
docs: { description: "Sort Master CSS classes" },
|
|
14
|
+
messages: { invalidClassOrder: "No consistent class order followed." },
|
|
15
|
+
schema: []
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create: function(context) {
|
|
19
|
+
const { settings, css } = resolveContext(context);
|
|
20
|
+
if (shouldUseSourceVisitors(context)) return defineSourceVisitors({
|
|
21
|
+
context,
|
|
22
|
+
css,
|
|
23
|
+
ruleId: "sort-classes"
|
|
24
|
+
});
|
|
25
|
+
return defineVisitors({
|
|
26
|
+
context,
|
|
27
|
+
settings
|
|
28
|
+
}, (node, { raw, start, end, nodes, unescape }) => {
|
|
29
|
+
if (nodes.length <= 1) return;
|
|
30
|
+
reportLintDiagnostics(context, node, {
|
|
31
|
+
raw,
|
|
32
|
+
start,
|
|
33
|
+
end,
|
|
34
|
+
nodes,
|
|
35
|
+
unescape,
|
|
36
|
+
value: raw,
|
|
37
|
+
classNodes: [],
|
|
38
|
+
classValues: []
|
|
39
|
+
}, createSortClassesReport(raw, css, { unescape }).diagnostics);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
//#endregion
|
|
44
|
+
export { sort_classes_default as default };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { JSONSchema4 } from "@typescript-eslint/utils/json-schema";
|
|
2
|
+
|
|
3
|
+
//#region src/settings-schema.d.ts
|
|
4
|
+
declare const masterCSSSettingsSchema: JSONSchema4;
|
|
5
|
+
declare const noInvalidClassesOptionsSchema: JSONSchema4;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { masterCSSSettingsSchema as default, masterCSSSettingsSchema, noInvalidClassesOptionsSchema };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/settings-schema.ts
|
|
2
|
+
const sourceMatcherSchema = {
|
|
3
|
+
type: "array",
|
|
4
|
+
items: {
|
|
5
|
+
type: "string",
|
|
6
|
+
minLength: 1
|
|
7
|
+
},
|
|
8
|
+
uniqueItems: true
|
|
9
|
+
};
|
|
10
|
+
const masterCSSSettingsSchema = {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
classAttributes: sourceMatcherSchema,
|
|
14
|
+
classFunctions: sourceMatcherSchema,
|
|
15
|
+
classDeclarations: sourceMatcherSchema,
|
|
16
|
+
ignoredKeys: sourceMatcherSchema,
|
|
17
|
+
manifest: { type: "object" }
|
|
18
|
+
},
|
|
19
|
+
additionalProperties: false
|
|
20
|
+
};
|
|
21
|
+
const noInvalidClassesOptionsSchema = {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: { disallowUnknownClass: { type: "boolean" } },
|
|
24
|
+
additionalProperties: false
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { masterCSSSettingsSchema as default, masterCSSSettingsSchema, noInvalidClassesOptionsSchema };
|
package/dist/settings.d.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
import { MasterCSSManifest } from "./utils/master-css.js";
|
|
2
|
+
|
|
3
|
+
//#region src/settings.d.ts
|
|
1
4
|
declare const settings: {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
manifest: any;
|
|
6
|
+
classAttributes: string[];
|
|
7
|
+
classFunctions: string[];
|
|
8
|
+
classDeclarations: string[];
|
|
9
|
+
ignoredKeys: string[];
|
|
6
10
|
};
|
|
7
|
-
|
|
11
|
+
interface Settings {
|
|
12
|
+
classAttributes?: string[];
|
|
13
|
+
classFunctions?: string[];
|
|
14
|
+
classDeclarations?: string[];
|
|
15
|
+
ignoredKeys: string[];
|
|
16
|
+
manifest?: MasterCSSManifest;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { Settings, settings as default };
|
package/dist/settings.js
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { defaultClassLintSettings } from "@master/css-lint";
|
|
2
|
+
//#region src/settings.ts
|
|
3
|
+
const settings = {
|
|
4
|
+
...defaultClassLintSettings,
|
|
5
|
+
manifest: void 0
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
export { settings as default };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/stylesheet-parser.d.ts
|
|
2
|
+
declare const _default: {
|
|
3
|
+
meta: {
|
|
4
|
+
name: string;
|
|
5
|
+
};
|
|
6
|
+
parseForESLint(source: string): {
|
|
7
|
+
ast: {
|
|
8
|
+
type: string;
|
|
9
|
+
body: any[];
|
|
10
|
+
comments: any[];
|
|
11
|
+
tokens: any[];
|
|
12
|
+
sourceType: string;
|
|
13
|
+
range: number[];
|
|
14
|
+
loc: {
|
|
15
|
+
start: {
|
|
16
|
+
line: number;
|
|
17
|
+
column: number;
|
|
18
|
+
};
|
|
19
|
+
end: {
|
|
20
|
+
line: number;
|
|
21
|
+
column: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
visitorKeys: {
|
|
26
|
+
Program: any[];
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { _default as default };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/stylesheet-parser.ts
|
|
2
|
+
function getLocFromIndex(source, index) {
|
|
3
|
+
const lines = source.slice(0, index).split(/\r\n|[\n\r]/);
|
|
4
|
+
return {
|
|
5
|
+
line: lines.length,
|
|
6
|
+
column: lines[lines.length - 1].length
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
var stylesheet_parser_default = {
|
|
10
|
+
meta: { name: "@master/eslint-plugin-css/stylesheet-parser" },
|
|
11
|
+
parseForESLint(source) {
|
|
12
|
+
return {
|
|
13
|
+
ast: {
|
|
14
|
+
type: "Program",
|
|
15
|
+
body: [],
|
|
16
|
+
comments: [],
|
|
17
|
+
tokens: [],
|
|
18
|
+
sourceType: "module",
|
|
19
|
+
range: [0, source.length],
|
|
20
|
+
loc: {
|
|
21
|
+
start: {
|
|
22
|
+
line: 1,
|
|
23
|
+
column: 0
|
|
24
|
+
},
|
|
25
|
+
end: getLocFromIndex(source, source.length)
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
visitorKeys: { Program: [] }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { stylesheet_parser_default as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MasterCSSLintContentRuleOptions, MasterCSSLintRuleId } from "@master/css-lint";
|
|
2
|
+
import { MasterCSS } from "@master/css-engine";
|
|
3
|
+
import { RuleContext, RuleListener } from "@typescript-eslint/utils/ts-eslint";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/define-source-visitors.d.ts
|
|
6
|
+
type SourceRuleOptions = MasterCSSLintContentRuleOptions[keyof MasterCSSLintContentRuleOptions];
|
|
7
|
+
interface DefineSourceVisitorsOptions {
|
|
8
|
+
context: RuleContext<any, any[]>;
|
|
9
|
+
css: MasterCSS;
|
|
10
|
+
ruleId: MasterCSSLintRuleId;
|
|
11
|
+
ruleOptions?: SourceRuleOptions;
|
|
12
|
+
}
|
|
13
|
+
declare function shouldUseSourceVisitors(context: RuleContext<any, any[]>): boolean;
|
|
14
|
+
declare function defineSourceVisitors({
|
|
15
|
+
context,
|
|
16
|
+
css,
|
|
17
|
+
ruleId,
|
|
18
|
+
ruleOptions
|
|
19
|
+
}: DefineSourceVisitorsOptions): RuleListener;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { defineSourceVisitors as default, shouldUseSourceVisitors };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { messageIdByCode, stringifyLintDiagnosticData } from "./report-lint-diagnostics.js";
|
|
2
|
+
import { lintMasterCSSContent, masterCSSLintRuleIds } from "@master/css-lint";
|
|
3
|
+
//#region src/utils/define-source-visitors.ts
|
|
4
|
+
const SOURCE_LINT_FILE_RE = /\.mdx$/i;
|
|
5
|
+
function shouldUseSourceVisitors(context) {
|
|
6
|
+
const filename = context.physicalFilename || context.filename;
|
|
7
|
+
return typeof filename === "string" && SOURCE_LINT_FILE_RE.test(filename);
|
|
8
|
+
}
|
|
9
|
+
function getFilename(context) {
|
|
10
|
+
return context.physicalFilename || context.filename || "source.mdx";
|
|
11
|
+
}
|
|
12
|
+
function createSingleRuleSet(ruleId) {
|
|
13
|
+
return Object.fromEntries(masterCSSLintRuleIds.map((eachRuleId) => [eachRuleId, eachRuleId === ruleId]));
|
|
14
|
+
}
|
|
15
|
+
function createRuleOptions(ruleId, ruleOptions) {
|
|
16
|
+
return ruleOptions ? { [ruleId]: ruleOptions } : void 0;
|
|
17
|
+
}
|
|
18
|
+
function reportSourceDiagnostic(context, node, diagnostic) {
|
|
19
|
+
const { sourceCode } = context;
|
|
20
|
+
const messageId = messageIdByCode[diagnostic.code];
|
|
21
|
+
const fix = diagnostic.fixes?.[0];
|
|
22
|
+
const descriptor = {
|
|
23
|
+
node,
|
|
24
|
+
loc: {
|
|
25
|
+
start: sourceCode.getLocFromIndex(diagnostic.range.start),
|
|
26
|
+
end: sourceCode.getLocFromIndex(diagnostic.range.end)
|
|
27
|
+
},
|
|
28
|
+
...messageId ? {
|
|
29
|
+
messageId,
|
|
30
|
+
data: stringifyLintDiagnosticData(diagnostic.data || { message: diagnostic.message })
|
|
31
|
+
} : { message: diagnostic.message }
|
|
32
|
+
};
|
|
33
|
+
if (fix) descriptor.fix = (fixer) => fixer.replaceTextRange([fix.range.start, fix.range.end], fix.text);
|
|
34
|
+
context.report(descriptor);
|
|
35
|
+
}
|
|
36
|
+
function defineSourceVisitors({ context, css, ruleId, ruleOptions }) {
|
|
37
|
+
return { Program(node) {
|
|
38
|
+
const result = lintMasterCSSContent({
|
|
39
|
+
content: context.sourceCode.getText(),
|
|
40
|
+
filePath: getFilename(context),
|
|
41
|
+
css,
|
|
42
|
+
rules: createSingleRuleSet(ruleId),
|
|
43
|
+
ruleOptions: createRuleOptions(ruleId, ruleOptions)
|
|
44
|
+
});
|
|
45
|
+
for (const diagnostic of result.diagnostics) {
|
|
46
|
+
if (diagnostic.ruleId !== ruleId) continue;
|
|
47
|
+
reportSourceDiagnostic(context, node, diagnostic);
|
|
48
|
+
}
|
|
49
|
+
} };
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { defineSourceVisitors as default, shouldUseSourceVisitors };
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { TSESTree } from "@typescript-eslint/utils";
|
|
2
|
+
import { Settings } from "../settings.js";
|
|
3
|
+
import { RuleContext, RuleListener } from "@typescript-eslint/utils/ts-eslint";
|
|
4
|
+
import resolveClassNode from "./resolve-class-node.js";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/define-visitors.d.ts
|
|
7
|
+
declare function defineVisitors({
|
|
8
|
+
context,
|
|
9
|
+
settings
|
|
10
|
+
}: {
|
|
11
|
+
context: RuleContext<any, any[]>;
|
|
12
|
+
settings: Settings;
|
|
13
|
+
}, visitNode: (node: TSESTree.Node, resolved: ReturnType<typeof resolveClassNode>) => void): RuleListener;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { defineVisitors as default };
|
|
@@ -1 +1,107 @@
|
|
|
1
|
-
|
|
1
|
+
import withVisitClassNode from "./with-visit-class-node.js";
|
|
2
|
+
//#region src/utils/define-visitors.ts
|
|
3
|
+
function defineVisitors({ context, settings }, visitNode) {
|
|
4
|
+
const classAttributeRegex = new RegExp(`^(?:${settings.classAttributes.join("|")})$`);
|
|
5
|
+
const classFunctionsRegex = new RegExp(`^(?:${settings.classFunctions.join("|")})$`);
|
|
6
|
+
const classDeclarationsRegex = new RegExp(`^(?:${settings.classDeclarations.join("|")})$`);
|
|
7
|
+
const visitClassNode = withVisitClassNode(visitNode, context);
|
|
8
|
+
const getStaticName = (node) => {
|
|
9
|
+
if (!node) return;
|
|
10
|
+
if (node.type === "Identifier") return node.name;
|
|
11
|
+
if (node.type === "Literal" && typeof node.value === "string") return node.value;
|
|
12
|
+
};
|
|
13
|
+
const getMemberExpressionName = (node) => {
|
|
14
|
+
if (!node || node.type !== "MemberExpression") return;
|
|
15
|
+
const objectName = getStaticName(node.object);
|
|
16
|
+
const propertyName = getStaticName(node.property);
|
|
17
|
+
if (!objectName || !propertyName) return;
|
|
18
|
+
return `${objectName}.${propertyName}`;
|
|
19
|
+
};
|
|
20
|
+
const getCalleeName = (node) => {
|
|
21
|
+
const calleeNode = node.callee || node.tag;
|
|
22
|
+
return getStaticName(calleeNode) || getMemberExpressionName(calleeNode);
|
|
23
|
+
};
|
|
24
|
+
const allowCalleeNode = (node) => {
|
|
25
|
+
const calleeName = getCalleeName(node);
|
|
26
|
+
return calleeName ? classFunctionsRegex.test(calleeName) : false;
|
|
27
|
+
};
|
|
28
|
+
const getPropertyName = (prop) => getStaticName(prop.key);
|
|
29
|
+
const visitUtilityDefinitions = (node) => {
|
|
30
|
+
if (!node) return;
|
|
31
|
+
if (node.type === "ArrayExpression") {
|
|
32
|
+
node.elements.forEach((element) => {
|
|
33
|
+
if (!element || element.type === "ObjectExpression") return;
|
|
34
|
+
visitClassNode(element);
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (node.type !== "ObjectExpression") {
|
|
39
|
+
visitClassNode(node);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const visitClassDeclarationNode = (name, node) => {
|
|
44
|
+
if (name !== "utilities") {
|
|
45
|
+
visitClassNode(node);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
visitUtilityDefinitions(node);
|
|
49
|
+
};
|
|
50
|
+
const CallExpression = function(node) {
|
|
51
|
+
if (!allowCalleeNode(node)) return;
|
|
52
|
+
node.arguments.forEach((node) => {
|
|
53
|
+
visitClassNode(node);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const scriptVisitor = {
|
|
57
|
+
CallExpression,
|
|
58
|
+
JSXAttribute: function(node) {
|
|
59
|
+
if (!node.name || !classAttributeRegex.test(node.name.name)) return;
|
|
60
|
+
if (node.value) visitClassNode(node.value);
|
|
61
|
+
},
|
|
62
|
+
SvelteAttribute: function(node) {
|
|
63
|
+
if (!node.key?.name || !classAttributeRegex.test(node.key.name)) return;
|
|
64
|
+
for (const eachValue of node.value) visitClassNode(eachValue);
|
|
65
|
+
},
|
|
66
|
+
TextAttribute: function(node) {
|
|
67
|
+
if (!node.name || !classAttributeRegex.test(node.name)) return;
|
|
68
|
+
visitClassNode(node);
|
|
69
|
+
},
|
|
70
|
+
TaggedTemplateExpression: function(node) {
|
|
71
|
+
if (allowCalleeNode(node)) {
|
|
72
|
+
visitClassNode(node.quasi);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
VariableDeclaration: function(node) {
|
|
77
|
+
node.declarations.forEach((decl) => {
|
|
78
|
+
if (decl.id.type === "Identifier" && classDeclarationsRegex.test(decl.id.name)) visitClassDeclarationNode(decl.id.name, decl.init);
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
ObjectExpression: function(node) {
|
|
82
|
+
node.properties.forEach((prop) => {
|
|
83
|
+
if (prop.type === "Property") {
|
|
84
|
+
const propName = getPropertyName(prop);
|
|
85
|
+
if (typeof propName === "string" && classDeclarationsRegex.test(propName)) visitClassDeclarationNode(propName, prop.value);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const templateBodyVisitor = {
|
|
91
|
+
CallExpression,
|
|
92
|
+
VAttribute: function(node) {
|
|
93
|
+
const name = node.key?.argument?.name || node.key?.name;
|
|
94
|
+
if (!name || !classAttributeRegex.test(name)) return;
|
|
95
|
+
if (node.value && node.value.type === "VLiteral") visitClassNode(node.value);
|
|
96
|
+
else if (node.value) {
|
|
97
|
+
if (node.value.type === "VExpressionContainer") {
|
|
98
|
+
if (node.value.expression?.type === "ArrayExpression" || node.value.expression?.type === "ObjectExpression") visitClassNode(node.value.expression);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
if (context.sourceCode.parserServices == null || context.sourceCode.parserServices.defineTemplateBodyVisitor == null) return scriptVisitor;
|
|
104
|
+
else return context.sourceCode.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { defineVisitors as default };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
//#region src/utils/is-same-or-child-path.ts
|
|
3
|
+
function isSameOrChildPath(parentPath, childPath) {
|
|
4
|
+
const relativePath = path.relative(parentPath, childPath);
|
|
5
|
+
return relativePath === "" || !!relativePath && relativePath !== ".." && !relativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(relativePath);
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { isSameOrChildPath as default };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCSSWithNativeDeclarations } from "@master/css-validator";
|
|
2
|
+
import { MasterCSS, MasterCSSManifest } from "@master/css";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/master-css.d.ts
|
|
5
|
+
declare const defaultManifest: MasterCSSManifest;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { type MasterCSS, type MasterCSSManifest, createCSSWithNativeDeclarations, defaultManifest };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { createCSSWithNativeDeclarations } from "@master/css-validator";
|
|
3
|
+
//#region src/utils/master-css.ts
|
|
4
|
+
const defaultManifest = createRequire(import.meta.url)("@master/css-preset/default-manifest.json");
|
|
5
|
+
//#endregion
|
|
6
|
+
export { createCSSWithNativeDeclarations, defaultManifest };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TSESTree } from "@typescript-eslint/utils";
|
|
2
|
+
import { MasterCSSLintDiagnostic, MasterCSSLintFix } from "@master/css-lint";
|
|
3
|
+
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
|
|
4
|
+
import { ResolvedClassNode } from "./resolve-class-node.js";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/report-lint-diagnostics.d.ts
|
|
7
|
+
type FixRange = [number, number];
|
|
8
|
+
interface ReportLintDiagnosticsOptions {
|
|
9
|
+
getFix?: (diagnostic: MasterCSSLintDiagnostic, fix: MasterCSSLintFix) => {
|
|
10
|
+
range: FixRange;
|
|
11
|
+
text: string;
|
|
12
|
+
} | undefined;
|
|
13
|
+
}
|
|
14
|
+
declare const messageIdByCode: Record<string, string>;
|
|
15
|
+
declare function stringifyLintDiagnosticData(data?: MasterCSSLintDiagnostic['data']): {
|
|
16
|
+
[k: string]: string;
|
|
17
|
+
};
|
|
18
|
+
declare function reportLintDiagnostics(context: RuleContext<any, any[]>, node: TSESTree.Node, resolved: ResolvedClassNode, diagnostics: MasterCSSLintDiagnostic[], options?: ReportLintDiagnosticsOptions): void;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { reportLintDiagnostics as default, messageIdByCode, stringifyLintDiagnosticData };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/utils/report-lint-diagnostics.ts
|
|
2
|
+
const messageIdByCode = {
|
|
3
|
+
"invalid-class-order": "invalidClassOrder",
|
|
4
|
+
"invalid-class": "invalidClass",
|
|
5
|
+
"unknown-class": "disallowUnknownClass",
|
|
6
|
+
"conflicting-class": "collisionClass",
|
|
7
|
+
"partially-conflicting-class": "partialCollisionClass",
|
|
8
|
+
"prefer-canonical-class": "preferClass",
|
|
9
|
+
"prefer-native-declaration": "preferClass",
|
|
10
|
+
"prefer-variant-block": "preferClass",
|
|
11
|
+
"unapproved-raw-value": "unapprovedRawValue"
|
|
12
|
+
};
|
|
13
|
+
function stringifyLintDiagnosticData(data = {}) {
|
|
14
|
+
return Object.fromEntries(Object.entries(data).filter(([, value]) => value !== void 0).map(([key, value]) => [key, Array.isArray(value) ? value.join(", ") : String(value)]));
|
|
15
|
+
}
|
|
16
|
+
function defaultFix(resolved, fix) {
|
|
17
|
+
if (fix.scope === "directive") return;
|
|
18
|
+
return {
|
|
19
|
+
range: [resolved.start + fix.range.start, resolved.start + fix.range.end],
|
|
20
|
+
text: fix.text
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function reportLintDiagnostics(context, node, resolved, diagnostics, options = {}) {
|
|
24
|
+
const { sourceCode } = context;
|
|
25
|
+
for (const diagnostic of diagnostics) {
|
|
26
|
+
const start = resolved.start + diagnostic.range.start;
|
|
27
|
+
const end = resolved.start + diagnostic.range.end;
|
|
28
|
+
const messageId = messageIdByCode[diagnostic.code];
|
|
29
|
+
const fix = diagnostic.fix ? options.getFix?.(diagnostic, diagnostic.fix) || defaultFix(resolved, diagnostic.fix) : void 0;
|
|
30
|
+
const descriptor = {
|
|
31
|
+
node,
|
|
32
|
+
loc: {
|
|
33
|
+
start: sourceCode.getLocFromIndex(start),
|
|
34
|
+
end: sourceCode.getLocFromIndex(end)
|
|
35
|
+
},
|
|
36
|
+
...messageId ? {
|
|
37
|
+
messageId,
|
|
38
|
+
data: stringifyLintDiagnosticData(diagnostic.data || { message: diagnostic.message })
|
|
39
|
+
} : { message: diagnostic.message }
|
|
40
|
+
};
|
|
41
|
+
if (fix) descriptor.fix = (fixer) => fixer.replaceTextRange(fix.range, fix.text);
|
|
42
|
+
context.report(descriptor);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { reportLintDiagnostics as default, messageIdByCode, stringifyLintDiagnosticData };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/resolve-class-node.d.ts
|
|
4
|
+
type ResolvedClassListUnescape = string | false;
|
|
5
|
+
interface ResolvedClassListNode {
|
|
6
|
+
type: 'class' | 'space';
|
|
7
|
+
value: string;
|
|
8
|
+
raw: string;
|
|
9
|
+
range: [number, number];
|
|
10
|
+
loc: any;
|
|
11
|
+
}
|
|
12
|
+
interface ResolvedClassNode {
|
|
13
|
+
nodes: ResolvedClassListNode[];
|
|
14
|
+
start: number;
|
|
15
|
+
end: number;
|
|
16
|
+
raw: string;
|
|
17
|
+
value: string;
|
|
18
|
+
unescape: ResolvedClassListUnescape;
|
|
19
|
+
classNodes: ResolvedClassListNode[];
|
|
20
|
+
classValues: string[];
|
|
21
|
+
}
|
|
22
|
+
declare function resolveClassNode(node: any, context: RuleContext<any, any[]>): ResolvedClassNode | undefined;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { ResolvedClassListNode, ResolvedClassListUnescape, ResolvedClassNode, resolveClassNode as default };
|