@nordcraft/search 1.0.89 → 1.0.90
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/actions/noReferenceProjectActionRule.js +2 -27
- package/dist/rules/issues/actions/noReferenceProjectActionRule.js.map +1 -1
- package/dist/rules/issues/actions/projectActionIsReferenced.memo.d.ts +3 -0
- package/dist/rules/issues/actions/projectActionIsReferenced.memo.js +38 -0
- package/dist/rules/issues/actions/projectActionIsReferenced.memo.js.map +1 -0
- package/dist/rules/issues/attributes/noReferenceAttributeInInstanceRule.js +2 -2
- package/dist/rules/issues/attributes/noReferenceAttributeInInstanceRule.js.map +1 -1
- package/dist/rules/issues/components/componentIsReferenced.memo.d.ts +3 -0
- package/dist/rules/issues/components/componentIsReferenced.memo.js +25 -0
- package/dist/rules/issues/components/componentIsReferenced.memo.js.map +1 -0
- package/dist/rules/issues/components/noReferenceComponentRule.d.ts +1 -3
- package/dist/rules/issues/components/noReferenceComponentRule.js +8 -26
- package/dist/rules/issues/components/noReferenceComponentRule.js.map +1 -1
- package/dist/rules/issues/formulas/noReferenceProjectFormulaRule.js +2 -85
- package/dist/rules/issues/formulas/noReferenceProjectFormulaRule.js.map +1 -1
- package/dist/rules/issues/formulas/projectFormulaIsReferenced.memo.d.ts +3 -0
- package/dist/rules/issues/formulas/projectFormulaIsReferenced.memo.js +84 -0
- package/dist/rules/issues/formulas/projectFormulaIsReferenced.memo.js.map +1 -0
- package/dist/rules/issues/miscellaneous/miscRules.index.js +2 -0
- package/dist/rules/issues/miscellaneous/miscRules.index.js.map +1 -1
- package/dist/rules/issues/miscellaneous/noReferencePackageRule.d.ts +5 -0
- package/dist/rules/issues/miscellaneous/noReferencePackageRule.js +54 -0
- package/dist/rules/issues/miscellaneous/noReferencePackageRule.js.map +1 -0
- package/dist/searchProject.js +23 -0
- package/dist/searchProject.js.map +1 -1
- package/dist/types.d.ts +10 -4
- package/package.json +3 -3
- package/src/rules/issues/actions/noReferenceProjectActionRule.ts +2 -32
- package/src/rules/issues/actions/projectActionIsReferenced.memo.ts +52 -0
- package/src/rules/issues/attributes/noReferenceAttributeInInstanceRule.ts +2 -2
- package/src/rules/issues/components/componentIsReferenced.memo.ts +39 -0
- package/src/rules/issues/components/noReferenceComponentRule.ts +10 -39
- package/src/rules/issues/formulas/noReferenceProjectFormulaRule.test.ts +33 -0
- package/src/rules/issues/formulas/noReferenceProjectFormulaRule.ts +2 -102
- package/src/rules/issues/formulas/projectFormulaIsReferenced.memo.ts +112 -0
- package/src/rules/issues/miscellaneous/miscRules.index.ts +2 -0
- package/src/rules/issues/miscellaneous/noReferencePackageRule.test.ts +289 -0
- package/src/rules/issues/miscellaneous/noReferencePackageRule.ts +72 -0
- package/src/searchProject.ts +24 -0
- package/src/types.ts +11 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ToddleComponent } from '@nordcraft/core/dist/component/ToddleComponent'
|
|
2
|
+
import {
|
|
3
|
+
isToddleFormula,
|
|
4
|
+
type Formula,
|
|
5
|
+
} from '@nordcraft/core/dist/formula/formula'
|
|
6
|
+
import { isDefined } from '@nordcraft/core/dist/utils/util'
|
|
7
|
+
import type { ProjectFiles } from '@nordcraft/ssr/dist/ssr.types'
|
|
8
|
+
import { ToddleApiService } from '@nordcraft/ssr/dist/ToddleApiService'
|
|
9
|
+
import { ToddleRoute } from '@nordcraft/ssr/dist/ToddleRoute'
|
|
10
|
+
import type { MemoFn } from '../../../types'
|
|
11
|
+
|
|
12
|
+
export const projectFormulaIsReferenced = (
|
|
13
|
+
files: Omit<ProjectFiles, 'config'> & Partial<Pick<ProjectFiles, 'config'>>,
|
|
14
|
+
memo: MemoFn,
|
|
15
|
+
) => {
|
|
16
|
+
const allUsedFormulaKeys = memo('all-used-formulas', () => {
|
|
17
|
+
const usedFormulas = new Set<string>()
|
|
18
|
+
|
|
19
|
+
// Check in all API services first, since that should be quick
|
|
20
|
+
for (const apiService of Object.values(files.services ?? {})) {
|
|
21
|
+
const service = new ToddleApiService({
|
|
22
|
+
service: apiService,
|
|
23
|
+
globalFormulas: { formulas: files.formulas, packages: files.packages },
|
|
24
|
+
})
|
|
25
|
+
const formulas = service.formulasInService()
|
|
26
|
+
for (const { path: _formulaPath, formula } of formulas) {
|
|
27
|
+
// Check if the formula is used in the formula
|
|
28
|
+
checkFormula(usedFormulas, formula)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check routes before components, since they should be quicker
|
|
33
|
+
for (const projectRoute of Object.values(files.routes ?? {})) {
|
|
34
|
+
const route = new ToddleRoute({
|
|
35
|
+
route: projectRoute,
|
|
36
|
+
globalFormulas: { formulas: files.formulas, packages: files.packages },
|
|
37
|
+
})
|
|
38
|
+
const formulas = route.formulasInRoute()
|
|
39
|
+
for (const { path: _formulaPath, formula } of formulas) {
|
|
40
|
+
// Check if the formula is used in the formula
|
|
41
|
+
checkFormula(usedFormulas, formula)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const component of Object.values(files.components)) {
|
|
46
|
+
const c = new ToddleComponent({
|
|
47
|
+
// Enforce that the component is not undefined since we're iterating
|
|
48
|
+
component: component!,
|
|
49
|
+
getComponent: (name) => files.components[name],
|
|
50
|
+
packageName: undefined,
|
|
51
|
+
globalFormulas: {
|
|
52
|
+
formulas: files.formulas,
|
|
53
|
+
packages: files.packages,
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
for (const { formula } of c.formulasInComponent()) {
|
|
57
|
+
if (formula.type === 'function') {
|
|
58
|
+
usedFormulas.add(
|
|
59
|
+
[formula.package, formula.name].filter(isDefined).join('/'),
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (const f of Object.values(files.formulas ?? {})) {
|
|
66
|
+
// Check if the formula is used in the formula
|
|
67
|
+
if (isToddleFormula(f)) {
|
|
68
|
+
const usedFormulasMinusSelf = new Set<string>()
|
|
69
|
+
checkFormula(usedFormulasMinusSelf, f.formula)
|
|
70
|
+
// Add all minus self (a formula is unused, if it's only used by itself)
|
|
71
|
+
usedFormulasMinusSelf.delete(f.name)
|
|
72
|
+
usedFormulasMinusSelf.forEach((f) => usedFormulas.add(f))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return usedFormulas
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
return (formulaName: string, packageName?: string) => {
|
|
80
|
+
return allUsedFormulaKeys.has(
|
|
81
|
+
[packageName, formulaName].filter(isDefined).join('/'),
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const checkArguments = (
|
|
87
|
+
usedFormulas: Set<string>,
|
|
88
|
+
args: {
|
|
89
|
+
formula: Formula
|
|
90
|
+
}[],
|
|
91
|
+
) => {
|
|
92
|
+
args.forEach((a) => {
|
|
93
|
+
checkFormula(usedFormulas, a.formula)
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const checkFormula = (usedFormulas: Set<string>, formula: Formula) => {
|
|
98
|
+
if (formula.type === 'function') {
|
|
99
|
+
usedFormulas.add(
|
|
100
|
+
[formula.package, formula.name].filter(isDefined).join('/'),
|
|
101
|
+
)
|
|
102
|
+
checkArguments(usedFormulas, formula.arguments ?? [])
|
|
103
|
+
} else if (
|
|
104
|
+
formula.type === 'object' ||
|
|
105
|
+
formula.type === 'array' ||
|
|
106
|
+
formula.type === 'or' ||
|
|
107
|
+
formula.type === 'and' ||
|
|
108
|
+
formula.type === 'apply'
|
|
109
|
+
) {
|
|
110
|
+
checkArguments(usedFormulas, formula.arguments ?? [])
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createStaticSizeConstraintRule } from './createStaticSizeConstraintRule'
|
|
2
2
|
import { noReferenceNodeRule } from './noReferenceNodeRule'
|
|
3
|
+
import { noReferenceProjectPackageRule } from './noReferencePackageRule'
|
|
3
4
|
import { requireExtensionRule } from './requireExtensionRule'
|
|
4
5
|
import { unknownCookieRule } from './unknownCookieRule'
|
|
5
6
|
|
|
@@ -11,4 +12,5 @@ export default [
|
|
|
11
12
|
createStaticSizeConstraintRule('svg', 100 * 1024),
|
|
12
13
|
// 50 KB is a large img element (with potential base64 encoded image)
|
|
13
14
|
createStaticSizeConstraintRule('img', 50 * 1024),
|
|
15
|
+
noReferenceProjectPackageRule,
|
|
14
16
|
]
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import type { ProjectFiles } from '@nordcraft/ssr/src/ssr.types'
|
|
2
|
+
import { describe, expect, test } from 'bun:test'
|
|
3
|
+
import { fixProject } from '../../../fixProject'
|
|
4
|
+
import { searchProject } from '../../../searchProject'
|
|
5
|
+
import { noReferenceProjectPackageRule } from './noReferencePackageRule'
|
|
6
|
+
|
|
7
|
+
describe('noReferenceProjectPackageRule', () => {
|
|
8
|
+
test('should report when no formula, actions or components from a package is used', () => {
|
|
9
|
+
const problems = Array.from(
|
|
10
|
+
searchProject({
|
|
11
|
+
files: {
|
|
12
|
+
formulas: {},
|
|
13
|
+
components: {},
|
|
14
|
+
packages: {
|
|
15
|
+
'my-pkg': {
|
|
16
|
+
manifest: { name: 'my-pkg', commit: 'abc' },
|
|
17
|
+
formulas: {
|
|
18
|
+
f1: {
|
|
19
|
+
name: 'f1',
|
|
20
|
+
exported: true,
|
|
21
|
+
arguments: [],
|
|
22
|
+
formula: { type: 'value', value: 1 },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
actions: {
|
|
26
|
+
a1: {
|
|
27
|
+
name: 'a1',
|
|
28
|
+
version: 2,
|
|
29
|
+
exported: true,
|
|
30
|
+
handler: () => {},
|
|
31
|
+
variableArguments: false,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
components: {
|
|
35
|
+
c1: {
|
|
36
|
+
name: 'c1',
|
|
37
|
+
exported: true,
|
|
38
|
+
nodes: {
|
|
39
|
+
root: {
|
|
40
|
+
type: 'element',
|
|
41
|
+
tag: 'div',
|
|
42
|
+
children: [],
|
|
43
|
+
attrs: {},
|
|
44
|
+
style: {},
|
|
45
|
+
events: {},
|
|
46
|
+
classes: {},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
rules: [noReferenceProjectPackageRule],
|
|
55
|
+
}),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
expect(problems).toHaveLength(1)
|
|
59
|
+
expect(problems[0].path).toEqual(['packages', 'my-pkg'])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('should not report if just one formula is used', () => {
|
|
63
|
+
const problems = Array.from(
|
|
64
|
+
searchProject({
|
|
65
|
+
files: {
|
|
66
|
+
formulas: {},
|
|
67
|
+
components: {
|
|
68
|
+
comp: {
|
|
69
|
+
name: 'comp',
|
|
70
|
+
nodes: {
|
|
71
|
+
root: {
|
|
72
|
+
type: 'element',
|
|
73
|
+
tag: 'div',
|
|
74
|
+
children: [],
|
|
75
|
+
attrs: {},
|
|
76
|
+
style: {},
|
|
77
|
+
events: {
|
|
78
|
+
onClick: {
|
|
79
|
+
trigger: 'click',
|
|
80
|
+
actions: [
|
|
81
|
+
{
|
|
82
|
+
type: 'SetVariable',
|
|
83
|
+
variable: 'v1',
|
|
84
|
+
data: {
|
|
85
|
+
type: 'function',
|
|
86
|
+
name: 'f1',
|
|
87
|
+
package: 'my-pkg',
|
|
88
|
+
arguments: [],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
classes: {},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
packages: {
|
|
100
|
+
'my-pkg': {
|
|
101
|
+
manifest: { name: 'my-pkg', commit: 'abc' },
|
|
102
|
+
formulas: {
|
|
103
|
+
f1: {
|
|
104
|
+
name: 'f1',
|
|
105
|
+
exported: true,
|
|
106
|
+
arguments: [],
|
|
107
|
+
formula: { type: 'value', value: 1 },
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
actions: {},
|
|
111
|
+
components: {},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
rules: [noReferenceProjectPackageRule],
|
|
116
|
+
}),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
expect(problems).toBeEmpty()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('should not report if just one action is used', () => {
|
|
123
|
+
const problems = Array.from(
|
|
124
|
+
searchProject({
|
|
125
|
+
files: {
|
|
126
|
+
formulas: {},
|
|
127
|
+
components: {
|
|
128
|
+
comp: {
|
|
129
|
+
name: 'comp',
|
|
130
|
+
nodes: {
|
|
131
|
+
root: {
|
|
132
|
+
type: 'element',
|
|
133
|
+
tag: 'button',
|
|
134
|
+
children: [],
|
|
135
|
+
attrs: {},
|
|
136
|
+
style: {},
|
|
137
|
+
events: {
|
|
138
|
+
click: {
|
|
139
|
+
trigger: 'click',
|
|
140
|
+
actions: [
|
|
141
|
+
{
|
|
142
|
+
type: 'Custom',
|
|
143
|
+
name: 'a1',
|
|
144
|
+
package: 'my-pkg',
|
|
145
|
+
arguments: [],
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
classes: {},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
packages: {
|
|
156
|
+
'my-pkg': {
|
|
157
|
+
manifest: { name: 'my-pkg', commit: 'abc' },
|
|
158
|
+
formulas: {},
|
|
159
|
+
actions: {
|
|
160
|
+
a1: {
|
|
161
|
+
name: 'a1',
|
|
162
|
+
version: 2,
|
|
163
|
+
exported: true,
|
|
164
|
+
handler: () => {},
|
|
165
|
+
variableArguments: false,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
components: {},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
rules: [noReferenceProjectPackageRule],
|
|
173
|
+
}),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
expect(problems).toHaveLength(0)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('should not report if just one component is used', () => {
|
|
180
|
+
const problems = Array.from(
|
|
181
|
+
searchProject({
|
|
182
|
+
files: {
|
|
183
|
+
formulas: {},
|
|
184
|
+
components: {
|
|
185
|
+
main: {
|
|
186
|
+
name: 'main',
|
|
187
|
+
nodes: {
|
|
188
|
+
root: {
|
|
189
|
+
type: 'component',
|
|
190
|
+
name: 'c1',
|
|
191
|
+
package: 'my-pkg',
|
|
192
|
+
attrs: {},
|
|
193
|
+
children: [],
|
|
194
|
+
events: {},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
packages: {
|
|
200
|
+
'my-pkg': {
|
|
201
|
+
manifest: { name: 'my-pkg', commit: 'abc' },
|
|
202
|
+
formulas: {},
|
|
203
|
+
actions: {},
|
|
204
|
+
components: {
|
|
205
|
+
c1: {
|
|
206
|
+
name: 'c1',
|
|
207
|
+
exported: true,
|
|
208
|
+
nodes: {
|
|
209
|
+
root: {
|
|
210
|
+
type: 'element',
|
|
211
|
+
tag: 'div',
|
|
212
|
+
children: [],
|
|
213
|
+
attrs: {},
|
|
214
|
+
style: {},
|
|
215
|
+
events: {},
|
|
216
|
+
classes: {},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
rules: [noReferenceProjectPackageRule],
|
|
225
|
+
}),
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
expect(problems).toHaveLength(0)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
test('should report when a package has no components, actions or formulas', () => {
|
|
232
|
+
const problems = Array.from(
|
|
233
|
+
searchProject({
|
|
234
|
+
files: {
|
|
235
|
+
formulas: {},
|
|
236
|
+
components: {},
|
|
237
|
+
packages: {
|
|
238
|
+
'empty-pkg': {
|
|
239
|
+
manifest: { name: 'empty-pkg', commit: 'abc' },
|
|
240
|
+
formulas: {},
|
|
241
|
+
actions: {},
|
|
242
|
+
components: {},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
rules: [noReferenceProjectPackageRule],
|
|
247
|
+
}),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
expect(problems).toHaveLength(1)
|
|
251
|
+
expect(problems[0].path).toEqual(['packages', 'empty-pkg'])
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
describe('fix noReferenceProjectPackageRule', () => {
|
|
256
|
+
test('should remove unreferenced package', () => {
|
|
257
|
+
const project: ProjectFiles = {
|
|
258
|
+
formulas: {},
|
|
259
|
+
components: {},
|
|
260
|
+
packages: {
|
|
261
|
+
'my-pkg': {
|
|
262
|
+
manifest: { name: 'my-pkg', commit: 'abc' },
|
|
263
|
+
formulas: {},
|
|
264
|
+
actions: {},
|
|
265
|
+
components: {},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const problems = Array.from(
|
|
271
|
+
searchProject({
|
|
272
|
+
files: project,
|
|
273
|
+
rules: [noReferenceProjectPackageRule],
|
|
274
|
+
}),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
expect(problems).toHaveLength(1)
|
|
278
|
+
expect(problems[0].code).toBe('no-reference project package')
|
|
279
|
+
expect(problems[0].fixes).toEqual(['uninstall-package'])
|
|
280
|
+
|
|
281
|
+
const fixedProject = fixProject({
|
|
282
|
+
files: project,
|
|
283
|
+
rule: noReferenceProjectPackageRule,
|
|
284
|
+
fixType: 'uninstall-package',
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
expect(fixedProject.packages).toEqual({})
|
|
288
|
+
})
|
|
289
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { PluginActionV2 } from '@nordcraft/core/dist/types'
|
|
2
|
+
import type { Rule } from '../../../types'
|
|
3
|
+
import { removeFromPathFix } from '../../../util/removeUnused.fix'
|
|
4
|
+
import { projectActionIsReferenced } from '../actions/projectActionIsReferenced.memo'
|
|
5
|
+
import { componentIsReferenced } from '../components/componentIsReferenced.memo'
|
|
6
|
+
import { projectFormulaIsReferenced } from '../formulas/projectFormulaIsReferenced.memo'
|
|
7
|
+
|
|
8
|
+
export const noReferenceProjectPackageRule: Rule<{ node: string }> = {
|
|
9
|
+
code: 'no-reference project package',
|
|
10
|
+
level: 'info',
|
|
11
|
+
category: 'No References',
|
|
12
|
+
visit: (report, info) => {
|
|
13
|
+
if (info.nodeType !== 'project-package') {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { files, memo, path, value, packageName } = info
|
|
18
|
+
|
|
19
|
+
const exportedFormulas = Object.entries(value.formulas ?? {}).filter(
|
|
20
|
+
([, formula]) => formula.exported,
|
|
21
|
+
)
|
|
22
|
+
if (exportedFormulas.length > 0) {
|
|
23
|
+
const projectFormulaIsReferencedFn = projectFormulaIsReferenced(
|
|
24
|
+
files,
|
|
25
|
+
memo,
|
|
26
|
+
)
|
|
27
|
+
for (const [, formula] of exportedFormulas) {
|
|
28
|
+
if (projectFormulaIsReferencedFn(formula.name, packageName)) {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const exportedActions = Object.entries(value.actions ?? {}).filter(
|
|
35
|
+
([, action]) => (action as PluginActionV2).exported,
|
|
36
|
+
)
|
|
37
|
+
if (exportedActions.length > 0) {
|
|
38
|
+
const projectActionIsReferencedFn = projectActionIsReferenced(files, memo)
|
|
39
|
+
for (const [, action] of exportedActions) {
|
|
40
|
+
if (projectActionIsReferencedFn(action.name, packageName)) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const exportedComponents = Object.entries(value.components ?? {}).filter(
|
|
47
|
+
([, component]) => component?.exported,
|
|
48
|
+
)
|
|
49
|
+
if (exportedComponents.length > 0) {
|
|
50
|
+
const componentIsReferencedFn = componentIsReferenced(files, memo)
|
|
51
|
+
for (const [, component] of exportedComponents) {
|
|
52
|
+
if (component && componentIsReferencedFn(component.name, packageName)) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
report({
|
|
59
|
+
path,
|
|
60
|
+
info: {
|
|
61
|
+
title: `Unused package`,
|
|
62
|
+
description: `Package is installed, but none of its formulas, actions, or components are used by any other part of the project. The package can safely be uninstalled.`,
|
|
63
|
+
},
|
|
64
|
+
fixes: ['uninstall-package'],
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
fixes: {
|
|
68
|
+
'uninstall-package': removeFromPathFix,
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type NoReferenceProjectPackageRuleFix = 'uninstall-package'
|
package/src/searchProject.ts
CHANGED
|
@@ -210,6 +210,29 @@ export function* searchProject({
|
|
|
210
210
|
state,
|
|
211
211
|
fixOptions: fixOptions as any,
|
|
212
212
|
})
|
|
213
|
+
|
|
214
|
+
if (files.packages) {
|
|
215
|
+
for (const key in files.packages) {
|
|
216
|
+
const pkg = files.packages[key]
|
|
217
|
+
if (pkg) {
|
|
218
|
+
yield* visitNode({
|
|
219
|
+
args: {
|
|
220
|
+
nodeType: 'project-package',
|
|
221
|
+
value: pkg,
|
|
222
|
+
packageName: key,
|
|
223
|
+
path: ['packages', key],
|
|
224
|
+
rules,
|
|
225
|
+
files,
|
|
226
|
+
pathsToVisit,
|
|
227
|
+
useExactPaths,
|
|
228
|
+
memo,
|
|
229
|
+
},
|
|
230
|
+
state,
|
|
231
|
+
fixOptions: fixOptions as any,
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
213
236
|
}
|
|
214
237
|
|
|
215
238
|
function visitNode(args: {
|
|
@@ -345,6 +368,7 @@ function* visitNode({
|
|
|
345
368
|
case 'project-config':
|
|
346
369
|
case 'project-theme':
|
|
347
370
|
case 'project-theme-property':
|
|
371
|
+
case 'project-package':
|
|
348
372
|
case 'style-declaration':
|
|
349
373
|
case 'style-variable':
|
|
350
374
|
case 'style-variant':
|
package/src/types.ts
CHANGED
|
@@ -27,6 +27,7 @@ import type { StyleVariant } from '@nordcraft/core/dist/styling/variantSelector'
|
|
|
27
27
|
import type { Nullable, PluginAction } from '@nordcraft/core/dist/types'
|
|
28
28
|
import type {
|
|
29
29
|
ApiService,
|
|
30
|
+
InstalledPackage,
|
|
30
31
|
ProjectFiles,
|
|
31
32
|
Route,
|
|
32
33
|
ToddleProject,
|
|
@@ -50,6 +51,7 @@ import type { NoReferenceComponentFormulaRuleFix } from './rules/issues/formulas
|
|
|
50
51
|
import type { NoReferenceProjectFormulaRuleFix } from './rules/issues/formulas/noReferenceProjectFormulaRule'
|
|
51
52
|
import type { NoStaticNodeConditionRuleFix } from './rules/issues/logic/noStaticNodeCondition'
|
|
52
53
|
import type { NoReferenceNodeRuleFix } from './rules/issues/miscellaneous/noReferenceNodeRule'
|
|
54
|
+
import type { NoReferenceProjectPackageRuleFix } from './rules/issues/miscellaneous/noReferencePackageRule'
|
|
53
55
|
import type { InvalidStyleSyntaxRuleFix } from './rules/issues/style/invalidStyleSyntaxRule'
|
|
54
56
|
import type { LegacyStyleVariableRuleFix } from './rules/issues/style/legacyStyleVariableRule'
|
|
55
57
|
import type { AddToThemeFix } from './rules/issues/style/unknownCSSVariable'
|
|
@@ -91,6 +93,7 @@ export type Code =
|
|
|
91
93
|
| 'no-reference node'
|
|
92
94
|
| 'no-reference project action'
|
|
93
95
|
| 'no-reference project formula'
|
|
96
|
+
| 'no-reference project package'
|
|
94
97
|
| 'no-reference variable'
|
|
95
98
|
| 'no-static-node-condition'
|
|
96
99
|
| 'no-unnecessary-condition-falsy'
|
|
@@ -376,6 +379,12 @@ export type ProjectConfigNode = {
|
|
|
376
379
|
value: unknown
|
|
377
380
|
} & Base
|
|
378
381
|
|
|
382
|
+
export type ProjectPackageNode = {
|
|
383
|
+
nodeType: 'project-package'
|
|
384
|
+
value: InstalledPackage
|
|
385
|
+
packageName: string
|
|
386
|
+
} & Base
|
|
387
|
+
|
|
379
388
|
export type StyleVariantNode = {
|
|
380
389
|
nodeType: 'style-variant'
|
|
381
390
|
value: {
|
|
@@ -435,6 +444,7 @@ export type NodeType =
|
|
|
435
444
|
| ProjectRoute
|
|
436
445
|
| ProjectThemeNode
|
|
437
446
|
| ProjectThemePropertyNode
|
|
447
|
+
| ProjectPackageNode
|
|
438
448
|
| StyleNode
|
|
439
449
|
| StyleVariableNode
|
|
440
450
|
| StyleVariantNode
|
|
@@ -463,6 +473,7 @@ export type FixType =
|
|
|
463
473
|
| UnknownActionEventRuleFix
|
|
464
474
|
| UnknownApiServiceRuleFix
|
|
465
475
|
| UnknownComponentAttributeRuleFix
|
|
476
|
+
| NoReferenceProjectPackageRuleFix
|
|
466
477
|
|
|
467
478
|
interface ReportedIssueInfo {
|
|
468
479
|
title: string
|