@nordcraft/search 1.0.87 → 1.0.88

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.
@@ -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;QACD,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"}
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"}
package/package.json CHANGED
@@ -10,8 +10,8 @@
10
10
  "directory": "packages/search"
11
11
  },
12
12
  "dependencies": {
13
- "@nordcraft/ssr": "1.0.87",
14
- "@nordcraft/core": "1.0.87",
13
+ "@nordcraft/ssr": "1.0.88",
14
+ "@nordcraft/core": "1.0.88",
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.87"
29
+ "version": "1.0.88"
30
30
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable inclusive-language/use-inclusive-words */
2
1
  import type { CustomActionModel } from '@nordcraft/core/dist/component/component.types'
3
2
  import { describe, expect, test } from 'bun:test'
4
3
  import { fixProject } from '../../../fixProject'
@@ -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
  },
@@ -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
  () => {