@bamboocss/eslint-plugin 1.41.1 → 1.43.0
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/dist/index.cjs +45 -6
- package/dist/index.mjs +45 -6
- package/dist/utils/worker.cjs +16 -0
- package/dist/utils/worker.d.cts +2 -0
- package/dist/utils/worker.d.mts +2 -0
- package/dist/utils/worker.mjs +16 -0
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,7 @@ require("@typescript-eslint/utils/ts-eslint");
|
|
|
8
8
|
let _bamboocss_shared = require("@bamboocss/shared");
|
|
9
9
|
//#region package.json
|
|
10
10
|
var name = "@bamboocss/eslint-plugin";
|
|
11
|
-
var version = "1.
|
|
11
|
+
var version = "1.43.0";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/utils/index.ts
|
|
14
14
|
const createRule = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/gajus/bamboocss/blob/main/packages/eslint-plugin/docs/rules/${name}.md`);
|
|
@@ -252,6 +252,22 @@ const getInvalidTokens = (value, context) => {
|
|
|
252
252
|
invalidTokensCache.set(value, invalidTokens);
|
|
253
253
|
return invalidTokens;
|
|
254
254
|
};
|
|
255
|
+
const unresolvedValueCache = /* @__PURE__ */ new Map();
|
|
256
|
+
/**
|
|
257
|
+
* What the build would say about this property and value, or nothing if it is fine.
|
|
258
|
+
*
|
|
259
|
+
* Asked of the resolver rather than reimplemented, so the squiggle and the build agree by
|
|
260
|
+
* construction. `getInvalidTokens` above answers a narrower question — is this dotted path a
|
|
261
|
+
* token — and cannot see `color: 'mutedd'` or tell `top: 'navH'` from `animationName: 'fadeIn'`,
|
|
262
|
+
* because neither is decidable without the property and its CSS grammar.
|
|
263
|
+
*/
|
|
264
|
+
const getUnresolvedValueMessage = (property, value, context) => {
|
|
265
|
+
const id = `${property}:${value}`;
|
|
266
|
+
if (unresolvedValueCache.has(id)) return unresolvedValueCache.get(id);
|
|
267
|
+
const message = syncAction("explainUnresolvedValue", getSyncOptions(context), property, value);
|
|
268
|
+
unresolvedValueCache.set(id, message);
|
|
269
|
+
return message;
|
|
270
|
+
};
|
|
255
271
|
const deprecatedTokensCache = /* @__PURE__ */ new Map();
|
|
256
272
|
const getDeprecatedTokens = (property, value, context) => {
|
|
257
273
|
const propertyCategory = syncAction("getPropCategory", getSyncOptions(context), property);
|
|
@@ -1058,25 +1074,45 @@ const rule$12 = createRule({
|
|
|
1058
1074
|
node
|
|
1059
1075
|
});
|
|
1060
1076
|
};
|
|
1061
|
-
|
|
1077
|
+
/**
|
|
1078
|
+
* With the property in hand, ask the resolver the whole question.
|
|
1079
|
+
*
|
|
1080
|
+
* `getInvalidTokens` can only answer "is this dotted path a token", because that is all a
|
|
1081
|
+
* value tells you on its own. The property is what makes `color: 'mutedd'` decidable at all,
|
|
1082
|
+
* and what separates `top: 'navH'` from `animationName: 'fadeIn'` — one is a typo and the
|
|
1083
|
+
* other is a `<custom-ident>` the grammar asks for.
|
|
1084
|
+
*/
|
|
1085
|
+
const reportUnresolved = (node, property, value) => {
|
|
1086
|
+
if (!value) return;
|
|
1087
|
+
const message = getUnresolvedValueMessage(property, value, context);
|
|
1088
|
+
if (message) context.report({
|
|
1089
|
+
data: { message },
|
|
1090
|
+
messageId: "unresolvedValue",
|
|
1091
|
+
node
|
|
1092
|
+
});
|
|
1093
|
+
};
|
|
1094
|
+
const handleValue = (node, property) => {
|
|
1062
1095
|
if (!node) return;
|
|
1063
1096
|
if (isLiteral(node)) {
|
|
1064
1097
|
const value = node.value?.toString();
|
|
1065
1098
|
sendReport(node, value);
|
|
1099
|
+
if (property) reportUnresolved(node, property, value);
|
|
1066
1100
|
} else if (isTemplateLiteral(node) && node.expressions.length === 0) {
|
|
1067
1101
|
const value = node.quasis[0].value.raw;
|
|
1068
1102
|
sendReport(node.quasis[0], value);
|
|
1103
|
+
if (property) reportUnresolved(node.quasis[0], property, value);
|
|
1069
1104
|
}
|
|
1070
1105
|
};
|
|
1071
1106
|
return {
|
|
1072
1107
|
JSXAttribute(node) {
|
|
1073
1108
|
if (!node.value || !isBambooProp(node, context)) return;
|
|
1074
|
-
|
|
1075
|
-
|
|
1109
|
+
const property = isJSXIdentifier(node.name) ? node.name.name : void 0;
|
|
1110
|
+
if (isLiteral(node.value)) handleValue(node.value, property);
|
|
1111
|
+
else if (isJSXExpressionContainer(node.value)) handleValue(node.value.expression, property);
|
|
1076
1112
|
},
|
|
1077
1113
|
Property(node) {
|
|
1078
1114
|
if (!isIdentifier(node.key) || !(0, _typescript_eslint_utils_ast_utils.isNodeOfTypes)([_typescript_eslint_utils.AST_NODE_TYPES.Literal, _typescript_eslint_utils.AST_NODE_TYPES.TemplateLiteral])(node.value) || !isBambooAttribute(node, context) || isRecipeVariant(node, context)) return;
|
|
1079
|
-
|
|
1115
|
+
handleValue(node.value, node.key.name);
|
|
1080
1116
|
},
|
|
1081
1117
|
TaggedTemplateExpression(node) {
|
|
1082
1118
|
if (!getTaggedTemplateCaller(node)) return;
|
|
@@ -1114,7 +1150,10 @@ const rule$12 = createRule({
|
|
|
1114
1150
|
defaultOptions: [],
|
|
1115
1151
|
meta: {
|
|
1116
1152
|
docs: { description: "Disallow the use of invalid token paths within token function syntax." },
|
|
1117
|
-
messages: {
|
|
1153
|
+
messages: {
|
|
1154
|
+
noInvalidTokenPaths: "`{{token}}` is an invalid token path.",
|
|
1155
|
+
unresolvedValue: "{{message}}"
|
|
1156
|
+
},
|
|
1118
1157
|
schema: [],
|
|
1119
1158
|
type: "problem"
|
|
1120
1159
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import "@typescript-eslint/utils/ts-eslint";
|
|
|
8
8
|
import { getArbitraryValue, parseFallbackValue } from "@bamboocss/shared";
|
|
9
9
|
//#region package.json
|
|
10
10
|
var name = "@bamboocss/eslint-plugin";
|
|
11
|
-
var version = "1.
|
|
11
|
+
var version = "1.43.0";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/utils/index.ts
|
|
14
14
|
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/gajus/bamboocss/blob/main/packages/eslint-plugin/docs/rules/${name}.md`);
|
|
@@ -252,6 +252,22 @@ const getInvalidTokens = (value, context) => {
|
|
|
252
252
|
invalidTokensCache.set(value, invalidTokens);
|
|
253
253
|
return invalidTokens;
|
|
254
254
|
};
|
|
255
|
+
const unresolvedValueCache = /* @__PURE__ */ new Map();
|
|
256
|
+
/**
|
|
257
|
+
* What the build would say about this property and value, or nothing if it is fine.
|
|
258
|
+
*
|
|
259
|
+
* Asked of the resolver rather than reimplemented, so the squiggle and the build agree by
|
|
260
|
+
* construction. `getInvalidTokens` above answers a narrower question — is this dotted path a
|
|
261
|
+
* token — and cannot see `color: 'mutedd'` or tell `top: 'navH'` from `animationName: 'fadeIn'`,
|
|
262
|
+
* because neither is decidable without the property and its CSS grammar.
|
|
263
|
+
*/
|
|
264
|
+
const getUnresolvedValueMessage = (property, value, context) => {
|
|
265
|
+
const id = `${property}:${value}`;
|
|
266
|
+
if (unresolvedValueCache.has(id)) return unresolvedValueCache.get(id);
|
|
267
|
+
const message = syncAction("explainUnresolvedValue", getSyncOptions(context), property, value);
|
|
268
|
+
unresolvedValueCache.set(id, message);
|
|
269
|
+
return message;
|
|
270
|
+
};
|
|
255
271
|
const deprecatedTokensCache = /* @__PURE__ */ new Map();
|
|
256
272
|
const getDeprecatedTokens = (property, value, context) => {
|
|
257
273
|
const propertyCategory = syncAction("getPropCategory", getSyncOptions(context), property);
|
|
@@ -1058,25 +1074,45 @@ const rule$12 = createRule({
|
|
|
1058
1074
|
node
|
|
1059
1075
|
});
|
|
1060
1076
|
};
|
|
1061
|
-
|
|
1077
|
+
/**
|
|
1078
|
+
* With the property in hand, ask the resolver the whole question.
|
|
1079
|
+
*
|
|
1080
|
+
* `getInvalidTokens` can only answer "is this dotted path a token", because that is all a
|
|
1081
|
+
* value tells you on its own. The property is what makes `color: 'mutedd'` decidable at all,
|
|
1082
|
+
* and what separates `top: 'navH'` from `animationName: 'fadeIn'` — one is a typo and the
|
|
1083
|
+
* other is a `<custom-ident>` the grammar asks for.
|
|
1084
|
+
*/
|
|
1085
|
+
const reportUnresolved = (node, property, value) => {
|
|
1086
|
+
if (!value) return;
|
|
1087
|
+
const message = getUnresolvedValueMessage(property, value, context);
|
|
1088
|
+
if (message) context.report({
|
|
1089
|
+
data: { message },
|
|
1090
|
+
messageId: "unresolvedValue",
|
|
1091
|
+
node
|
|
1092
|
+
});
|
|
1093
|
+
};
|
|
1094
|
+
const handleValue = (node, property) => {
|
|
1062
1095
|
if (!node) return;
|
|
1063
1096
|
if (isLiteral(node)) {
|
|
1064
1097
|
const value = node.value?.toString();
|
|
1065
1098
|
sendReport(node, value);
|
|
1099
|
+
if (property) reportUnresolved(node, property, value);
|
|
1066
1100
|
} else if (isTemplateLiteral(node) && node.expressions.length === 0) {
|
|
1067
1101
|
const value = node.quasis[0].value.raw;
|
|
1068
1102
|
sendReport(node.quasis[0], value);
|
|
1103
|
+
if (property) reportUnresolved(node.quasis[0], property, value);
|
|
1069
1104
|
}
|
|
1070
1105
|
};
|
|
1071
1106
|
return {
|
|
1072
1107
|
JSXAttribute(node) {
|
|
1073
1108
|
if (!node.value || !isBambooProp(node, context)) return;
|
|
1074
|
-
|
|
1075
|
-
|
|
1109
|
+
const property = isJSXIdentifier(node.name) ? node.name.name : void 0;
|
|
1110
|
+
if (isLiteral(node.value)) handleValue(node.value, property);
|
|
1111
|
+
else if (isJSXExpressionContainer(node.value)) handleValue(node.value.expression, property);
|
|
1076
1112
|
},
|
|
1077
1113
|
Property(node) {
|
|
1078
1114
|
if (!isIdentifier(node.key) || !isNodeOfTypes([AST_NODE_TYPES.Literal, AST_NODE_TYPES.TemplateLiteral])(node.value) || !isBambooAttribute(node, context) || isRecipeVariant(node, context)) return;
|
|
1079
|
-
|
|
1115
|
+
handleValue(node.value, node.key.name);
|
|
1080
1116
|
},
|
|
1081
1117
|
TaggedTemplateExpression(node) {
|
|
1082
1118
|
if (!getTaggedTemplateCaller(node)) return;
|
|
@@ -1114,7 +1150,10 @@ const rule$12 = createRule({
|
|
|
1114
1150
|
defaultOptions: [],
|
|
1115
1151
|
meta: {
|
|
1116
1152
|
docs: { description: "Disallow the use of invalid token paths within token function syntax." },
|
|
1117
|
-
messages: {
|
|
1153
|
+
messages: {
|
|
1154
|
+
noInvalidTokenPaths: "`{{token}}` is an invalid token path.",
|
|
1155
|
+
unresolvedValue: "{{message}}"
|
|
1156
|
+
},
|
|
1118
1157
|
schema: [],
|
|
1119
1158
|
type: "problem"
|
|
1120
1159
|
},
|
package/dist/utils/worker.cjs
CHANGED
|
@@ -63,6 +63,21 @@ const filterDeprecatedTokens = (context, tokens) => {
|
|
|
63
63
|
const filterInvalidTokens = (context, paths) => {
|
|
64
64
|
return paths.filter((path$2) => !context.utility.tokens.view.get(path$2));
|
|
65
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* The build's own verdict on one property/value pair, for the editor.
|
|
68
|
+
*
|
|
69
|
+
* The same predicate and the same sentence the build prints — not a second implementation of
|
|
70
|
+
* either. The type layer used to give this feedback by narrowing every generated prop type, at
|
|
71
|
+
* a measured 19% of the types and 28% of the instantiations in a real project, and it could
|
|
72
|
+
* only ever say "not assignable"; the resolver knows the value is a `sizes` token used on a
|
|
73
|
+
* property that reads `spacing`, and knowing that is the whole point.
|
|
74
|
+
*/
|
|
75
|
+
const explainUnresolvedValue = (context, property, value) => {
|
|
76
|
+
const { utility } = context;
|
|
77
|
+
if (!utility.isUnresolvedTokenValue(property, value)) return void 0;
|
|
78
|
+
const key = utility.resolveShorthand(property);
|
|
79
|
+
return utility.explainUnresolvedToken(utility.unresolvedTokenRef(key, utility.bareTokenPath(key, value)));
|
|
80
|
+
};
|
|
66
81
|
const getPropertyCategory = (context, _attribute) => {
|
|
67
82
|
const attribute = resolveLongHand(context, _attribute) || _attribute;
|
|
68
83
|
const attributeConfig = context.utility.config[attribute];
|
|
@@ -82,6 +97,7 @@ async function runAsync(action, options, ...args) {
|
|
|
82
97
|
switch (action) {
|
|
83
98
|
case "filterDeprecatedTokens": return filterDeprecatedTokens(context, ...args);
|
|
84
99
|
case "filterImports": return filterImports(context, ...args);
|
|
100
|
+
case "explainUnresolvedValue": return explainUnresolvedValue(context, ...args);
|
|
85
101
|
case "filterInvalidTokens": return filterInvalidTokens(context, ...args);
|
|
86
102
|
case "getPropCategory": return getPropertyCategory(context, ...args);
|
|
87
103
|
case "isColorAttribute": return isColorAttribute(context, ...args);
|
package/dist/utils/worker.d.cts
CHANGED
|
@@ -22,6 +22,7 @@ type MatchImportResult = {
|
|
|
22
22
|
name: string;
|
|
23
23
|
};
|
|
24
24
|
declare function run(action: 'filterInvalidTokens', options: Options, paths: string[]): string[];
|
|
25
|
+
declare function run(action: 'explainUnresolvedValue', options: Options, property: string, value: string): string | undefined;
|
|
25
26
|
declare function run(action: 'isColorToken', options: Options, value: string): boolean;
|
|
26
27
|
declare function run(action: 'isColorAttribute', options: Options, attribute: string): boolean;
|
|
27
28
|
declare function run(action: 'isValidFile', options: Options): boolean;
|
|
@@ -34,6 +35,7 @@ declare function run(action: 'filterImports', options: Options, imports: MatchIm
|
|
|
34
35
|
declare function run(action: 'getPropCategory', options: Options, property: string): string;
|
|
35
36
|
declare function run(action: 'filterDeprecatedTokens', options: Options, tokens: DeprecatedToken[]): DeprecatedToken[];
|
|
36
37
|
declare function runAsync(action: 'filterInvalidTokens', options: Options, paths: string[]): Promise<string[]>;
|
|
38
|
+
declare function runAsync(action: 'explainUnresolvedValue', options: Options, property: string, value: string): Promise<string | undefined>;
|
|
37
39
|
declare function runAsync(action: 'isColorToken', options: Options, value: string): Promise<boolean>;
|
|
38
40
|
declare function runAsync(action: 'isColorAttribute', options: Options, attribute: string): Promise<boolean>;
|
|
39
41
|
declare function runAsync(action: 'isValidFile', options: Options, fileName: string): Promise<string>;
|
package/dist/utils/worker.d.mts
CHANGED
|
@@ -22,6 +22,7 @@ type MatchImportResult = {
|
|
|
22
22
|
name: string;
|
|
23
23
|
};
|
|
24
24
|
declare function run(action: 'filterInvalidTokens', options: Options, paths: string[]): string[];
|
|
25
|
+
declare function run(action: 'explainUnresolvedValue', options: Options, property: string, value: string): string | undefined;
|
|
25
26
|
declare function run(action: 'isColorToken', options: Options, value: string): boolean;
|
|
26
27
|
declare function run(action: 'isColorAttribute', options: Options, attribute: string): boolean;
|
|
27
28
|
declare function run(action: 'isValidFile', options: Options): boolean;
|
|
@@ -34,6 +35,7 @@ declare function run(action: 'filterImports', options: Options, imports: MatchIm
|
|
|
34
35
|
declare function run(action: 'getPropCategory', options: Options, property: string): string;
|
|
35
36
|
declare function run(action: 'filterDeprecatedTokens', options: Options, tokens: DeprecatedToken[]): DeprecatedToken[];
|
|
36
37
|
declare function runAsync(action: 'filterInvalidTokens', options: Options, paths: string[]): Promise<string[]>;
|
|
38
|
+
declare function runAsync(action: 'explainUnresolvedValue', options: Options, property: string, value: string): Promise<string | undefined>;
|
|
37
39
|
declare function runAsync(action: 'isColorToken', options: Options, value: string): Promise<boolean>;
|
|
38
40
|
declare function runAsync(action: 'isColorAttribute', options: Options, attribute: string): Promise<boolean>;
|
|
39
41
|
declare function runAsync(action: 'isValidFile', options: Options, fileName: string): Promise<string>;
|
package/dist/utils/worker.mjs
CHANGED
|
@@ -38,6 +38,21 @@ const filterDeprecatedTokens = (context, tokens) => {
|
|
|
38
38
|
const filterInvalidTokens = (context, paths) => {
|
|
39
39
|
return paths.filter((path) => !context.utility.tokens.view.get(path));
|
|
40
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* The build's own verdict on one property/value pair, for the editor.
|
|
43
|
+
*
|
|
44
|
+
* The same predicate and the same sentence the build prints — not a second implementation of
|
|
45
|
+
* either. The type layer used to give this feedback by narrowing every generated prop type, at
|
|
46
|
+
* a measured 19% of the types and 28% of the instantiations in a real project, and it could
|
|
47
|
+
* only ever say "not assignable"; the resolver knows the value is a `sizes` token used on a
|
|
48
|
+
* property that reads `spacing`, and knowing that is the whole point.
|
|
49
|
+
*/
|
|
50
|
+
const explainUnresolvedValue = (context, property, value) => {
|
|
51
|
+
const { utility } = context;
|
|
52
|
+
if (!utility.isUnresolvedTokenValue(property, value)) return void 0;
|
|
53
|
+
const key = utility.resolveShorthand(property);
|
|
54
|
+
return utility.explainUnresolvedToken(utility.unresolvedTokenRef(key, utility.bareTokenPath(key, value)));
|
|
55
|
+
};
|
|
41
56
|
const getPropertyCategory = (context, _attribute) => {
|
|
42
57
|
const attribute = resolveLongHand(context, _attribute) || _attribute;
|
|
43
58
|
const attributeConfig = context.utility.config[attribute];
|
|
@@ -57,6 +72,7 @@ async function runAsync(action, options, ...args) {
|
|
|
57
72
|
switch (action) {
|
|
58
73
|
case "filterDeprecatedTokens": return filterDeprecatedTokens(context, ...args);
|
|
59
74
|
case "filterImports": return filterImports(context, ...args);
|
|
75
|
+
case "explainUnresolvedValue": return explainUnresolvedValue(context, ...args);
|
|
60
76
|
case "filterInvalidTokens": return filterInvalidTokens(context, ...args);
|
|
61
77
|
case "getPropCategory": return getPropertyCategory(context, ...args);
|
|
62
78
|
case "isColorAttribute": return isColorAttribute(context, ...args);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/eslint-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.0",
|
|
4
4
|
"description": "ESLint plugin for Bamboo CSS",
|
|
5
5
|
"homepage": "https://bamboocss.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"@typescript-eslint/utils": "^8.21.0",
|
|
37
37
|
"micromatch": "^4.0.8",
|
|
38
38
|
"synckit": "^0.9.0",
|
|
39
|
-
"@bamboocss/config": "1.
|
|
40
|
-
"@bamboocss/generator": "1.
|
|
41
|
-
"@bamboocss/shared": "1.
|
|
39
|
+
"@bamboocss/config": "1.43.0",
|
|
40
|
+
"@bamboocss/generator": "1.43.0",
|
|
41
|
+
"@bamboocss/shared": "1.43.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/micromatch": "^4.0.10",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"eslint": "^9.35.0",
|
|
47
47
|
"multiline-ts": "^4.0.1",
|
|
48
48
|
"typescript": "^5.7.2",
|
|
49
|
-
"@bamboocss/dev": "1.
|
|
50
|
-
"@bamboocss/preset-bamboo": "1.
|
|
51
|
-
"@bamboocss/preset-base": "1.
|
|
52
|
-
"@bamboocss/types": "1.
|
|
49
|
+
"@bamboocss/dev": "1.43.0",
|
|
50
|
+
"@bamboocss/preset-bamboo": "1.43.0",
|
|
51
|
+
"@bamboocss/preset-base": "1.43.0",
|
|
52
|
+
"@bamboocss/types": "1.43.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"eslint": "*"
|