@nordcraft/search 1.0.39 → 1.0.41
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/actions/legacyActionRule.js +168 -2
- package/dist/rules/actions/legacyActionRule.js.map +1 -1
- package/dist/rules/actions/legacyActionRule.test.js +304 -1
- package/dist/rules/actions/legacyActionRule.test.js.map +1 -1
- package/dist/rules/formulas/legacyFormulaRule.js +5 -23
- package/dist/rules/formulas/legacyFormulaRule.js.map +1 -1
- package/dist/rules/formulas/noReferenceProjectFormulaRule.js +73 -58
- package/dist/rules/formulas/noReferenceProjectFormulaRule.js.map +1 -1
- package/dist/rules/formulas/noReferenceProjectFormulaRule.test.js +34 -1
- package/dist/rules/formulas/noReferenceProjectFormulaRule.test.js.map +1 -1
- package/dist/util/helpers.js +13 -2
- package/dist/util/helpers.js.map +1 -1
- package/package.json +2 -2
- package/src/rules/actions/legacyActionRule.test.ts +316 -1
- package/src/rules/actions/legacyActionRule.ts +191 -4
- package/src/rules/formulas/legacyFormulaRule.ts +9 -31
- package/src/rules/formulas/noReferenceProjectFormulaRule.test.ts +36 -1
- package/src/rules/formulas/noReferenceProjectFormulaRule.ts +78 -64
- package/src/types.d.ts +7 -1
- package/src/util/helpers.ts +28 -3
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActionModel,
|
|
3
|
+
ElementNodeModel,
|
|
4
|
+
} from '@nordcraft/core/dist/component/component.types'
|
|
5
|
+
import type { ProjectFiles } from '@nordcraft/ssr/dist/ssr.types'
|
|
1
6
|
import { describe, expect, test } from 'bun:test'
|
|
7
|
+
import { fixProject } from '../../fixProject'
|
|
2
8
|
import { searchProject } from '../../searchProject'
|
|
3
9
|
import { legacyActionRule } from './legacyActionRule'
|
|
4
10
|
|
|
5
|
-
describe('
|
|
11
|
+
describe('find legacyActions', () => {
|
|
6
12
|
test('should detect legacy actions used in components', () => {
|
|
7
13
|
const problems = Array.from(
|
|
8
14
|
searchProject({
|
|
@@ -90,3 +96,312 @@ describe('legacyAction', () => {
|
|
|
90
96
|
expect(problems).toHaveLength(0)
|
|
91
97
|
})
|
|
92
98
|
})
|
|
99
|
+
|
|
100
|
+
describe('fix legacyActions', () => {
|
|
101
|
+
test('should replace the If action with a Switch action', () => {
|
|
102
|
+
const legacyIfAction: ActionModel = {
|
|
103
|
+
name: 'If',
|
|
104
|
+
events: {
|
|
105
|
+
true: {
|
|
106
|
+
actions: [
|
|
107
|
+
{
|
|
108
|
+
name: '@toddle/logToConsole',
|
|
109
|
+
arguments: [
|
|
110
|
+
{
|
|
111
|
+
name: 'Label',
|
|
112
|
+
description: 'A label for the message.',
|
|
113
|
+
formula: { type: 'value', value: '' },
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'Data',
|
|
117
|
+
type: { type: 'Any' },
|
|
118
|
+
description: 'The data you want to log to the console.',
|
|
119
|
+
formula: {
|
|
120
|
+
type: 'value',
|
|
121
|
+
value: '<Data>',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
label: 'Log to console',
|
|
126
|
+
group: 'debugging',
|
|
127
|
+
description: 'Log a message to the browser console.',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
false: {
|
|
132
|
+
actions: [
|
|
133
|
+
{
|
|
134
|
+
name: '@toddle/logToConsole',
|
|
135
|
+
arguments: [
|
|
136
|
+
{
|
|
137
|
+
name: 'Label',
|
|
138
|
+
description: 'A label for the message.',
|
|
139
|
+
formula: { type: 'value', value: '' },
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'Data',
|
|
143
|
+
type: { type: 'Any' },
|
|
144
|
+
description: 'The data you want to log to the console.',
|
|
145
|
+
formula: {
|
|
146
|
+
type: 'value',
|
|
147
|
+
value: '<Data>',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
label: 'Log to console',
|
|
152
|
+
group: 'debugging',
|
|
153
|
+
description: 'Log a message to the browser console.',
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
arguments: [
|
|
159
|
+
{
|
|
160
|
+
name: 'Condition',
|
|
161
|
+
formula: { type: 'value', value: true },
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
}
|
|
165
|
+
const projectFiles: ProjectFiles = {
|
|
166
|
+
formulas: {},
|
|
167
|
+
components: {
|
|
168
|
+
apiComponent: {
|
|
169
|
+
name: 'test',
|
|
170
|
+
nodes: {
|
|
171
|
+
root: {
|
|
172
|
+
tag: 'p',
|
|
173
|
+
type: 'element',
|
|
174
|
+
attrs: {},
|
|
175
|
+
style: {},
|
|
176
|
+
events: {
|
|
177
|
+
click: {
|
|
178
|
+
trigger: 'click',
|
|
179
|
+
actions: [legacyIfAction],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
classes: {},
|
|
183
|
+
children: [],
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
formulas: {},
|
|
187
|
+
apis: {},
|
|
188
|
+
attributes: {},
|
|
189
|
+
variables: {},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
const fixedProject = fixProject({
|
|
194
|
+
files: projectFiles,
|
|
195
|
+
rule: legacyActionRule,
|
|
196
|
+
fixType: 'replace-legacy-action',
|
|
197
|
+
})
|
|
198
|
+
const fixedAction = (
|
|
199
|
+
fixedProject.components['apiComponent']?.nodes['root'] as ElementNodeModel
|
|
200
|
+
).events['click'].actions[0]
|
|
201
|
+
expect(fixedAction).toMatchInlineSnapshot(`
|
|
202
|
+
{
|
|
203
|
+
"cases": [
|
|
204
|
+
{
|
|
205
|
+
"actions": [
|
|
206
|
+
{
|
|
207
|
+
"arguments": [
|
|
208
|
+
{
|
|
209
|
+
"description": "A label for the message.",
|
|
210
|
+
"formula": {
|
|
211
|
+
"type": "value",
|
|
212
|
+
"value": "",
|
|
213
|
+
},
|
|
214
|
+
"name": "Label",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"description": "The data you want to log to the console.",
|
|
218
|
+
"formula": {
|
|
219
|
+
"type": "value",
|
|
220
|
+
"value": "<Data>",
|
|
221
|
+
},
|
|
222
|
+
"name": "Data",
|
|
223
|
+
"type": {
|
|
224
|
+
"type": "Any",
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
"description": "Log a message to the browser console.",
|
|
229
|
+
"group": "debugging",
|
|
230
|
+
"label": "Log to console",
|
|
231
|
+
"name": "@toddle/logToConsole",
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
"condition": {
|
|
235
|
+
"type": "value",
|
|
236
|
+
"value": true,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
"default": {
|
|
241
|
+
"actions": [
|
|
242
|
+
{
|
|
243
|
+
"arguments": [
|
|
244
|
+
{
|
|
245
|
+
"description": "A label for the message.",
|
|
246
|
+
"formula": {
|
|
247
|
+
"type": "value",
|
|
248
|
+
"value": "",
|
|
249
|
+
},
|
|
250
|
+
"name": "Label",
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"description": "The data you want to log to the console.",
|
|
254
|
+
"formula": {
|
|
255
|
+
"type": "value",
|
|
256
|
+
"value": "<Data>",
|
|
257
|
+
},
|
|
258
|
+
"name": "Data",
|
|
259
|
+
"type": {
|
|
260
|
+
"type": "Any",
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
"description": "Log a message to the browser console.",
|
|
265
|
+
"group": "debugging",
|
|
266
|
+
"label": "Log to console",
|
|
267
|
+
"name": "@toddle/logToConsole",
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
"type": "Switch",
|
|
272
|
+
}
|
|
273
|
+
`)
|
|
274
|
+
})
|
|
275
|
+
test('should replace the TriggerEvent action with the builtin action', () => {
|
|
276
|
+
const legacyAction: ActionModel = {
|
|
277
|
+
name: 'TriggerEvent',
|
|
278
|
+
arguments: [
|
|
279
|
+
{
|
|
280
|
+
name: 'name',
|
|
281
|
+
formula: { type: 'value', value: 'sdfsdf' },
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: 'data',
|
|
285
|
+
formula: { type: 'value', value: 'test' },
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
}
|
|
289
|
+
const projectFiles: ProjectFiles = {
|
|
290
|
+
formulas: {},
|
|
291
|
+
components: {
|
|
292
|
+
apiComponent: {
|
|
293
|
+
name: 'test',
|
|
294
|
+
nodes: {
|
|
295
|
+
root: {
|
|
296
|
+
tag: 'p',
|
|
297
|
+
type: 'element',
|
|
298
|
+
attrs: {},
|
|
299
|
+
style: {},
|
|
300
|
+
events: {
|
|
301
|
+
click: {
|
|
302
|
+
trigger: 'click',
|
|
303
|
+
actions: [legacyAction],
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
classes: {},
|
|
307
|
+
children: [],
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
formulas: {},
|
|
311
|
+
apis: {},
|
|
312
|
+
attributes: {},
|
|
313
|
+
variables: {},
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
}
|
|
317
|
+
const fixedProject = fixProject({
|
|
318
|
+
files: projectFiles,
|
|
319
|
+
rule: legacyActionRule,
|
|
320
|
+
fixType: 'replace-legacy-action',
|
|
321
|
+
})
|
|
322
|
+
const fixedAction = (
|
|
323
|
+
fixedProject.components['apiComponent']?.nodes['root'] as ElementNodeModel
|
|
324
|
+
).events['click'].actions[0]
|
|
325
|
+
expect(fixedAction).toMatchInlineSnapshot(`
|
|
326
|
+
{
|
|
327
|
+
"data": {
|
|
328
|
+
"type": "value",
|
|
329
|
+
"value": "test",
|
|
330
|
+
},
|
|
331
|
+
"event": "sdfsdf",
|
|
332
|
+
"type": "TriggerEvent",
|
|
333
|
+
}
|
|
334
|
+
`)
|
|
335
|
+
})
|
|
336
|
+
test('should replace the TriggerEvent action with the builtin action', () => {
|
|
337
|
+
const legacyAction: ActionModel = {
|
|
338
|
+
name: 'FocusElement',
|
|
339
|
+
arguments: [
|
|
340
|
+
{
|
|
341
|
+
name: 'elementId',
|
|
342
|
+
formula: { type: 'value', value: 'my-id' },
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
}
|
|
346
|
+
const projectFiles: ProjectFiles = {
|
|
347
|
+
formulas: {},
|
|
348
|
+
components: {
|
|
349
|
+
apiComponent: {
|
|
350
|
+
name: 'test',
|
|
351
|
+
nodes: {
|
|
352
|
+
root: {
|
|
353
|
+
tag: 'p',
|
|
354
|
+
type: 'element',
|
|
355
|
+
attrs: {},
|
|
356
|
+
style: {},
|
|
357
|
+
events: {
|
|
358
|
+
click: {
|
|
359
|
+
trigger: 'click',
|
|
360
|
+
actions: [legacyAction],
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
classes: {},
|
|
364
|
+
children: [],
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
formulas: {},
|
|
368
|
+
apis: {},
|
|
369
|
+
attributes: {},
|
|
370
|
+
variables: {},
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
}
|
|
374
|
+
const fixedProject = fixProject({
|
|
375
|
+
files: projectFiles,
|
|
376
|
+
rule: legacyActionRule,
|
|
377
|
+
fixType: 'replace-legacy-action',
|
|
378
|
+
})
|
|
379
|
+
const fixedAction = (
|
|
380
|
+
fixedProject.components['apiComponent']?.nodes['root'] as ElementNodeModel
|
|
381
|
+
).events['click'].actions[0]
|
|
382
|
+
expect(fixedAction).toMatchInlineSnapshot(`
|
|
383
|
+
{
|
|
384
|
+
"arguments": [
|
|
385
|
+
{
|
|
386
|
+
"formula": {
|
|
387
|
+
"arguments": [
|
|
388
|
+
{
|
|
389
|
+
"formula": {
|
|
390
|
+
"type": "value",
|
|
391
|
+
"value": "my-id",
|
|
392
|
+
},
|
|
393
|
+
"name": "Id",
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
"name": "@toddle/getElementById",
|
|
397
|
+
"type": "function",
|
|
398
|
+
},
|
|
399
|
+
"name": "Element",
|
|
400
|
+
},
|
|
401
|
+
],
|
|
402
|
+
"label": "Focus",
|
|
403
|
+
"name": "@toddle/focus",
|
|
404
|
+
}
|
|
405
|
+
`)
|
|
406
|
+
})
|
|
407
|
+
})
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActionModel,
|
|
3
|
+
CustomActionArgument,
|
|
4
|
+
} from '@nordcraft/core/dist/component/component.types'
|
|
5
|
+
import { valueFormula } from '@nordcraft/core/dist/formula/formulaUtils'
|
|
6
|
+
import { set } from '@nordcraft/core/dist/utils/collections'
|
|
1
7
|
import type { Rule } from '../../types'
|
|
2
|
-
import { isLegacyAction } from '../../util/helpers'
|
|
8
|
+
import { isLegacyAction, renameArguments } from '../../util/helpers'
|
|
3
9
|
|
|
4
10
|
export const legacyActionRule: Rule<{
|
|
5
11
|
name: string
|
|
@@ -11,7 +17,6 @@ export const legacyActionRule: Rule<{
|
|
|
11
17
|
if (nodeType !== 'action-model') {
|
|
12
18
|
return
|
|
13
19
|
}
|
|
14
|
-
|
|
15
20
|
if (isLegacyAction(value)) {
|
|
16
21
|
let details: { name: string } | undefined
|
|
17
22
|
if ('name' in value) {
|
|
@@ -19,8 +24,190 @@ export const legacyActionRule: Rule<{
|
|
|
19
24
|
name: value.name,
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
report(
|
|
28
|
+
path,
|
|
29
|
+
details,
|
|
30
|
+
unfixableLegacyActions.has(value.name)
|
|
31
|
+
? undefined
|
|
32
|
+
: !formulaNamedActions.includes(value.name) ||
|
|
33
|
+
// Check if the first argument is a value formula with a string value
|
|
34
|
+
(value.arguments?.[0].formula.type === 'value' &&
|
|
35
|
+
typeof value.arguments[0].formula.value === 'string')
|
|
36
|
+
? ['replace-legacy-action']
|
|
37
|
+
: undefined,
|
|
38
|
+
)
|
|
24
39
|
}
|
|
25
40
|
},
|
|
41
|
+
fixes: {
|
|
42
|
+
'replace-legacy-action': ({ path, value, nodeType, files }) => {
|
|
43
|
+
if (nodeType !== 'action-model') {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
if (!isLegacyAction(value)) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let newAction: ActionModel | undefined
|
|
51
|
+
switch (value.name) {
|
|
52
|
+
case 'If': {
|
|
53
|
+
const trueActions = value.events?.['true']?.actions ?? []
|
|
54
|
+
const falseActions = value.events?.['false']?.actions ?? []
|
|
55
|
+
const trueCondition: CustomActionArgument | undefined =
|
|
56
|
+
(value.arguments ?? [])[0]
|
|
57
|
+
newAction = {
|
|
58
|
+
type: 'Switch',
|
|
59
|
+
cases: [
|
|
60
|
+
{
|
|
61
|
+
condition: trueCondition?.formula ?? null,
|
|
62
|
+
actions: trueActions,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
default: { actions: falseActions },
|
|
66
|
+
}
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
case 'PreventDefault': {
|
|
70
|
+
newAction = {
|
|
71
|
+
name: '@toddle/preventDefault',
|
|
72
|
+
arguments: [],
|
|
73
|
+
label: 'Prevent default',
|
|
74
|
+
}
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
case 'StopPropagation': {
|
|
78
|
+
newAction = {
|
|
79
|
+
name: '@toddle/stopPropagation',
|
|
80
|
+
arguments: [],
|
|
81
|
+
label: 'Stop propagation',
|
|
82
|
+
}
|
|
83
|
+
break
|
|
84
|
+
}
|
|
85
|
+
case 'UpdateVariable':
|
|
86
|
+
case 'Update Variable': {
|
|
87
|
+
const variableName =
|
|
88
|
+
value.arguments?.[0]?.formula.type === 'value'
|
|
89
|
+
? value.arguments[0].formula.value
|
|
90
|
+
: undefined
|
|
91
|
+
if (typeof variableName !== 'string') {
|
|
92
|
+
break
|
|
93
|
+
}
|
|
94
|
+
const variableValue = value.arguments?.[1]?.formula
|
|
95
|
+
if (!variableValue) {
|
|
96
|
+
break
|
|
97
|
+
}
|
|
98
|
+
newAction = {
|
|
99
|
+
type: 'SetVariable',
|
|
100
|
+
variable: variableName,
|
|
101
|
+
data: variableValue,
|
|
102
|
+
}
|
|
103
|
+
break
|
|
104
|
+
}
|
|
105
|
+
case 'SetTimeout': {
|
|
106
|
+
newAction = {
|
|
107
|
+
...value,
|
|
108
|
+
name: '@toddle/sleep',
|
|
109
|
+
arguments: renameArguments(
|
|
110
|
+
{ 'Delay in ms': 'Delay in milliseconds' },
|
|
111
|
+
value.arguments,
|
|
112
|
+
),
|
|
113
|
+
events: value.events?.['timeout']
|
|
114
|
+
? { tick: value.events.timeout }
|
|
115
|
+
: undefined,
|
|
116
|
+
label: 'Sleep',
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
}
|
|
120
|
+
case 'SetInterval': {
|
|
121
|
+
newAction = {
|
|
122
|
+
...value,
|
|
123
|
+
name: '@toddle/interval',
|
|
124
|
+
arguments: renameArguments(
|
|
125
|
+
{ 'Interval in ms': 'Interval in milliseconds' },
|
|
126
|
+
value.arguments,
|
|
127
|
+
),
|
|
128
|
+
label: 'Interval',
|
|
129
|
+
}
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
case 'Debug': {
|
|
133
|
+
newAction = {
|
|
134
|
+
...value,
|
|
135
|
+
name: '@toddle/logToConsole',
|
|
136
|
+
label: 'Log to console',
|
|
137
|
+
}
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
case 'GoToURL': {
|
|
141
|
+
newAction = {
|
|
142
|
+
name: '@toddle/gotToURL', // Yes, the typo is in the action name
|
|
143
|
+
arguments: renameArguments({ url: 'URL' }, value.arguments),
|
|
144
|
+
label: 'Go to URL',
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
}
|
|
148
|
+
case 'TriggerEvent': {
|
|
149
|
+
const eventName =
|
|
150
|
+
value.arguments?.[0]?.formula.type === 'value'
|
|
151
|
+
? value.arguments[0].formula.value
|
|
152
|
+
: undefined
|
|
153
|
+
if (typeof eventName !== 'string') {
|
|
154
|
+
break
|
|
155
|
+
}
|
|
156
|
+
const eventData = value.arguments?.[1]?.formula
|
|
157
|
+
if (!eventData) {
|
|
158
|
+
break
|
|
159
|
+
}
|
|
160
|
+
newAction = {
|
|
161
|
+
type: 'TriggerEvent',
|
|
162
|
+
event: eventName,
|
|
163
|
+
data: eventData,
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
}
|
|
167
|
+
case 'FocusElement': {
|
|
168
|
+
newAction = {
|
|
169
|
+
name: '@toddle/focus',
|
|
170
|
+
arguments: [
|
|
171
|
+
{
|
|
172
|
+
name: 'Element',
|
|
173
|
+
formula: {
|
|
174
|
+
type: 'function',
|
|
175
|
+
name: '@toddle/getElementById',
|
|
176
|
+
arguments: [
|
|
177
|
+
{
|
|
178
|
+
name: 'Id',
|
|
179
|
+
formula:
|
|
180
|
+
value.arguments?.[0]?.formula ?? valueFormula(null),
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
label: 'Focus',
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (newAction) {
|
|
191
|
+
return set(files, path, newAction)
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
},
|
|
26
195
|
}
|
|
196
|
+
|
|
197
|
+
// These actions take a first argument which is a formula as the name
|
|
198
|
+
// of the thing to update/trigger. We can only safely autofix these if
|
|
199
|
+
// the argument is a value operation and a string
|
|
200
|
+
const formulaNamedActions = [
|
|
201
|
+
'UpdateVariable',
|
|
202
|
+
'Update Variable',
|
|
203
|
+
'TriggerEvent',
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
const unfixableLegacyActions = new Set([
|
|
207
|
+
'CopyToClipboard', // Previously, this action would JSON stringify non-string inputs
|
|
208
|
+
'Update URL parameter', // The user will need to pick a history mode (push/replace)
|
|
209
|
+
'Fetch', // This was mainly used for APIs v1
|
|
210
|
+
'@toddle/setSessionCookies', // The new 'Set cookie' action takes more arguments
|
|
211
|
+
])
|
|
212
|
+
|
|
213
|
+
export type LegacyActionRuleFix = 'replace-legacy-action'
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AndOperation,
|
|
3
3
|
ArrayOperation,
|
|
4
|
-
FunctionArgument,
|
|
5
4
|
FunctionOperation,
|
|
6
5
|
OrOperation,
|
|
7
6
|
SwitchOperation,
|
|
@@ -11,6 +10,11 @@ import { omitKeys, set } from '@nordcraft/core/dist/utils/collections'
|
|
|
11
10
|
import { isDefined } from '@nordcraft/core/dist/utils/util'
|
|
12
11
|
import type { ProjectFiles } from '@nordcraft/ssr/dist/ssr.types'
|
|
13
12
|
import type { FormulaNode, NodeType, Rule } from '../../types'
|
|
13
|
+
import {
|
|
14
|
+
ARRAY_ARGUMENT_MAPPINGS,
|
|
15
|
+
PREDICATE_ARGUMENT_MAPPINGS,
|
|
16
|
+
renameArguments,
|
|
17
|
+
} from '../../util/helpers'
|
|
14
18
|
|
|
15
19
|
export const legacyFormulaRule: Rule<{
|
|
16
20
|
name: string
|
|
@@ -25,8 +29,10 @@ export const legacyFormulaRule: Rule<{
|
|
|
25
29
|
report(
|
|
26
30
|
data.path,
|
|
27
31
|
{ name: data.value.name },
|
|
28
|
-
// The TYPE
|
|
29
|
-
data.value.name !== 'TYPE'
|
|
32
|
+
// The TYPE and BOOLEAN formulas cannot be autofixed since the logic has changed between the 2 implementations
|
|
33
|
+
data.value.name !== 'TYPE' && data.value.name !== 'BOOLEAN'
|
|
34
|
+
? ['replace-legacy-formula']
|
|
35
|
+
: undefined,
|
|
30
36
|
)
|
|
31
37
|
},
|
|
32
38
|
fixes: {
|
|
@@ -372,14 +378,6 @@ export const legacyFormulaRule: Rule<{
|
|
|
372
378
|
}
|
|
373
379
|
return set(data.files, data.path, newAppendFormula)
|
|
374
380
|
}
|
|
375
|
-
case 'BOOLEAN': {
|
|
376
|
-
const newBooleanFormula: FunctionOperation = {
|
|
377
|
-
...data.value,
|
|
378
|
-
name: '@toddle/boolean',
|
|
379
|
-
display_name: 'Boolean',
|
|
380
|
-
}
|
|
381
|
-
return set(data.files, data.path, newBooleanFormula)
|
|
382
|
-
}
|
|
383
381
|
case 'CLAMP': {
|
|
384
382
|
const newClampFormula: FunctionOperation = {
|
|
385
383
|
...data.value,
|
|
@@ -845,23 +843,3 @@ const builtInFormulas = new Set([
|
|
|
845
843
|
'uppercase',
|
|
846
844
|
])
|
|
847
845
|
// cSpell: enable
|
|
848
|
-
|
|
849
|
-
const ARRAY_ARGUMENT_MAPPINGS = { List: 'Array' }
|
|
850
|
-
const PREDICATE_ARGUMENT_MAPPINGS = {
|
|
851
|
-
...ARRAY_ARGUMENT_MAPPINGS,
|
|
852
|
-
'Predicate fx': 'Formula',
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
const renameArguments = (
|
|
856
|
-
mappings: Record<string, string>,
|
|
857
|
-
args: FunctionArgument[] | undefined,
|
|
858
|
-
): FunctionArgument[] =>
|
|
859
|
-
args?.map((arg) => ({
|
|
860
|
-
...arg,
|
|
861
|
-
// Let's adjust the names
|
|
862
|
-
name:
|
|
863
|
-
typeof arg.name === 'string'
|
|
864
|
-
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
865
|
-
(mappings[arg.name] ?? arg.name)
|
|
866
|
-
: arg.name,
|
|
867
|
-
})) ?? []
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { ProjectFiles } from '@nordcraft/ssr/dist/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 { noReferenceProjectFormulaRule } from './noReferenceProjectFormulaRule'
|
|
4
6
|
|
|
5
|
-
describe('noReferenceFormulaRule', () => {
|
|
7
|
+
describe('find noReferenceFormulaRule', () => {
|
|
6
8
|
test('should detect unused global formulas', () => {
|
|
7
9
|
const problems = Array.from(
|
|
8
10
|
searchProject({
|
|
@@ -289,3 +291,36 @@ describe('noReferenceFormulaRule', () => {
|
|
|
289
291
|
expect(problems).toHaveLength(0)
|
|
290
292
|
})
|
|
291
293
|
})
|
|
294
|
+
|
|
295
|
+
describe('fix noReferenceFormulaRule', () => {
|
|
296
|
+
test('should remove unused global formulas', () => {
|
|
297
|
+
const projectFiles: ProjectFiles = {
|
|
298
|
+
formulas: {
|
|
299
|
+
'my-formula': {
|
|
300
|
+
name: 'my-formula',
|
|
301
|
+
arguments: [],
|
|
302
|
+
formula: {
|
|
303
|
+
type: 'value',
|
|
304
|
+
value: 'value',
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
components: {
|
|
309
|
+
test: {
|
|
310
|
+
name: 'test',
|
|
311
|
+
nodes: {},
|
|
312
|
+
formulas: {},
|
|
313
|
+
apis: {},
|
|
314
|
+
attributes: {},
|
|
315
|
+
variables: {},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
}
|
|
319
|
+
const fixedProject = fixProject({
|
|
320
|
+
files: projectFiles,
|
|
321
|
+
rule: noReferenceProjectFormulaRule,
|
|
322
|
+
fixType: 'delete-project-formula',
|
|
323
|
+
})
|
|
324
|
+
expect(fixedProject.formulas).toEqual({})
|
|
325
|
+
})
|
|
326
|
+
})
|