@nordcraft/search 1.0.44 → 1.0.45
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/problems.worker.js +4 -2
- package/dist/problems.worker.js.map +1 -1
- package/dist/rules/actions/legacyActionRule.test.js +3 -3
- package/dist/rules/actions/legacyActionRule.test.js.map +1 -1
- package/dist/rules/events/duplicateEventTriggerRule.js +2 -1
- package/dist/rules/events/duplicateEventTriggerRule.js.map +1 -1
- package/dist/rules/noReferenceNodeRule.js +22 -0
- package/dist/rules/noReferenceNodeRule.js.map +1 -0
- package/dist/rules/noReferenceNodeRule.test.js +131 -0
- package/dist/rules/noReferenceNodeRule.test.js.map +1 -0
- package/dist/rules/style/invalidStyleSyntaxRule.js +28 -0
- package/dist/rules/style/invalidStyleSyntaxRule.js.map +1 -0
- package/dist/rules/style/invalidStyleSyntaxRule.test.js +100 -0
- package/dist/rules/style/invalidStyleSyntaxRule.test.js.map +1 -0
- package/dist/searchProject.js +22 -1
- package/dist/searchProject.js.map +1 -1
- package/package.json +4 -3
- package/src/problems.worker.ts +4 -2
- package/src/rules/actions/legacyActionRule.test.ts +3 -3
- package/src/rules/events/duplicateEventTriggerRule.ts +2 -1
- package/src/rules/noReferenceNodeRule.test.ts +140 -0
- package/src/rules/noReferenceNodeRule.ts +27 -0
- package/src/rules/style/invalidStyleSyntaxRule.test.ts +106 -0
- package/src/rules/style/invalidStyleSyntaxRule.ts +35 -0
- package/src/searchProject.ts +25 -1
- package/src/types.d.ts +17 -2
- package/dist/memos/getAllCustomPropertiesBySyntax.js +0 -43
- package/dist/memos/getAllCustomPropertiesBySyntax.js.map +0 -1
- package/dist/rules/style-variables/ambiguousStyleVariableSyntaxRule.js +0 -50
- package/dist/rules/style-variables/ambiguousStyleVariableSyntaxRule.js.map +0 -1
- package/dist/rules/style-variables/ambiguousStyleVariableSyntaxRule.test.js +0 -265
- package/dist/rules/style-variables/ambiguousStyleVariableSyntaxRule.test.js.map +0 -1
- package/src/memos/getAllCustomPropertiesBySyntax.ts +0 -68
- package/src/rules/style-variables/ambiguousStyleVariableSyntaxRule.test.ts +0 -278
- package/src/rules/style-variables/ambiguousStyleVariableSyntaxRule.ts +0 -65
|
@@ -197,7 +197,7 @@ describe('fix legacyActions', () => {
|
|
|
197
197
|
})
|
|
198
198
|
const fixedAction = (
|
|
199
199
|
fixedProject.components['apiComponent']?.nodes['root'] as ElementNodeModel
|
|
200
|
-
).events['click']
|
|
200
|
+
).events['click']?.actions[0]
|
|
201
201
|
expect(fixedAction).toMatchInlineSnapshot(`
|
|
202
202
|
{
|
|
203
203
|
"cases": [
|
|
@@ -321,7 +321,7 @@ describe('fix legacyActions', () => {
|
|
|
321
321
|
})
|
|
322
322
|
const fixedAction = (
|
|
323
323
|
fixedProject.components['apiComponent']?.nodes['root'] as ElementNodeModel
|
|
324
|
-
).events['click']
|
|
324
|
+
).events['click']?.actions[0]
|
|
325
325
|
expect(fixedAction).toMatchInlineSnapshot(`
|
|
326
326
|
{
|
|
327
327
|
"data": {
|
|
@@ -378,7 +378,7 @@ describe('fix legacyActions', () => {
|
|
|
378
378
|
})
|
|
379
379
|
const fixedAction = (
|
|
380
380
|
fixedProject.components['apiComponent']?.nodes['root'] as ElementNodeModel
|
|
381
|
-
).events['click']
|
|
381
|
+
).events['click']?.actions[0]
|
|
382
382
|
expect(fixedAction).toMatchInlineSnapshot(`
|
|
383
383
|
{
|
|
384
384
|
"arguments": [
|
|
@@ -10,8 +10,9 @@ export const duplicateEventTriggerRule: Rule<{ trigger: string }> = {
|
|
|
10
10
|
}
|
|
11
11
|
const eventTriggers = new Set<string>()
|
|
12
12
|
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
13
14
|
Object.entries(value.events ?? {}).forEach(([key, event]) => {
|
|
14
|
-
if (typeof event
|
|
15
|
+
if (typeof event?.trigger !== 'string') {
|
|
15
16
|
return
|
|
16
17
|
}
|
|
17
18
|
if (eventTriggers.has(event.trigger)) {
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { ProjectFiles } from '@nordcraft/ssr/dist/ssr.types'
|
|
2
|
+
import { describe, expect, test } from 'bun:test'
|
|
3
|
+
import { fixProject } from '../fixProject'
|
|
4
|
+
import { searchProject } from '../searchProject'
|
|
5
|
+
import { noReferenceNodeRule } from './noReferenceNodeRule'
|
|
6
|
+
|
|
7
|
+
describe('find noReferenceNodeRule', () => {
|
|
8
|
+
test('should detect nodes with no references', () => {
|
|
9
|
+
const problems = Array.from(
|
|
10
|
+
searchProject({
|
|
11
|
+
files: {
|
|
12
|
+
formulas: {},
|
|
13
|
+
components: {
|
|
14
|
+
test: {
|
|
15
|
+
name: 'test',
|
|
16
|
+
nodes: {
|
|
17
|
+
root: {
|
|
18
|
+
id: 'root',
|
|
19
|
+
type: 'element',
|
|
20
|
+
tag: 'div',
|
|
21
|
+
children: [],
|
|
22
|
+
attrs: {},
|
|
23
|
+
style: {},
|
|
24
|
+
events: {},
|
|
25
|
+
classes: {},
|
|
26
|
+
},
|
|
27
|
+
'1LisbD0eCjsuccoUwajn1': {
|
|
28
|
+
id: 'XdhwPGsdFNI4s8A0oMwre',
|
|
29
|
+
type: 'text',
|
|
30
|
+
value: { type: 'value', value: 'Clone the project' },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
formulas: {},
|
|
34
|
+
apis: {},
|
|
35
|
+
attributes: {},
|
|
36
|
+
variables: {},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
rules: [noReferenceNodeRule],
|
|
41
|
+
}),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
expect(problems).toHaveLength(1)
|
|
45
|
+
expect(problems[0].details).toEqual({ node: '1LisbD0eCjsuccoUwajn1' })
|
|
46
|
+
expect(problems[0].path).toEqual([
|
|
47
|
+
'components',
|
|
48
|
+
'test',
|
|
49
|
+
'nodes',
|
|
50
|
+
'1LisbD0eCjsuccoUwajn1',
|
|
51
|
+
])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('should not detect nodes with references', () => {
|
|
55
|
+
const problems = Array.from(
|
|
56
|
+
searchProject({
|
|
57
|
+
files: {
|
|
58
|
+
formulas: {},
|
|
59
|
+
components: {
|
|
60
|
+
test: {
|
|
61
|
+
name: 'test',
|
|
62
|
+
nodes: {
|
|
63
|
+
root: {
|
|
64
|
+
id: 'root',
|
|
65
|
+
type: 'element',
|
|
66
|
+
tag: 'div',
|
|
67
|
+
children: ['1LisbD0eCjsuccoUwajn1'],
|
|
68
|
+
attrs: {},
|
|
69
|
+
style: {},
|
|
70
|
+
events: {},
|
|
71
|
+
classes: {},
|
|
72
|
+
},
|
|
73
|
+
'1LisbD0eCjsuccoUwajn1': {
|
|
74
|
+
id: 'XdhwPGsdFNI4s8A0oMwre',
|
|
75
|
+
type: 'text',
|
|
76
|
+
value: { type: 'value', value: 'Clone the project' },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
formulas: {},
|
|
80
|
+
apis: {},
|
|
81
|
+
attributes: {},
|
|
82
|
+
variables: {},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
rules: [noReferenceNodeRule],
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
expect(problems).toEqual([])
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('fix noReferenceNodeRule', () => {
|
|
95
|
+
test('should delete nodes with no references', () => {
|
|
96
|
+
const files: ProjectFiles = {
|
|
97
|
+
formulas: {},
|
|
98
|
+
components: {
|
|
99
|
+
test: {
|
|
100
|
+
name: 'test',
|
|
101
|
+
nodes: {
|
|
102
|
+
root: {
|
|
103
|
+
id: 'root',
|
|
104
|
+
type: 'element',
|
|
105
|
+
tag: 'div',
|
|
106
|
+
children: ['used'],
|
|
107
|
+
attrs: {},
|
|
108
|
+
style: {},
|
|
109
|
+
events: {},
|
|
110
|
+
classes: {},
|
|
111
|
+
},
|
|
112
|
+
'1LisbD0eCjsuccoUwajn1': {
|
|
113
|
+
id: 'XdhwPGsdFNI4s8A0oMwre',
|
|
114
|
+
type: 'text',
|
|
115
|
+
value: { type: 'value', value: 'Clone the project' },
|
|
116
|
+
},
|
|
117
|
+
used: {
|
|
118
|
+
id: 'used',
|
|
119
|
+
type: 'text',
|
|
120
|
+
value: { type: 'value', value: 'I am used' },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
formulas: {},
|
|
124
|
+
apis: {},
|
|
125
|
+
attributes: {},
|
|
126
|
+
variables: {},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
const fixedFiles = fixProject({
|
|
131
|
+
files,
|
|
132
|
+
rule: noReferenceNodeRule,
|
|
133
|
+
fixType: 'delete orphan node',
|
|
134
|
+
})
|
|
135
|
+
expect(Object.keys(fixedFiles.components.test!.nodes)).toEqual([
|
|
136
|
+
'root',
|
|
137
|
+
'used',
|
|
138
|
+
])
|
|
139
|
+
})
|
|
140
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Rule } from '../types'
|
|
2
|
+
import { removeFromPathFix } from '../util/removeUnused.fix'
|
|
3
|
+
|
|
4
|
+
export const noReferenceNodeRule: Rule<{ node: string }> = {
|
|
5
|
+
code: 'no-reference node',
|
|
6
|
+
level: 'warning',
|
|
7
|
+
category: 'No References',
|
|
8
|
+
visit: (report, args) => {
|
|
9
|
+
if (args.nodeType !== 'component') {
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
const { path, value: component } = args
|
|
13
|
+
const referencedNodes = new Set(
|
|
14
|
+
Object.values(component.nodes).flatMap((node) => node.children ?? []),
|
|
15
|
+
)
|
|
16
|
+
for (const key of Object.keys(component.nodes)) {
|
|
17
|
+
if (key !== 'root' && !referencedNodes.has(key)) {
|
|
18
|
+
report([...path, 'nodes', key], { node: key }, ['delete orphan node'])
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
fixes: {
|
|
23
|
+
'delete orphan node': removeFromPathFix,
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type NoReferenceNodeRuleFix = 'delete orphan node'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ElementNodeModel } from '@nordcraft/core/dist/component/component.types'
|
|
2
|
+
import type { ProjectFiles } from '@nordcraft/ssr/dist/ssr.types'
|
|
3
|
+
import { describe, expect, test } from 'bun:test'
|
|
4
|
+
import { fixProject } from '../../fixProject'
|
|
5
|
+
import { searchProject } from '../../searchProject'
|
|
6
|
+
import { invalidStyleSyntaxRule } from './invalidStyleSyntaxRule'
|
|
7
|
+
|
|
8
|
+
describe('find invalidStyleSyntaxRule', () => {
|
|
9
|
+
test('should find invalid style syntax', () => {
|
|
10
|
+
const problems = Array.from(
|
|
11
|
+
searchProject({
|
|
12
|
+
files: {
|
|
13
|
+
formulas: {},
|
|
14
|
+
components: {
|
|
15
|
+
test: {
|
|
16
|
+
name: 'test',
|
|
17
|
+
nodes: {
|
|
18
|
+
root: {
|
|
19
|
+
tag: 'ul',
|
|
20
|
+
type: 'element',
|
|
21
|
+
attrs: {},
|
|
22
|
+
style: {
|
|
23
|
+
gap: '8px',
|
|
24
|
+
width: '100%',
|
|
25
|
+
'max-width': 'calc(NOT VALID',
|
|
26
|
+
height: '/* 100px */ 22px',
|
|
27
|
+
'{': '100px',
|
|
28
|
+
'border-width': '--my-var',
|
|
29
|
+
},
|
|
30
|
+
events: {},
|
|
31
|
+
classes: {},
|
|
32
|
+
children: [],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
formulas: {},
|
|
36
|
+
apis: {},
|
|
37
|
+
attributes: {},
|
|
38
|
+
variables: {},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
rules: [invalidStyleSyntaxRule],
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
expect(problems).toHaveLength(2)
|
|
47
|
+
expect(problems[0].code).toBe('invalid style syntax')
|
|
48
|
+
expect(problems[0].path).toEqual([
|
|
49
|
+
'components',
|
|
50
|
+
'test',
|
|
51
|
+
'nodes',
|
|
52
|
+
'root',
|
|
53
|
+
'style',
|
|
54
|
+
'max-width',
|
|
55
|
+
])
|
|
56
|
+
expect(problems[0].details.property).toBe('max-width')
|
|
57
|
+
expect(problems[1].details.property).toBe('{')
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('fix invalidStyleSyntaxRule', () => {
|
|
62
|
+
test('should remove an invalid style property', () => {
|
|
63
|
+
const files: ProjectFiles = {
|
|
64
|
+
formulas: {},
|
|
65
|
+
components: {
|
|
66
|
+
test: {
|
|
67
|
+
name: 'test',
|
|
68
|
+
nodes: {
|
|
69
|
+
root: {
|
|
70
|
+
tag: 'ul',
|
|
71
|
+
type: 'element',
|
|
72
|
+
attrs: {},
|
|
73
|
+
style: {
|
|
74
|
+
gap: '8px',
|
|
75
|
+
width: '100%',
|
|
76
|
+
'max-width': 'calc(NOT VALID',
|
|
77
|
+
height: '/* 100px */ 22px',
|
|
78
|
+
'{': '100px',
|
|
79
|
+
},
|
|
80
|
+
events: {},
|
|
81
|
+
classes: {},
|
|
82
|
+
children: [],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
formulas: {},
|
|
86
|
+
apis: {},
|
|
87
|
+
attributes: {},
|
|
88
|
+
variables: {},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
const fixedFiles = fixProject({
|
|
93
|
+
files,
|
|
94
|
+
rule: invalidStyleSyntaxRule,
|
|
95
|
+
fixType: 'delete style property',
|
|
96
|
+
})
|
|
97
|
+
expect((fixedFiles.components.test!.nodes.root as ElementNodeModel).style)
|
|
98
|
+
.toMatchInlineSnapshot(`
|
|
99
|
+
{
|
|
100
|
+
"gap": "8px",
|
|
101
|
+
"height": "/* 100px */ 22px",
|
|
102
|
+
"width": "100%",
|
|
103
|
+
}
|
|
104
|
+
`)
|
|
105
|
+
})
|
|
106
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { parse } from 'postcss'
|
|
2
|
+
import type { Rule } from '../../types'
|
|
3
|
+
import { removeFromPathFix } from '../../util/removeUnused.fix'
|
|
4
|
+
|
|
5
|
+
export const invalidStyleSyntaxRule: Rule<{
|
|
6
|
+
property: string
|
|
7
|
+
}> = {
|
|
8
|
+
code: 'invalid style syntax',
|
|
9
|
+
level: 'error',
|
|
10
|
+
category: 'Quality',
|
|
11
|
+
visit: (report, { nodeType, value, path, memo }) => {
|
|
12
|
+
if (nodeType !== 'style-declaration') {
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
const valid = memo(
|
|
16
|
+
`valid-style-${value.styleProperty}:${value.styleValue}`,
|
|
17
|
+
() => {
|
|
18
|
+
try {
|
|
19
|
+
parse(`${value.styleProperty}: ${value.styleValue}`)
|
|
20
|
+
return true
|
|
21
|
+
} catch {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
if (!valid) {
|
|
27
|
+
report(path, { property: value.styleProperty }, ['delete style property'])
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
fixes: {
|
|
31
|
+
'delete style property': removeFromPathFix,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type InvalidStyleSyntaxRuleFix = 'delete style property'
|
package/src/searchProject.ts
CHANGED
|
@@ -262,7 +262,12 @@ function* visitNode({
|
|
|
262
262
|
// The rule must have an implementation for the fix
|
|
263
263
|
rule.fixes?.[fixOptions.fixType]
|
|
264
264
|
) {
|
|
265
|
-
const ruleFixes = rule.fixes[fixOptions.fixType]?.(
|
|
265
|
+
const ruleFixes = rule.fixes[fixOptions.fixType]?.(
|
|
266
|
+
// We must use the path from the report, not the original path
|
|
267
|
+
// because the report might be for a subpath
|
|
268
|
+
{ ...data, path },
|
|
269
|
+
state,
|
|
270
|
+
)
|
|
266
271
|
if (ruleFixes) {
|
|
267
272
|
fixedFiles = ruleFixes
|
|
268
273
|
}
|
|
@@ -571,6 +576,25 @@ function* visitNode({
|
|
|
571
576
|
})
|
|
572
577
|
}
|
|
573
578
|
}
|
|
579
|
+
for (const [styleKey, styleValue] of Object.entries(
|
|
580
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
581
|
+
value.style ?? {},
|
|
582
|
+
)) {
|
|
583
|
+
yield* visitNode({
|
|
584
|
+
args: {
|
|
585
|
+
nodeType: 'style-declaration',
|
|
586
|
+
value: { styleProperty: styleKey, styleValue, element: value },
|
|
587
|
+
path: [...path, 'style', styleKey],
|
|
588
|
+
rules,
|
|
589
|
+
files,
|
|
590
|
+
pathsToVisit,
|
|
591
|
+
useExactPaths,
|
|
592
|
+
memo,
|
|
593
|
+
},
|
|
594
|
+
state,
|
|
595
|
+
fixOptions: fixOptions as any,
|
|
596
|
+
})
|
|
597
|
+
}
|
|
574
598
|
}
|
|
575
599
|
break
|
|
576
600
|
|
package/src/types.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ import type { ToddleComponent } from '@nordcraft/core/dist/component/ToddleCompo
|
|
|
14
14
|
import type { Formula } from '@nordcraft/core/dist/formula/formula'
|
|
15
15
|
import type { PluginFormula } from '@nordcraft/core/dist/formula/formulaTypes'
|
|
16
16
|
import type { Theme } from '@nordcraft/core/dist/styling/theme'
|
|
17
|
+
import type { PluginAction } from '@nordcraft/core/dist/types'
|
|
17
18
|
import type {
|
|
18
19
|
ApiService,
|
|
19
|
-
PluginAction,
|
|
20
20
|
ProjectFiles,
|
|
21
21
|
Route,
|
|
22
22
|
ToddleProject,
|
|
@@ -30,9 +30,10 @@ import type { NoReferenceEventRuleFix } from './rules/events/noReferenceEventRul
|
|
|
30
30
|
import type { LegacyFormulaRuleFix } from './rules/formulas/legacyFormulaRule'
|
|
31
31
|
import type { NoReferenceComponentFormulaRuleFix } from './rules/formulas/noReferenceComponentFormulaRule'
|
|
32
32
|
import type { NoReferenceProjectFormulaRuleFix } from './rules/formulas/noReferenceProjectFormulaRule'
|
|
33
|
+
import type { NoReferenceNodeRuleFix } from './rules/noReferenceNodeRule'
|
|
34
|
+
import type { InvalidStyleSyntaxRuleFix } from './rules/style/invalidStyleSyntaxRule'
|
|
33
35
|
|
|
34
36
|
type Code =
|
|
35
|
-
| 'ambiguous style variable syntax'
|
|
36
37
|
| 'duplicate event trigger'
|
|
37
38
|
| 'duplicate url parameter'
|
|
38
39
|
| 'duplicate workflow parameter'
|
|
@@ -40,6 +41,7 @@ type Code =
|
|
|
40
41
|
| 'invalid api parser mode'
|
|
41
42
|
| 'invalid api proxy body setting'
|
|
42
43
|
| 'invalid element child'
|
|
44
|
+
| 'invalid style syntax'
|
|
43
45
|
| 'legacy action'
|
|
44
46
|
| 'legacy api'
|
|
45
47
|
| 'legacy formula'
|
|
@@ -53,6 +55,7 @@ type Code =
|
|
|
53
55
|
| 'no-reference component workflow'
|
|
54
56
|
| 'no-reference component'
|
|
55
57
|
| 'no-reference event'
|
|
58
|
+
| 'no-reference node'
|
|
56
59
|
| 'no-reference project action'
|
|
57
60
|
| 'no-reference project formula'
|
|
58
61
|
| 'no-reference variable'
|
|
@@ -297,6 +300,15 @@ type StyleVariantNode = {
|
|
|
297
300
|
value: { variant: StyleVariant; element: ElementNodeModel }
|
|
298
301
|
} & Base
|
|
299
302
|
|
|
303
|
+
type StyleNode = {
|
|
304
|
+
nodeType: 'style-declaration'
|
|
305
|
+
value: {
|
|
306
|
+
styleProperty: string
|
|
307
|
+
styleValue: string
|
|
308
|
+
element: ElementNodeModel
|
|
309
|
+
}
|
|
310
|
+
} & Base
|
|
311
|
+
|
|
300
312
|
export type NodeType =
|
|
301
313
|
| ActionModelNode
|
|
302
314
|
| ComponentAPIInputNode
|
|
@@ -316,6 +328,7 @@ export type NodeType =
|
|
|
316
328
|
| ProjectFormulaNode
|
|
317
329
|
| ProjectThemeNode
|
|
318
330
|
| ProjectRoute
|
|
331
|
+
| StyleNode
|
|
319
332
|
| StyleVariantNode
|
|
320
333
|
|
|
321
334
|
type FixType =
|
|
@@ -328,6 +341,8 @@ type FixType =
|
|
|
328
341
|
| NoReferenceAttributeRuleFix
|
|
329
342
|
| NoReferenceEventRuleFix
|
|
330
343
|
| NoReferenceComponentFormulaRuleFix
|
|
344
|
+
| NoReferenceNodeRuleFix
|
|
345
|
+
| InvalidStyleSyntaxRuleFix
|
|
331
346
|
|
|
332
347
|
export interface Rule<T = unknown, V = NodeType> {
|
|
333
348
|
category: Category
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export const getAllCustomPropertiesBySyntax = (memo, { files, }) => memo('allCustomPropertiesBySyntax', () => {
|
|
2
|
-
const store = {};
|
|
3
|
-
const add = (propName, syntax, fullPath) => {
|
|
4
|
-
if (syntax.type !== 'primitive')
|
|
5
|
-
return;
|
|
6
|
-
const sName = syntax.name;
|
|
7
|
-
store[propName] ??= {};
|
|
8
|
-
store[propName][sName] ??= [];
|
|
9
|
-
store[propName][sName].push({ syntax, path: fullPath });
|
|
10
|
-
};
|
|
11
|
-
for (const [componentKey, component] of Object.entries(files.components)) {
|
|
12
|
-
for (const [nodeKey, node] of Object.entries(component?.nodes ?? {})) {
|
|
13
|
-
if (node.type !== 'element' && node.type !== 'component')
|
|
14
|
-
continue;
|
|
15
|
-
for (const [propName, prop] of Object.entries(node.customProperties ?? {})) {
|
|
16
|
-
add(propName, prop.syntax, [
|
|
17
|
-
'components',
|
|
18
|
-
componentKey,
|
|
19
|
-
'nodes',
|
|
20
|
-
nodeKey,
|
|
21
|
-
'customProperties',
|
|
22
|
-
propName,
|
|
23
|
-
]);
|
|
24
|
-
}
|
|
25
|
-
node.variants?.forEach((variant, variantIndex) => {
|
|
26
|
-
for (const [propName, prop] of Object.entries(variant.customProperties ?? {})) {
|
|
27
|
-
add(propName, prop.syntax, [
|
|
28
|
-
'components',
|
|
29
|
-
componentKey,
|
|
30
|
-
'nodes',
|
|
31
|
-
nodeKey,
|
|
32
|
-
'variants',
|
|
33
|
-
String(variantIndex),
|
|
34
|
-
'customProperties',
|
|
35
|
-
propName,
|
|
36
|
-
]);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return store;
|
|
42
|
-
});
|
|
43
|
-
//# sourceMappingURL=getAllCustomPropertiesBySyntax.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getAllCustomPropertiesBySyntax.js","sourceRoot":"","sources":["../../src/memos/getAllCustomPropertiesBySyntax.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,IAAY,EACZ,EACE,KAAK,GAGN,EACD,EAAE,CACF,IAAI,CAAC,6BAA6B,EAAE,GAAG,EAAE;IACvC,MAAM,KAAK,GAGP,EAAE,CAAA;IAEN,MAAM,GAAG,GAAG,CACV,QAAgB,EAChB,MAAqB,EACrB,QAAkB,EAClB,EAAE;QACF,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;YAAE,OAAM;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAA;QACzB,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACtB,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAC7B,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IACzD,CAAC,CAAA;IAED,KAAK,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QACzE,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;YACrE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW;gBAAE,SAAQ;YAElE,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAC3C,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAC5B,EAAE,CAAC;gBACF,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;oBACzB,YAAY;oBACZ,YAAY;oBACZ,OAAO;oBACP,OAAO;oBACP,kBAAkB;oBAClB,QAAQ;iBACT,CAAC,CAAA;YACJ,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE;gBAC/C,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAC3C,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAC/B,EAAE,CAAC;oBACF,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;wBACzB,YAAY;wBACZ,YAAY;wBACZ,OAAO;wBACP,OAAO;wBACP,UAAU;wBACV,MAAM,CAAC,YAAY,CAAC;wBACpB,kBAAkB;wBAClB,QAAQ;qBACT,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAC,CAAA"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { getAllCustomPropertiesBySyntax } from '../../memos/getAllCustomPropertiesBySyntax';
|
|
2
|
-
export const ambiguousStyleVariableSyntaxRule = {
|
|
3
|
-
code: 'ambiguous style variable syntax',
|
|
4
|
-
level: 'error',
|
|
5
|
-
category: 'Other',
|
|
6
|
-
visit: (report, args) => {
|
|
7
|
-
const { nodeType, value, files, memo, path } = args;
|
|
8
|
-
if (nodeType !== 'component-node')
|
|
9
|
-
return;
|
|
10
|
-
if (value.type !== 'element' && value.type !== 'component')
|
|
11
|
-
return;
|
|
12
|
-
const check = (propName, syntax, basePath) => {
|
|
13
|
-
if (syntax.type !== 'primitive')
|
|
14
|
-
return;
|
|
15
|
-
const allCustomPropertiesBySyntax = getAllCustomPropertiesBySyntax(memo, {
|
|
16
|
-
files,
|
|
17
|
-
})[propName];
|
|
18
|
-
const conflicts = Object.entries(allCustomPropertiesBySyntax)
|
|
19
|
-
.filter(([name]) => name !== syntax.name)
|
|
20
|
-
.flatMap(([, entries]) => entries);
|
|
21
|
-
if (conflicts.length > 0) {
|
|
22
|
-
report(basePath, {
|
|
23
|
-
name: propName,
|
|
24
|
-
duplicates: conflicts,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
for (const [propName, prop] of Object.entries(value.customProperties ?? {})) {
|
|
29
|
-
check(propName, prop.syntax, [
|
|
30
|
-
...path,
|
|
31
|
-
'customProperties',
|
|
32
|
-
propName,
|
|
33
|
-
'name',
|
|
34
|
-
]);
|
|
35
|
-
}
|
|
36
|
-
value.variants?.forEach((variant, variantIndex) => {
|
|
37
|
-
for (const [propName, prop] of Object.entries(variant.customProperties ?? {})) {
|
|
38
|
-
check(propName, prop.syntax, [
|
|
39
|
-
...path,
|
|
40
|
-
'variants',
|
|
41
|
-
String(variantIndex),
|
|
42
|
-
'customProperties',
|
|
43
|
-
propName,
|
|
44
|
-
'name',
|
|
45
|
-
]);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
//# sourceMappingURL=ambiguousStyleVariableSyntaxRule.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ambiguousStyleVariableSyntaxRule.js","sourceRoot":"","sources":["../../../src/rules/style-variables/ambiguousStyleVariableSyntaxRule.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,4CAA4C,CAAA;AAG3F,MAAM,CAAC,MAAM,gCAAgC,GAGxC;IACH,IAAI,EAAE,iCAAiC;IACvC,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,OAAO;IACjB,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QACtB,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;QACnD,IAAI,QAAQ,KAAK,gBAAgB;YAAE,OAAM;QACzC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,OAAM;QAElE,MAAM,KAAK,GAAG,CACZ,QAAgB,EAChB,MAAqB,EACrB,QAAgC,EAChC,EAAE;YACF,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;gBAAE,OAAM;YACvC,MAAM,2BAA2B,GAAG,8BAA8B,CAAC,IAAI,EAAE;gBACvE,KAAK;aACN,CAAC,CAAC,QAAQ,CAAC,CAAA;YAEZ,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,2BAA2B,CAAC;iBAC1D,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC;iBACxC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;YAEpC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,QAAQ,EAAE;oBACf,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,SAAS;iBACtB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAA;QAED,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAC3C,KAAK,CAAC,gBAAgB,IAAI,EAAE,CAC7B,EAAE,CAAC;YACF,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;gBAC3B,GAAG,IAAI;gBACP,kBAAkB;gBAClB,QAAQ;gBACR,MAAM;aACP,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE;YAChD,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAC3C,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAC/B,EAAE,CAAC;gBACF,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;oBAC3B,GAAG,IAAI;oBACP,UAAU;oBACV,MAAM,CAAC,YAAY,CAAC;oBACpB,kBAAkB;oBAClB,QAAQ;oBACR,MAAM;iBACP,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;CACF,CAAA"}
|