@nordcraft/search 1.0.87 → 1.0.89
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/rules/issues/dom/nonEmptyVoidElementRule.js +1 -1
- package/dist/rules/issues/dom/nonEmptyVoidElementRule.js.map +1 -1
- package/dist/rules/issues/miscellaneous/createStaticSizeConstraintRule.js +1 -1
- package/dist/rules/issues/miscellaneous/createStaticSizeConstraintRule.js.map +1 -1
- package/dist/rules/issues/style/invalidStyleSyntaxRule.js +16 -0
- package/dist/rules/issues/style/invalidStyleSyntaxRule.js.map +1 -1
- package/dist/rules/issues/style/styleRules.index.d.ts +3 -1
- package/dist/rules/issues/style/unknownCSSVariable.d.ts +3 -2
- package/dist/rules/issues/style/unknownCSSVariable.js +79 -36
- package/dist/rules/issues/style/unknownCSSVariable.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/package.json +3 -3
- package/src/rules/issues/actions/unknownActionEventRule.test.ts +0 -1
- package/src/rules/issues/dom/nonEmptyVoidElementRule.ts +1 -1
- package/src/rules/issues/events/noReferenceEventRule.test.ts +0 -4
- package/src/rules/issues/events/unknownEventRule.test.ts +0 -4
- package/src/rules/issues/events/unknownTriggerEventRule.test.ts +0 -2
- package/src/rules/issues/miscellaneous/createStaticSizeConstraintRule.ts +1 -1
- package/src/rules/issues/style/invalidStyleSyntaxRule.test.ts +386 -0
- package/src/rules/issues/style/invalidStyleSyntaxRule.ts +21 -0
- package/src/rules/issues/style/unknownCSSVariable.test.ts +107 -44
- package/src/rules/issues/style/unknownCSSVariable.ts +101 -46
- package/src/types.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nonEmptyVoidElementRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/nonEmptyVoidElementRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"nonEmptyVoidElementRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/nonEmptyVoidElementRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAEpE;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAA0B;IAC5D,IAAI,EAAE,wBAAwB;IAC9B,KAAK,EAAE,SAAS;IAChB,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC5C,IACE,QAAQ,KAAK,gBAAgB;YAC7B,KAAK,CAAC,IAAI,KAAK,SAAS;YACxB,KAAK,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC;YAC1B,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EACvC,CAAC;YACD,OAAM;QACR,CAAC;QACD,MAAM,CAAC;YACL,IAAI;YACJ,IAAI,EAAE;gBACJ,KAAK,EAAE,wBAAwB;gBAC/B,WAAW,EAAE,SAAS,KAAK,CAAC,GAAG,wCAAwC,KAAK,CAAC,GAAG,4GAA4G;aAC7L;YACD,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE;SAC5B,CAAC,CAAA;IAAA,CACH;CACF,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { VOID_HTML_ELEMENTS } from '@nordcraft/core/dist/utils/html';
|
|
1
2
|
import { isDefined } from '@nordcraft/core/dist/utils/util';
|
|
2
|
-
import { VOID_HTML_ELEMENTS } from '@nordcraft/ssr/dist/const';
|
|
3
3
|
export function createStaticSizeConstraintRule(tag, maxSize, level = 'info') {
|
|
4
4
|
return {
|
|
5
5
|
code: 'size constraint',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createStaticSizeConstraintRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/miscellaneous/createStaticSizeConstraintRule.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"createStaticSizeConstraintRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/miscellaneous/createStaticSizeConstraintRule.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,22 @@ export const invalidStyleSyntaxRule = {
|
|
|
8
8
|
if (nodeType !== 'style-declaration') {
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
|
+
// Check for variable/formula references: Variables., Formulas., Event., Attributes., Apis., Parameters., ListItem., URLParameters.
|
|
12
|
+
if (typeof value.styleValue === 'string') {
|
|
13
|
+
const hasVariableReference = /\b(Variables|Formulas|Event|Attributes|Apis|Parameters|ListItem|URLParameters)\.\w+/i.test(value.styleValue);
|
|
14
|
+
if (hasVariableReference) {
|
|
15
|
+
report({
|
|
16
|
+
path,
|
|
17
|
+
info: {
|
|
18
|
+
title: `Formulas detected in style declaration`,
|
|
19
|
+
description: `The style declaration for the property "${value.styleProperty}" contains Nordcraft formula syntax (e.g., references like "Variables.xxx", "Event.xxx", "Attributes.xxx", etc.). Formulas should not be used directly in CSS style values. Use style-variables or computed styles instead.`,
|
|
20
|
+
},
|
|
21
|
+
details: { property: value.styleProperty },
|
|
22
|
+
fixes: ['delete-style-property'],
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
11
27
|
const valid = memo(`valid-style-${value.styleProperty}:${value.styleValue}`, () => {
|
|
12
28
|
try {
|
|
13
29
|
parse(`${value.styleProperty}: ${value.styleValue}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidStyleSyntaxRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/style/invalidStyleSyntaxRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAElE,MAAM,CAAC,MAAM,sBAAsB,GAE9B;IACH,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAClD,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;YACrC,OAAM;QACR,CAAC;
|
|
1
|
+
{"version":3,"file":"invalidStyleSyntaxRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/style/invalidStyleSyntaxRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAElE,MAAM,CAAC,MAAM,sBAAsB,GAE9B;IACH,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAClD,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;YACrC,OAAM;QACR,CAAC;QAED,mIAAmI;QACnI,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACzC,MAAM,oBAAoB,GACxB,sFAAsF,CAAC,IAAI,CACzF,KAAK,CAAC,UAAU,CACjB,CAAA;YACH,IAAI,oBAAoB,EAAE,CAAC;gBACzB,MAAM,CAAC;oBACL,IAAI;oBACJ,IAAI,EAAE;wBACJ,KAAK,EAAE,wCAAwC;wBAC/C,WAAW,EAAE,2CAA2C,KAAK,CAAC,aAAa,6NAA6N;qBACzS;oBACD,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE;oBAC1C,KAAK,EAAE,CAAC,uBAAuB,CAAC;iBACjC,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAChB,eAAe,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,UAAU,EAAE,EACxD,GAAG,EAAE,CAAC;YACJ,IAAI,CAAC;gBACH,KAAK,CAAC,GAAG,KAAK,CAAC,aAAa,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;gBACpD,OAAO,IAAI,CAAA;YACb,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAA;YACd,CAAC;QAAA,CACF,CACF,CAAA;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC;gBACL,IAAI;gBACJ,IAAI,EAAE;oBACJ,KAAK,EAAE,2BAA2B;oBAClC,WAAW,EAAE,2CAA2C,KAAK,CAAC,aAAa,kIAAkI;iBAC9M;gBACD,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,EAAE;gBAC1C,KAAK,EAAE,CAAC,uBAAuB,CAAC;aACjC,CAAC,CAAA;QACJ,CAAC;IAAA,CACF;IACD,KAAK,EAAE;QACL,uBAAuB,EAAE,iBAAiB;KAC3C;CACF,CAAA"}
|
|
@@ -2,5 +2,7 @@ declare const _default: (import("../../../types").Rule<unknown, import("../../..
|
|
|
2
2
|
property: string;
|
|
3
3
|
}, import("../../../types").NodeType, import("../../../types").NodeType> | import("../../../types").Rule<{
|
|
4
4
|
name: string;
|
|
5
|
-
}, import("../../../types").NodeType, import("../../../types").StyleVariableNode>)
|
|
5
|
+
}, import("../../../types").NodeType, import("../../../types").StyleVariableNode> | import("../../../types").Rule<{
|
|
6
|
+
name: string;
|
|
7
|
+
}, import("../../../types").StyleNode, import("../../../types").StyleNode>)[];
|
|
6
8
|
export default _default;
|
|
@@ -18,59 +18,102 @@ export const unknownCSSVariableRule = {
|
|
|
18
18
|
if (vars.length === 0) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
const themeCssVariables = theme.propertyDefinitions;
|
|
22
|
+
const [_fileType, componentName, _nodes, nodeName] = path;
|
|
23
|
+
const localCssVariables = memo(`component-css-variables-${componentName}-${nodeName}`, () => {
|
|
24
|
+
const vars = new Set();
|
|
25
|
+
const component = files.components[componentName];
|
|
26
|
+
if (!component) {
|
|
27
|
+
return vars;
|
|
28
|
+
}
|
|
29
|
+
const visitVars = (nodeName) => {
|
|
30
|
+
const node = component?.nodes?.[nodeName];
|
|
31
|
+
if (!node) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (node.type === 'component' || node.type === 'element') {
|
|
35
|
+
Object.keys(node.customProperties ?? {}).forEach((varName) => {
|
|
36
|
+
vars.add(varName);
|
|
37
|
+
});
|
|
38
|
+
Object.values(node.variants ?? {}).forEach((variant) => {
|
|
39
|
+
Object.keys(variant.customProperties ?? {}).forEach((varName) => {
|
|
40
|
+
vars.add(varName);
|
|
32
41
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
});
|
|
43
|
+
// Also add legacy style variables
|
|
44
|
+
if (node.type === 'element' && node['style-variables']) {
|
|
45
|
+
node['style-variables'].forEach((styleVar) => {
|
|
46
|
+
vars.add(`--${styleVar.name}`);
|
|
37
47
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
}
|
|
49
|
+
// Add if declared in any parent styles object
|
|
50
|
+
Object.keys(node.style ?? {}).forEach((styleKey) => {
|
|
51
|
+
if (styleKey.startsWith('--')) {
|
|
52
|
+
vars.add(styleKey);
|
|
43
53
|
}
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
});
|
|
55
|
+
Object.values(node.variants ?? {}).forEach((variant) => {
|
|
56
|
+
Object.keys(variant.style ?? {}).forEach((styleKey) => {
|
|
46
57
|
if (styleKey.startsWith('--')) {
|
|
47
|
-
|
|
58
|
+
vars.add(styleKey);
|
|
48
59
|
}
|
|
49
60
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
});
|
|
60
|
-
return cssVariableKeys;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const parent = Object.entries(component.nodes ?? {}).find(([_, n]) => n.children?.includes(nodeName));
|
|
64
|
+
if (parent) {
|
|
65
|
+
visitVars(parent[0]);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
visitVars(nodeName.toString());
|
|
69
|
+
return vars;
|
|
61
70
|
});
|
|
62
71
|
for (const varName of vars) {
|
|
63
|
-
if (
|
|
72
|
+
if (!(varName in themeCssVariables) && !localCssVariables.has(varName)) {
|
|
64
73
|
report({
|
|
65
74
|
path,
|
|
66
75
|
info: {
|
|
67
76
|
title: `Unknown CSS variable`,
|
|
68
|
-
description: `The CSS variable **${varName}** is not declared in any parent element or
|
|
77
|
+
description: `The CSS variable **${varName}** is not declared in any parent element or theme. CSS variables must be declared in an ancestor element or in your global theme.`,
|
|
69
78
|
},
|
|
70
79
|
details: { name: varName },
|
|
80
|
+
fixes: ['add-to-theme'],
|
|
71
81
|
});
|
|
72
82
|
}
|
|
73
83
|
}
|
|
74
84
|
},
|
|
85
|
+
fixes: {
|
|
86
|
+
'add-to-theme': addToThemeFix,
|
|
87
|
+
},
|
|
75
88
|
};
|
|
89
|
+
function addToThemeFix(args) {
|
|
90
|
+
const varName = args.details?.name;
|
|
91
|
+
if (typeof varName !== 'string' || !args.data.files.themes?.Default) {
|
|
92
|
+
return args.data.files;
|
|
93
|
+
}
|
|
94
|
+
const definition = {
|
|
95
|
+
syntax: {
|
|
96
|
+
type: 'primitive',
|
|
97
|
+
name: '*',
|
|
98
|
+
},
|
|
99
|
+
inherits: true,
|
|
100
|
+
initialValue: '',
|
|
101
|
+
values: {},
|
|
102
|
+
description: '',
|
|
103
|
+
};
|
|
104
|
+
// Add the variable to the theme with Any (*) syntax type
|
|
105
|
+
return {
|
|
106
|
+
...args.data.files,
|
|
107
|
+
themes: {
|
|
108
|
+
...args.data.files.themes,
|
|
109
|
+
Default: {
|
|
110
|
+
...args.data.files.themes.Default,
|
|
111
|
+
propertyDefinitions: {
|
|
112
|
+
...args.data.files.themes.Default.propertyDefinitions,
|
|
113
|
+
[varName]: definition,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
76
119
|
//# sourceMappingURL=unknownCSSVariable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unknownCSSVariable.js","sourceRoot":"","sources":["../../../../src/rules/issues/style/unknownCSSVariable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"unknownCSSVariable.js","sourceRoot":"","sources":["../../../../src/rules/issues/style/unknownCSSVariable.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ import type { NoStaticNodeConditionRuleFix } from './rules/issues/logic/noStatic
|
|
|
29
29
|
import type { NoReferenceNodeRuleFix } from './rules/issues/miscellaneous/noReferenceNodeRule';
|
|
30
30
|
import type { InvalidStyleSyntaxRuleFix } from './rules/issues/style/invalidStyleSyntaxRule';
|
|
31
31
|
import type { LegacyStyleVariableRuleFix } from './rules/issues/style/legacyStyleVariableRule';
|
|
32
|
+
import type { AddToThemeFix } from './rules/issues/style/unknownCSSVariable';
|
|
32
33
|
import type { NoReferenceVariableRuleFix } from './rules/issues/variables/noReferenceVariableRule';
|
|
33
34
|
import type { NoPostNavigateActionRuleFix } from './rules/issues/workflows/noPostNavigateAction';
|
|
34
35
|
export type Code = 'duplicate action argument name' | 'duplicate event trigger' | 'duplicate formula argument name' | 'duplicate route' | 'duplicate url parameter' | 'duplicate workflow parameter' | 'image without dimension' | 'invalid api parser mode' | 'invalid api proxy body setting' | 'invalid api proxy cookie setting' | 'invalid component structure' | 'invalid element child' | 'invalid style syntax' | 'legacy action' | 'legacy api' | 'legacy formula' | 'legacy style variable' | 'legacy theme' | 'no context consumers' | 'no post navigate action' | 'no-console' | 'no-reference api input' | 'no-reference api service' | 'no-reference api' | 'no-reference attribute in instance' | 'no-reference attribute' | 'no-reference component formula' | 'no-reference component workflow' | 'no-reference component' | 'no-reference event' | 'no-reference global css variable' | 'no-reference node' | 'no-reference project action' | 'no-reference project formula' | 'no-reference variable' | 'no-static-node-condition' | 'no-unnecessary-condition-falsy' | 'no-unnecessary-condition-truthy' | 'non-empty void element' | 'required api autofetch' | 'required direct child' | 'required direct parent' | 'required element attribute' | 'required extension' | 'required meta tag' | 'size constraint' | 'unknown action argument' | 'unknown action event' | 'unknown api input' | 'unknown api service' | 'unknown api' | 'unknown attribute' | 'unknown classname' | 'unknown component attribute' | 'unknown component formula input' | 'unknown component slot' | 'unknown component' | 'unknown context formula' | 'unknown context provider formula' | 'unknown context provider workflow' | 'unknown context provider' | 'unknown context workflow' | 'unknown cookie' | 'unknown css variable' | 'unknown event' | 'unknown fetch input' | 'unknown formula' | 'unknown project action' | 'unknown project formula input' | 'unknown project formula' | 'unknown repeat index formula' | 'unknown repeat item formula' | 'unknown set url parameter' | 'unknown set url parameters' | 'unknown trigger event' | 'unknown trigger workflow parameter' | 'unknown trigger workflow' | 'unknown url parameter' | 'unknown variable setter' | 'unknown variable' | 'unknown workflow parameter';
|
|
@@ -261,7 +262,7 @@ export type StyleNode = {
|
|
|
261
262
|
};
|
|
262
263
|
} & Base;
|
|
263
264
|
export type NodeType = ActionModelNode | ComponentAPIInputNode | ComponentAPINode | ComponentAttributeNode | ComponentContext | ComponentEvent | ComponentFormulaNode | ComponentNode | ComponentNodeAttributeNode | ComponentNodeNode | ComponentVariableNode | ComponentWorkflowNode | CustomActionModelArgumentNode | CustomActionModelEventNode | CustomPropertyNode | FormulaNode | ProjectActionNode | ProjectApiService | ProjectConfigNode | ProjectFormulaNode | ProjectRoute | ProjectThemeNode | ProjectThemePropertyNode | StyleNode | StyleVariableNode | StyleVariantNode;
|
|
264
|
-
export type FixType = ChangeDataTypeFix | DeleteFetchInputFix | InvalidStyleSyntaxRuleFix | LegacyActionRuleFix | LegacyFormulaRuleFix | LegacyStyleVariableRuleFix | NoPostNavigateActionRuleFix | NoReferenceApiRuleFix | NoReferenceApiServiceRuleFix | NoReferenceAttributeRuleFix | NoReferenceComponentFormulaRuleFix | NoReferenceComponentRuleFix | NoReferenceEventRuleFix | NoReferenceNodeRuleFix | NoReferenceProjectActionRuleFix | NoReferenceProjectFormulaRuleFix | NoReferenceVariableRuleFix | NoStaticNodeConditionRuleFix | UnknownActionArgumentRuleFix | UnknownActionEventRuleFix | UnknownApiServiceRuleFix | UnknownComponentAttributeRuleFix;
|
|
265
|
+
export type FixType = AddToThemeFix | ChangeDataTypeFix | DeleteFetchInputFix | InvalidStyleSyntaxRuleFix | LegacyActionRuleFix | LegacyFormulaRuleFix | LegacyStyleVariableRuleFix | NoPostNavigateActionRuleFix | NoReferenceApiRuleFix | NoReferenceApiServiceRuleFix | NoReferenceAttributeRuleFix | NoReferenceComponentFormulaRuleFix | NoReferenceComponentRuleFix | NoReferenceEventRuleFix | NoReferenceNodeRuleFix | NoReferenceProjectActionRuleFix | NoReferenceProjectFormulaRuleFix | NoReferenceVariableRuleFix | NoStaticNodeConditionRuleFix | UnknownActionArgumentRuleFix | UnknownActionEventRuleFix | UnknownApiServiceRuleFix | UnknownComponentAttributeRuleFix;
|
|
265
266
|
interface ReportedIssueInfo {
|
|
266
267
|
title: string;
|
|
267
268
|
description: string;
|
package/package.json
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"directory": "packages/search"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@nordcraft/ssr": "1.0.
|
|
14
|
-
"@nordcraft/core": "1.0.
|
|
13
|
+
"@nordcraft/ssr": "1.0.89",
|
|
14
|
+
"@nordcraft/core": "1.0.89",
|
|
15
15
|
"jsondiffpatch": "0.7.3",
|
|
16
16
|
"postcss": "8.5.6",
|
|
17
17
|
"zod": "4.2.1"
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
"test:watch:only": "bun test --watch --only"
|
|
27
27
|
},
|
|
28
28
|
"files": ["dist", "src"],
|
|
29
|
-
"version": "1.0.
|
|
29
|
+
"version": "1.0.89"
|
|
30
30
|
}
|
|
@@ -42,7 +42,6 @@ describe('find noReferenceEventRule', () => {
|
|
|
42
42
|
events: [
|
|
43
43
|
{
|
|
44
44
|
name: 'unused-event',
|
|
45
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
46
45
|
dummyEvent: {
|
|
47
46
|
name: 'Name',
|
|
48
47
|
},
|
|
@@ -120,7 +119,6 @@ describe('find noReferenceEventRule', () => {
|
|
|
120
119
|
events: [
|
|
121
120
|
{
|
|
122
121
|
name: 'known-event',
|
|
123
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
124
122
|
dummyEvent: {
|
|
125
123
|
name: 'Name',
|
|
126
124
|
},
|
|
@@ -130,7 +128,6 @@ describe('find noReferenceEventRule', () => {
|
|
|
130
128
|
},
|
|
131
129
|
{
|
|
132
130
|
name: 'used-event',
|
|
133
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
134
131
|
dummyEvent: {
|
|
135
132
|
name: 'Name',
|
|
136
133
|
},
|
|
@@ -184,7 +181,6 @@ describe('fix noReferenceEventRule', () => {
|
|
|
184
181
|
events: [
|
|
185
182
|
{
|
|
186
183
|
name: 'unused-event',
|
|
187
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
188
184
|
dummyEvent: {
|
|
189
185
|
name: 'Name',
|
|
190
186
|
},
|
|
@@ -66,7 +66,6 @@ describe('unknownEvent', () => {
|
|
|
66
66
|
events: [
|
|
67
67
|
{
|
|
68
68
|
name: 'known-event',
|
|
69
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
70
69
|
dummyEvent: {
|
|
71
70
|
name: 'Name',
|
|
72
71
|
},
|
|
@@ -94,7 +93,6 @@ describe('unknownEvent', () => {
|
|
|
94
93
|
events: [
|
|
95
94
|
{
|
|
96
95
|
name: 'known-event',
|
|
97
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
98
96
|
dummyEvent: {
|
|
99
97
|
name: 'Name',
|
|
100
98
|
},
|
|
@@ -187,7 +185,6 @@ describe('unknownEvent', () => {
|
|
|
187
185
|
events: [
|
|
188
186
|
{
|
|
189
187
|
name: 'known-event',
|
|
190
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
191
188
|
dummyEvent: {
|
|
192
189
|
name: 'Name',
|
|
193
190
|
},
|
|
@@ -215,7 +212,6 @@ describe('unknownEvent', () => {
|
|
|
215
212
|
events: [
|
|
216
213
|
{
|
|
217
214
|
name: 'known-event',
|
|
218
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
219
215
|
dummyEvent: {
|
|
220
216
|
name: 'Name',
|
|
221
217
|
},
|
|
@@ -40,7 +40,6 @@ describe('unknownTriggerEventRule', () => {
|
|
|
40
40
|
events: [
|
|
41
41
|
{
|
|
42
42
|
name: 'known-event',
|
|
43
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
44
43
|
dummyEvent: {
|
|
45
44
|
name: 'Name',
|
|
46
45
|
},
|
|
@@ -97,7 +96,6 @@ describe('unknownTriggerEventRule', () => {
|
|
|
97
96
|
events: [
|
|
98
97
|
{
|
|
99
98
|
name: 'known-event',
|
|
100
|
-
// eslint-disable-next-line inclusive-language/use-inclusive-words
|
|
101
99
|
dummyEvent: {
|
|
102
100
|
name: 'Name',
|
|
103
101
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NodeModel } from '@nordcraft/core/dist/component/component.types'
|
|
2
|
+
import { VOID_HTML_ELEMENTS } from '@nordcraft/core/dist/utils/html'
|
|
2
3
|
import { isDefined } from '@nordcraft/core/dist/utils/util'
|
|
3
|
-
import { VOID_HTML_ELEMENTS } from '@nordcraft/ssr/dist/const'
|
|
4
4
|
import type { Level, Rule } from '../../../types'
|
|
5
5
|
|
|
6
6
|
export function createStaticSizeConstraintRule(
|
|
@@ -203,6 +203,298 @@ describe('find invalidStyleSyntaxRule', () => {
|
|
|
203
203
|
})
|
|
204
204
|
})
|
|
205
205
|
|
|
206
|
+
describe('find formulas in style syntax', () => {
|
|
207
|
+
test('should find Variables. references in style syntax', () => {
|
|
208
|
+
const problems = Array.from(
|
|
209
|
+
searchProject({
|
|
210
|
+
files: {
|
|
211
|
+
formulas: {},
|
|
212
|
+
components: {
|
|
213
|
+
test: {
|
|
214
|
+
name: 'test',
|
|
215
|
+
nodes: {
|
|
216
|
+
root: {
|
|
217
|
+
tag: 'div',
|
|
218
|
+
type: 'element',
|
|
219
|
+
attrs: {},
|
|
220
|
+
style: {
|
|
221
|
+
transform: 'translateX(Variables.offsetX)',
|
|
222
|
+
width: '100px',
|
|
223
|
+
height: 'Variables.height',
|
|
224
|
+
},
|
|
225
|
+
events: {},
|
|
226
|
+
classes: {},
|
|
227
|
+
children: [],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
formulas: {},
|
|
231
|
+
apis: {},
|
|
232
|
+
attributes: {},
|
|
233
|
+
variables: {},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
rules: [invalidStyleSyntaxRule],
|
|
238
|
+
}),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
expect(problems).toMatchObject([
|
|
242
|
+
{
|
|
243
|
+
code: 'invalid style syntax',
|
|
244
|
+
path: ['components', 'test', 'nodes', 'root', 'style', 'transform'],
|
|
245
|
+
details: { property: 'transform' },
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
code: 'invalid style syntax',
|
|
249
|
+
path: ['components', 'test', 'nodes', 'root', 'style', 'height'],
|
|
250
|
+
details: { property: 'height' },
|
|
251
|
+
},
|
|
252
|
+
])
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
test('should find Formulas., Event., Attributes., Apis., Parameters., ListItem., URLParameters. references', () => {
|
|
256
|
+
const problems = Array.from(
|
|
257
|
+
searchProject({
|
|
258
|
+
files: {
|
|
259
|
+
formulas: {},
|
|
260
|
+
components: {
|
|
261
|
+
test: {
|
|
262
|
+
name: 'test',
|
|
263
|
+
nodes: {
|
|
264
|
+
root: {
|
|
265
|
+
tag: 'div',
|
|
266
|
+
type: 'element',
|
|
267
|
+
attrs: {},
|
|
268
|
+
style: {
|
|
269
|
+
color: 'Formulas.getColor()',
|
|
270
|
+
top: 'Event.clientY',
|
|
271
|
+
margin: 'Attributes.margin',
|
|
272
|
+
background: 'Apis.getBackground()',
|
|
273
|
+
fontSize: 'Parameters.size',
|
|
274
|
+
backgroundColor: 'ListItem.color',
|
|
275
|
+
width: 'URLParameters.width',
|
|
276
|
+
},
|
|
277
|
+
events: {},
|
|
278
|
+
classes: {},
|
|
279
|
+
children: [],
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
formulas: {},
|
|
283
|
+
apis: {},
|
|
284
|
+
attributes: {},
|
|
285
|
+
variables: {},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
rules: [invalidStyleSyntaxRule],
|
|
290
|
+
}),
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
expect(problems).toHaveLength(7)
|
|
294
|
+
expect(problems.map((p) => p.details.property)).toEqual([
|
|
295
|
+
'color',
|
|
296
|
+
'top',
|
|
297
|
+
'margin',
|
|
298
|
+
'background',
|
|
299
|
+
'fontSize',
|
|
300
|
+
'backgroundColor',
|
|
301
|
+
'width',
|
|
302
|
+
])
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
test('should not find formulas in valid CSS values', () => {
|
|
306
|
+
const problems = Array.from(
|
|
307
|
+
searchProject({
|
|
308
|
+
files: {
|
|
309
|
+
formulas: {},
|
|
310
|
+
components: {
|
|
311
|
+
test: {
|
|
312
|
+
name: 'test',
|
|
313
|
+
nodes: {
|
|
314
|
+
root: {
|
|
315
|
+
tag: 'div',
|
|
316
|
+
type: 'element',
|
|
317
|
+
attrs: {},
|
|
318
|
+
style: {
|
|
319
|
+
width: '100px',
|
|
320
|
+
height: '50%',
|
|
321
|
+
color: '#ffffff',
|
|
322
|
+
backgroundColor: 'var(--my-var)',
|
|
323
|
+
transform: 'translateX(10px)',
|
|
324
|
+
margin: '10px 20px',
|
|
325
|
+
},
|
|
326
|
+
events: {},
|
|
327
|
+
classes: {},
|
|
328
|
+
children: [],
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
formulas: {},
|
|
332
|
+
apis: {},
|
|
333
|
+
attributes: {},
|
|
334
|
+
variables: {},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
rules: [invalidStyleSyntaxRule],
|
|
339
|
+
}),
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
expect(problems).toHaveLength(0)
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
test('should not find formulas in numeric style values', () => {
|
|
346
|
+
const problems = Array.from(
|
|
347
|
+
searchProject({
|
|
348
|
+
files: {
|
|
349
|
+
formulas: {},
|
|
350
|
+
components: {
|
|
351
|
+
test: {
|
|
352
|
+
name: 'test',
|
|
353
|
+
nodes: {
|
|
354
|
+
root: {
|
|
355
|
+
tag: 'div',
|
|
356
|
+
type: 'element',
|
|
357
|
+
attrs: {},
|
|
358
|
+
style: {
|
|
359
|
+
opacity: 0.5,
|
|
360
|
+
zIndex: 10,
|
|
361
|
+
flex: 1,
|
|
362
|
+
},
|
|
363
|
+
events: {},
|
|
364
|
+
classes: {},
|
|
365
|
+
children: [],
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
formulas: {},
|
|
369
|
+
apis: {},
|
|
370
|
+
attributes: {},
|
|
371
|
+
variables: {},
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
rules: [invalidStyleSyntaxRule],
|
|
376
|
+
}),
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
expect(problems).toHaveLength(0)
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
test('should find formulas in variant styles', () => {
|
|
383
|
+
const problems = Array.from(
|
|
384
|
+
searchProject({
|
|
385
|
+
files: {
|
|
386
|
+
formulas: {},
|
|
387
|
+
components: {
|
|
388
|
+
test: {
|
|
389
|
+
name: 'test',
|
|
390
|
+
nodes: {
|
|
391
|
+
root: {
|
|
392
|
+
tag: 'div',
|
|
393
|
+
type: 'element',
|
|
394
|
+
attrs: {},
|
|
395
|
+
style: {
|
|
396
|
+
width: '100px',
|
|
397
|
+
},
|
|
398
|
+
events: {},
|
|
399
|
+
classes: {},
|
|
400
|
+
children: [],
|
|
401
|
+
variants: [
|
|
402
|
+
{
|
|
403
|
+
style: {
|
|
404
|
+
transform: 'translateX(Variables.offsetX)',
|
|
405
|
+
color: 'Event.color',
|
|
406
|
+
},
|
|
407
|
+
hover: true,
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
formulas: {},
|
|
413
|
+
apis: {},
|
|
414
|
+
attributes: {},
|
|
415
|
+
variables: {},
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
rules: [invalidStyleSyntaxRule],
|
|
420
|
+
}),
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
expect(problems).toMatchObject([
|
|
424
|
+
{
|
|
425
|
+
code: 'invalid style syntax',
|
|
426
|
+
path: [
|
|
427
|
+
'components',
|
|
428
|
+
'test',
|
|
429
|
+
'nodes',
|
|
430
|
+
'root',
|
|
431
|
+
'variants',
|
|
432
|
+
0,
|
|
433
|
+
'style',
|
|
434
|
+
'transform',
|
|
435
|
+
],
|
|
436
|
+
details: { property: 'transform' },
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
code: 'invalid style syntax',
|
|
440
|
+
path: [
|
|
441
|
+
'components',
|
|
442
|
+
'test',
|
|
443
|
+
'nodes',
|
|
444
|
+
'root',
|
|
445
|
+
'variants',
|
|
446
|
+
0,
|
|
447
|
+
'style',
|
|
448
|
+
'color',
|
|
449
|
+
],
|
|
450
|
+
details: { property: 'color' },
|
|
451
|
+
},
|
|
452
|
+
])
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test('should handle case-insensitive matching for formulas', () => {
|
|
456
|
+
const problems = Array.from(
|
|
457
|
+
searchProject({
|
|
458
|
+
files: {
|
|
459
|
+
formulas: {},
|
|
460
|
+
components: {
|
|
461
|
+
test: {
|
|
462
|
+
name: 'test',
|
|
463
|
+
nodes: {
|
|
464
|
+
root: {
|
|
465
|
+
tag: 'div',
|
|
466
|
+
type: 'element',
|
|
467
|
+
attrs: {},
|
|
468
|
+
style: {
|
|
469
|
+
width: 'VARIABLES.offsetX',
|
|
470
|
+
height: 'variables.height',
|
|
471
|
+
color: 'FORMULAS.getColor()',
|
|
472
|
+
},
|
|
473
|
+
events: {},
|
|
474
|
+
classes: {},
|
|
475
|
+
children: [],
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
formulas: {},
|
|
479
|
+
apis: {},
|
|
480
|
+
attributes: {},
|
|
481
|
+
variables: {},
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
rules: [invalidStyleSyntaxRule],
|
|
486
|
+
}),
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
expect(problems).toHaveLength(3)
|
|
490
|
+
expect(problems.map((p) => p.details.property)).toEqual([
|
|
491
|
+
'width',
|
|
492
|
+
'height',
|
|
493
|
+
'color',
|
|
494
|
+
])
|
|
495
|
+
})
|
|
496
|
+
})
|
|
497
|
+
|
|
206
498
|
describe('fix invalidStyleSyntaxRule', () => {
|
|
207
499
|
test('should remove an invalid style property', () => {
|
|
208
500
|
const files: ProjectFiles = {
|
|
@@ -248,6 +540,49 @@ describe('fix invalidStyleSyntaxRule', () => {
|
|
|
248
540
|
}
|
|
249
541
|
`)
|
|
250
542
|
})
|
|
543
|
+
test('should remove a style property with formula syntax', () => {
|
|
544
|
+
const files: ProjectFiles = {
|
|
545
|
+
formulas: {},
|
|
546
|
+
components: {
|
|
547
|
+
test: {
|
|
548
|
+
name: 'test',
|
|
549
|
+
nodes: {
|
|
550
|
+
root: {
|
|
551
|
+
tag: 'div',
|
|
552
|
+
type: 'element',
|
|
553
|
+
attrs: {},
|
|
554
|
+
style: {
|
|
555
|
+
width: '100px',
|
|
556
|
+
transform: 'translateX(Variables.offsetX)',
|
|
557
|
+
height: '50px',
|
|
558
|
+
color: 'Variables.color',
|
|
559
|
+
},
|
|
560
|
+
events: {},
|
|
561
|
+
classes: {},
|
|
562
|
+
children: [],
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
formulas: {},
|
|
566
|
+
apis: {},
|
|
567
|
+
attributes: {},
|
|
568
|
+
variables: {},
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
}
|
|
572
|
+
const fixedFiles = fixProject({
|
|
573
|
+
files,
|
|
574
|
+
rule: invalidStyleSyntaxRule,
|
|
575
|
+
fixType: 'delete-style-property',
|
|
576
|
+
})
|
|
577
|
+
expect((fixedFiles.components.test!.nodes?.root as ElementNodeModel).style)
|
|
578
|
+
.toMatchInlineSnapshot(`
|
|
579
|
+
{
|
|
580
|
+
"height": "50px",
|
|
581
|
+
"width": "100px",
|
|
582
|
+
}
|
|
583
|
+
`)
|
|
584
|
+
})
|
|
585
|
+
|
|
251
586
|
test('should remove an invalid style variant style property', () => {
|
|
252
587
|
const files: ProjectFiles = {
|
|
253
588
|
formulas: {},
|
|
@@ -300,4 +635,55 @@ describe('fix invalidStyleSyntaxRule', () => {
|
|
|
300
635
|
}
|
|
301
636
|
`)
|
|
302
637
|
})
|
|
638
|
+
|
|
639
|
+
test('should remove a variant style property with formula syntax', () => {
|
|
640
|
+
const files: ProjectFiles = {
|
|
641
|
+
formulas: {},
|
|
642
|
+
components: {
|
|
643
|
+
test: {
|
|
644
|
+
name: 'test',
|
|
645
|
+
nodes: {
|
|
646
|
+
root: {
|
|
647
|
+
tag: 'div',
|
|
648
|
+
type: 'element',
|
|
649
|
+
attrs: {},
|
|
650
|
+
style: {},
|
|
651
|
+
events: {},
|
|
652
|
+
classes: {},
|
|
653
|
+
children: [],
|
|
654
|
+
variants: [
|
|
655
|
+
{
|
|
656
|
+
style: {
|
|
657
|
+
width: '100px',
|
|
658
|
+
transform: 'translateX(Variables.offsetX)',
|
|
659
|
+
height: '50px',
|
|
660
|
+
color: 'Event.color',
|
|
661
|
+
},
|
|
662
|
+
hover: true,
|
|
663
|
+
},
|
|
664
|
+
],
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
formulas: {},
|
|
668
|
+
apis: {},
|
|
669
|
+
attributes: {},
|
|
670
|
+
variables: {},
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
}
|
|
674
|
+
const fixedFiles = fixProject({
|
|
675
|
+
files,
|
|
676
|
+
rule: invalidStyleSyntaxRule,
|
|
677
|
+
fixType: 'delete-style-property',
|
|
678
|
+
})
|
|
679
|
+
expect(
|
|
680
|
+
(fixedFiles.components.test!.nodes?.root as ElementNodeModel)
|
|
681
|
+
.variants?.[0].style,
|
|
682
|
+
).toMatchInlineSnapshot(`
|
|
683
|
+
{
|
|
684
|
+
"height": "50px",
|
|
685
|
+
"width": "100px",
|
|
686
|
+
}
|
|
687
|
+
`)
|
|
688
|
+
})
|
|
303
689
|
})
|
|
@@ -12,6 +12,27 @@ export const invalidStyleSyntaxRule: Rule<{
|
|
|
12
12
|
if (nodeType !== 'style-declaration') {
|
|
13
13
|
return
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
// Check for variable/formula references: Variables., Formulas., Event., Attributes., Apis., Parameters., ListItem., URLParameters.
|
|
17
|
+
if (typeof value.styleValue === 'string') {
|
|
18
|
+
const hasVariableReference =
|
|
19
|
+
/\b(Variables|Formulas|Event|Attributes|Apis|Parameters|ListItem|URLParameters)\.\w+/i.test(
|
|
20
|
+
value.styleValue,
|
|
21
|
+
)
|
|
22
|
+
if (hasVariableReference) {
|
|
23
|
+
report({
|
|
24
|
+
path,
|
|
25
|
+
info: {
|
|
26
|
+
title: `Formulas detected in style declaration`,
|
|
27
|
+
description: `The style declaration for the property "${value.styleProperty}" contains Nordcraft formula syntax (e.g., references like "Variables.xxx", "Event.xxx", "Attributes.xxx", etc.). Formulas should not be used directly in CSS style values. Use style-variables or computed styles instead.`,
|
|
28
|
+
},
|
|
29
|
+
details: { property: value.styleProperty },
|
|
30
|
+
fixes: ['delete-style-property'],
|
|
31
|
+
})
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
15
36
|
const valid = memo(
|
|
16
37
|
`valid-style-${value.styleProperty}:${value.styleValue}`,
|
|
17
38
|
() => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { ProjectFiles } from '@nordcraft/ssr/dist/src/ssr.types'
|
|
1
2
|
import { describe, expect, test } from 'bun:test'
|
|
3
|
+
import { fixProject } from '../../../fixProject'
|
|
2
4
|
import { searchProject } from '../../../searchProject'
|
|
3
5
|
import { unknownCSSVariableRule } from './unknownCSSVariable'
|
|
4
6
|
|
|
@@ -171,7 +173,7 @@ describe('unknownCSSVariableRule', () => {
|
|
|
171
173
|
expect(problems[1].details).toEqual({ name: '--undefined-local' })
|
|
172
174
|
})
|
|
173
175
|
|
|
174
|
-
test('should
|
|
176
|
+
test('should report problem if local variable is used in parent but only defined in child', () => {
|
|
175
177
|
const problems = Array.from(
|
|
176
178
|
searchProject({
|
|
177
179
|
files: {
|
|
@@ -190,19 +192,26 @@ describe('unknownCSSVariableRule', () => {
|
|
|
190
192
|
tag: 'div',
|
|
191
193
|
type: 'element',
|
|
192
194
|
attrs: {},
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
195
|
+
style: {
|
|
196
|
+
color: 'var(--child-only-variable)',
|
|
197
|
+
},
|
|
198
|
+
events: {},
|
|
199
|
+
classes: {},
|
|
200
|
+
children: ['child'],
|
|
201
|
+
},
|
|
202
|
+
child: {
|
|
203
|
+
tag: 'div',
|
|
204
|
+
type: 'element',
|
|
205
|
+
attrs: {},
|
|
206
|
+
customProperties: {
|
|
207
|
+
'--child-only-variable': {
|
|
196
208
|
formula: {
|
|
197
209
|
type: 'value',
|
|
198
|
-
value: '
|
|
210
|
+
value: 'red',
|
|
199
211
|
},
|
|
200
|
-
category: 'spacing',
|
|
201
212
|
},
|
|
202
|
-
],
|
|
203
|
-
style: {
|
|
204
|
-
margin: 'var(--legacy-variable)',
|
|
205
213
|
},
|
|
214
|
+
style: {},
|
|
206
215
|
events: {},
|
|
207
216
|
classes: {},
|
|
208
217
|
children: [],
|
|
@@ -219,10 +228,10 @@ describe('unknownCSSVariableRule', () => {
|
|
|
219
228
|
}),
|
|
220
229
|
)
|
|
221
230
|
|
|
222
|
-
expect(problems).
|
|
231
|
+
expect(problems).toHaveLength(1)
|
|
223
232
|
})
|
|
224
233
|
|
|
225
|
-
test('should not report when
|
|
234
|
+
test('should not report when legacy style variables are used', () => {
|
|
226
235
|
const problems = Array.from(
|
|
227
236
|
searchProject({
|
|
228
237
|
files: {
|
|
@@ -241,9 +250,18 @@ describe('unknownCSSVariableRule', () => {
|
|
|
241
250
|
tag: 'div',
|
|
242
251
|
type: 'element',
|
|
243
252
|
attrs: {},
|
|
253
|
+
'style-variables': [
|
|
254
|
+
{
|
|
255
|
+
name: 'legacy-variable',
|
|
256
|
+
formula: {
|
|
257
|
+
type: 'value',
|
|
258
|
+
value: '10px',
|
|
259
|
+
},
|
|
260
|
+
category: 'spacing',
|
|
261
|
+
},
|
|
262
|
+
],
|
|
244
263
|
style: {
|
|
245
|
-
'--
|
|
246
|
-
margin: 'var(--declared-in-style)',
|
|
264
|
+
margin: 'var(--legacy-variable)',
|
|
247
265
|
},
|
|
248
266
|
events: {},
|
|
249
267
|
classes: {},
|
|
@@ -264,13 +282,14 @@ describe('unknownCSSVariableRule', () => {
|
|
|
264
282
|
expect(problems).toBeEmpty()
|
|
265
283
|
})
|
|
266
284
|
|
|
267
|
-
test('should not report when
|
|
285
|
+
test('should not report when declared in a style', () => {
|
|
268
286
|
const problems = Array.from(
|
|
269
287
|
searchProject({
|
|
270
288
|
files: {
|
|
271
289
|
themes: {
|
|
272
290
|
Default: {
|
|
273
291
|
fonts: [],
|
|
292
|
+
propertyDefinitions: {},
|
|
274
293
|
},
|
|
275
294
|
},
|
|
276
295
|
formulas: {},
|
|
@@ -283,7 +302,8 @@ describe('unknownCSSVariableRule', () => {
|
|
|
283
302
|
type: 'element',
|
|
284
303
|
attrs: {},
|
|
285
304
|
style: {
|
|
286
|
-
|
|
305
|
+
'--declared-in-style': '10px',
|
|
306
|
+
margin: 'var(--declared-in-style)',
|
|
287
307
|
},
|
|
288
308
|
events: {},
|
|
289
309
|
classes: {},
|
|
@@ -304,32 +324,26 @@ describe('unknownCSSVariableRule', () => {
|
|
|
304
324
|
expect(problems).toBeEmpty()
|
|
305
325
|
})
|
|
306
326
|
|
|
307
|
-
test('should not report
|
|
327
|
+
test('should not report when a legacy theme exists (no propertyDefinitions)', () => {
|
|
308
328
|
const problems = Array.from(
|
|
309
329
|
searchProject({
|
|
310
330
|
files: {
|
|
311
331
|
themes: {
|
|
312
332
|
Default: {
|
|
313
333
|
fonts: [],
|
|
314
|
-
propertyDefinitions: {},
|
|
315
334
|
},
|
|
316
335
|
},
|
|
317
336
|
formulas: {},
|
|
318
337
|
components: {
|
|
319
|
-
|
|
320
|
-
name: '
|
|
338
|
+
test: {
|
|
339
|
+
name: 'test',
|
|
321
340
|
nodes: {
|
|
322
341
|
root: {
|
|
323
342
|
tag: 'div',
|
|
324
343
|
type: 'element',
|
|
325
|
-
customProperties: {
|
|
326
|
-
'--variable-in-a': {
|
|
327
|
-
formula: { type: 'value', value: 'red' },
|
|
328
|
-
},
|
|
329
|
-
},
|
|
330
344
|
attrs: {},
|
|
331
345
|
style: {
|
|
332
|
-
color: 'var(--
|
|
346
|
+
color: 'var(--legacy-theme-variable)',
|
|
333
347
|
},
|
|
334
348
|
events: {},
|
|
335
349
|
classes: {},
|
|
@@ -341,32 +355,81 @@ describe('unknownCSSVariableRule', () => {
|
|
|
341
355
|
attributes: {},
|
|
342
356
|
variables: {},
|
|
343
357
|
},
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
rules: [unknownCSSVariableRule],
|
|
361
|
+
}),
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
expect(problems).toBeEmpty()
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
test('fix should add variable to theme', () => {
|
|
368
|
+
const files: ProjectFiles = {
|
|
369
|
+
themes: {
|
|
370
|
+
Default: {
|
|
371
|
+
fonts: [],
|
|
372
|
+
propertyDefinitions: {},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
formulas: {},
|
|
376
|
+
components: {
|
|
377
|
+
test: {
|
|
378
|
+
name: 'test',
|
|
379
|
+
nodes: {
|
|
380
|
+
root: {
|
|
381
|
+
tag: 'div',
|
|
382
|
+
type: 'element',
|
|
383
|
+
attrs: {},
|
|
384
|
+
style: {
|
|
385
|
+
color: 'var(--new-theme-variable)',
|
|
358
386
|
},
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
variables: {},
|
|
387
|
+
events: {},
|
|
388
|
+
classes: {},
|
|
389
|
+
children: [],
|
|
363
390
|
},
|
|
364
391
|
},
|
|
392
|
+
formulas: {},
|
|
393
|
+
apis: {},
|
|
394
|
+
attributes: {},
|
|
395
|
+
variables: {},
|
|
365
396
|
},
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
const problems = Array.from(
|
|
400
|
+
searchProject({
|
|
401
|
+
files,
|
|
366
402
|
rules: [unknownCSSVariableRule],
|
|
367
403
|
}),
|
|
368
404
|
)
|
|
369
405
|
|
|
370
|
-
expect(problems).
|
|
406
|
+
expect(problems).toHaveLength(1)
|
|
407
|
+
|
|
408
|
+
const fixedProject = fixProject({
|
|
409
|
+
files,
|
|
410
|
+
rule: unknownCSSVariableRule,
|
|
411
|
+
fixType: 'add-to-theme',
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
expect(
|
|
415
|
+
Object.keys(fixedProject.themes?.Default.propertyDefinitions ?? {}),
|
|
416
|
+
).toHaveLength(1)
|
|
417
|
+
expect(fixedProject.themes?.Default.propertyDefinitions).toHaveProperty(
|
|
418
|
+
'--new-theme-variable',
|
|
419
|
+
)
|
|
420
|
+
expect(
|
|
421
|
+
fixedProject.themes?.Default.propertyDefinitions?.[
|
|
422
|
+
'--new-theme-variable'
|
|
423
|
+
],
|
|
424
|
+
).toEqual({
|
|
425
|
+
syntax: {
|
|
426
|
+
type: 'primitive',
|
|
427
|
+
name: '*',
|
|
428
|
+
},
|
|
429
|
+
inherits: true,
|
|
430
|
+
initialValue: '',
|
|
431
|
+
values: {},
|
|
432
|
+
description: '',
|
|
433
|
+
})
|
|
371
434
|
})
|
|
372
435
|
})
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CustomPropertyDefinition } from '@nordcraft/core/dist/styling/theme'
|
|
2
|
+
import type { FixFunction, Rule, StyleNode } from '../../../types'
|
|
2
3
|
|
|
3
4
|
const REGEX = /var\(\s*(--[\w-]+)/g
|
|
4
5
|
|
|
5
|
-
export const unknownCSSVariableRule: Rule<
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
export const unknownCSSVariableRule: Rule<
|
|
7
|
+
{
|
|
8
|
+
name: string
|
|
9
|
+
},
|
|
10
|
+
StyleNode
|
|
11
|
+
> = {
|
|
8
12
|
code: 'unknown css variable',
|
|
9
13
|
level: 'warning',
|
|
10
14
|
category: 'Unknown Reference',
|
|
@@ -30,69 +34,120 @@ export const unknownCSSVariableRule: Rule<{
|
|
|
30
34
|
return
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
const
|
|
34
|
-
|
|
37
|
+
const themeCssVariables = theme.propertyDefinitions
|
|
38
|
+
const [_fileType, componentName, _nodes, nodeName] = path
|
|
39
|
+
const localCssVariables = memo(
|
|
40
|
+
`component-css-variables-${componentName}-${nodeName}`,
|
|
35
41
|
() => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const vars = new Set<string>()
|
|
43
|
+
const component = files.components[componentName]
|
|
44
|
+
if (!component) {
|
|
45
|
+
return vars
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const visitVars = (nodeName: string) => {
|
|
49
|
+
const node = component?.nodes?.[nodeName]
|
|
50
|
+
if (!node) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
if (node.type === 'component' || node.type === 'element') {
|
|
55
|
+
Object.keys(node.customProperties ?? {}).forEach((varName) => {
|
|
56
|
+
vars.add(varName)
|
|
57
|
+
})
|
|
58
|
+
Object.values(node.variants ?? {}).forEach((variant) => {
|
|
59
|
+
Object.keys(variant.customProperties ?? {}).forEach((varName) => {
|
|
60
|
+
vars.add(varName)
|
|
49
61
|
})
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// Also add legacy style variables
|
|
65
|
+
if (node.type === 'element' && node['style-variables']) {
|
|
66
|
+
node['style-variables'].forEach((styleVar) => {
|
|
67
|
+
vars.add(`--${styleVar.name}`)
|
|
56
68
|
})
|
|
69
|
+
}
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
71
|
+
// Add if declared in any parent styles object
|
|
72
|
+
Object.keys(node.style ?? {}).forEach((styleKey) => {
|
|
73
|
+
if (styleKey.startsWith('--')) {
|
|
74
|
+
vars.add(styleKey)
|
|
63
75
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Object.keys(
|
|
76
|
+
})
|
|
77
|
+
Object.values(node.variants ?? {}).forEach((variant) => {
|
|
78
|
+
Object.keys(variant.style ?? {}).forEach((styleKey) => {
|
|
67
79
|
if (styleKey.startsWith('--')) {
|
|
68
|
-
|
|
80
|
+
vars.add(styleKey)
|
|
69
81
|
}
|
|
70
82
|
})
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const parent = Object.entries(component.nodes ?? {}).find(([_, n]) =>
|
|
87
|
+
n.children?.includes(nodeName),
|
|
88
|
+
)
|
|
89
|
+
if (parent) {
|
|
90
|
+
visitVars(parent[0])
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
visitVars(nodeName.toString())
|
|
95
|
+
return vars
|
|
82
96
|
},
|
|
83
97
|
)
|
|
84
98
|
|
|
85
99
|
for (const varName of vars) {
|
|
86
|
-
if (
|
|
100
|
+
if (!(varName in themeCssVariables) && !localCssVariables.has(varName)) {
|
|
87
101
|
report({
|
|
88
102
|
path,
|
|
89
103
|
info: {
|
|
90
104
|
title: `Unknown CSS variable`,
|
|
91
|
-
description: `The CSS variable **${varName}** is not declared in any parent element or
|
|
105
|
+
description: `The CSS variable **${varName}** is not declared in any parent element or theme. CSS variables must be declared in an ancestor element or in your global theme.`,
|
|
92
106
|
},
|
|
93
107
|
details: { name: varName },
|
|
108
|
+
fixes: ['add-to-theme'],
|
|
94
109
|
})
|
|
95
110
|
}
|
|
96
111
|
}
|
|
97
112
|
},
|
|
113
|
+
fixes: {
|
|
114
|
+
'add-to-theme': addToThemeFix,
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type AddToThemeFix = 'add-to-theme'
|
|
119
|
+
|
|
120
|
+
function addToThemeFix(
|
|
121
|
+
args: Parameters<FixFunction<StyleNode, { name: string }>>[0],
|
|
122
|
+
): ReturnType<FixFunction<StyleNode, { name: string }>> {
|
|
123
|
+
const varName = args.details?.name
|
|
124
|
+
if (typeof varName !== 'string' || !args.data.files.themes?.Default) {
|
|
125
|
+
return args.data.files
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const definition: CustomPropertyDefinition = {
|
|
129
|
+
syntax: {
|
|
130
|
+
type: 'primitive',
|
|
131
|
+
name: '*',
|
|
132
|
+
},
|
|
133
|
+
inherits: true,
|
|
134
|
+
initialValue: '',
|
|
135
|
+
values: {},
|
|
136
|
+
description: '',
|
|
137
|
+
} as const
|
|
138
|
+
|
|
139
|
+
// Add the variable to the theme with Any (*) syntax type
|
|
140
|
+
return {
|
|
141
|
+
...args.data.files,
|
|
142
|
+
themes: {
|
|
143
|
+
...args.data.files.themes,
|
|
144
|
+
Default: {
|
|
145
|
+
...args.data.files.themes.Default,
|
|
146
|
+
propertyDefinitions: {
|
|
147
|
+
...args.data.files.themes.Default.propertyDefinitions,
|
|
148
|
+
[varName]: definition,
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
}
|
|
98
153
|
}
|
package/src/types.ts
CHANGED
|
@@ -52,6 +52,7 @@ import type { NoStaticNodeConditionRuleFix } from './rules/issues/logic/noStatic
|
|
|
52
52
|
import type { NoReferenceNodeRuleFix } from './rules/issues/miscellaneous/noReferenceNodeRule'
|
|
53
53
|
import type { InvalidStyleSyntaxRuleFix } from './rules/issues/style/invalidStyleSyntaxRule'
|
|
54
54
|
import type { LegacyStyleVariableRuleFix } from './rules/issues/style/legacyStyleVariableRule'
|
|
55
|
+
import type { AddToThemeFix } from './rules/issues/style/unknownCSSVariable'
|
|
55
56
|
import type { NoReferenceVariableRuleFix } from './rules/issues/variables/noReferenceVariableRule'
|
|
56
57
|
import type { NoPostNavigateActionRuleFix } from './rules/issues/workflows/noPostNavigateAction'
|
|
57
58
|
|
|
@@ -439,6 +440,7 @@ export type NodeType =
|
|
|
439
440
|
| StyleVariantNode
|
|
440
441
|
|
|
441
442
|
export type FixType =
|
|
443
|
+
| AddToThemeFix
|
|
442
444
|
| ChangeDataTypeFix
|
|
443
445
|
| DeleteFetchInputFix
|
|
444
446
|
| InvalidStyleSyntaxRuleFix
|