@santi020k/lumen 3.0.1 → 4.1.0

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.
Files changed (125) hide show
  1. package/README.md +211 -3
  2. package/dist/cli.js +49 -5
  3. package/dist/consumer-upgrade-audit.d.ts +10 -0
  4. package/dist/consumer-upgrade-audit.d.ts.map +1 -0
  5. package/dist/consumer-upgrade-audit.js +52 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -0
  9. package/dist/installer.d.ts.map +1 -1
  10. package/dist/installer.js +16 -0
  11. package/dist/integration-diagnostics.d.ts.map +1 -1
  12. package/dist/integration-diagnostics.js +199 -3
  13. package/dist/registry-component-name.d.ts +2 -0
  14. package/dist/registry-component-name.d.ts.map +1 -0
  15. package/dist/registry-component-name.js +53 -0
  16. package/dist/registry-data.d.ts +339 -18
  17. package/dist/registry-data.d.ts.map +1 -1
  18. package/dist/registry-data.js +789 -3
  19. package/dist/registry.d.ts.map +1 -1
  20. package/dist/registry.js +11 -9
  21. package/dist/source-script-ranges.d.ts +3 -0
  22. package/dist/source-script-ranges.d.ts.map +1 -0
  23. package/dist/source-script-ranges.js +41 -0
  24. package/dist/v2-migration.d.ts +38 -0
  25. package/dist/v2-migration.d.ts.map +1 -1
  26. package/dist/v2-migration.js +26 -14
  27. package/dist/v4-migration.d.ts +26 -0
  28. package/dist/v4-migration.d.ts.map +1 -0
  29. package/dist/v4-migration.js +272 -0
  30. package/dist/version-migration-dependencies.d.ts +8 -0
  31. package/dist/version-migration-dependencies.d.ts.map +1 -0
  32. package/dist/version-migration-dependencies.js +10 -0
  33. package/dist/version-migration-source.d.ts +4 -0
  34. package/dist/version-migration-source.d.ts.map +1 -0
  35. package/dist/version-migration-source.js +281 -0
  36. package/dist/version-migration.d.ts +34 -0
  37. package/dist/version-migration.d.ts.map +1 -0
  38. package/dist/version-migration.js +158 -0
  39. package/native-components.json +564 -17
  40. package/package.json +26 -11
  41. package/release-manifest.json +22 -17
  42. package/styles/critical.css +696 -66
  43. package/styles/motion.css +61 -0
  44. package/styles/world-map.css +30 -0
  45. package/styles.css +1756 -409
  46. package/templates/astro/advanced-fields/src/lumen/advanced-fields.astro +35 -0
  47. package/templates/astro/ai-docs/llms.txt +3 -0
  48. package/templates/astro/analytics-dashboard/src/lumen/analytics-dashboard.astro +110 -0
  49. package/templates/astro/auth-onboarding/src/lumen/auth-onboarding.astro +107 -0
  50. package/templates/astro/command-center/src/lumen/command-center.astro +34 -0
  51. package/templates/astro/commerce-dashboard/src/lumen/commerce-dashboard.astro +108 -0
  52. package/templates/astro/content-flow-actions/src/lumen/content-flow-actions.astro +10 -0
  53. package/templates/astro/content-flow-header/src/lumen/content-flow-header.astro +14 -0
  54. package/templates/astro/content-flow-list/src/lumen/content-flow-list.astro +13 -0
  55. package/templates/astro/content-flow-settings/src/lumen/content-flow-settings.astro +17 -0
  56. package/templates/astro/data-collections/src/lumen/data-collections.astro +52 -0
  57. package/templates/astro/feature-preview/src/lumen/feature-preview.astro +32 -0
  58. package/templates/astro/guided-onboarding/src/lumen/guided-onboarding.astro +35 -0
  59. package/templates/astro/interactive-pricing/src/lumen/interactive-pricing.astro +32 -0
  60. package/templates/astro/media-workspace/src/lumen/adjustment-controls.astro +89 -0
  61. package/templates/astro/media-workspace/src/lumen/media-processing.astro +47 -0
  62. package/templates/astro/media-workspace/src/lumen/media-workspace.astro +77 -0
  63. package/templates/astro/page-header/src/lumen/page-header.astro +41 -0
  64. package/templates/astro/project-workspace/src/lumen/project-workspace.astro +103 -0
  65. package/templates/astro/rich-text-editor/src/lumen/rich-text-editor.astro +21 -0
  66. package/templates/astro/saas-admin/src/lumen/saas-admin.astro +110 -0
  67. package/templates/astro/scheduler/src/lumen/scheduler.astro +36 -0
  68. package/templates/astro/section-header/src/lumen/section-header.astro +35 -0
  69. package/templates/astro/theme-builder/src/lumen/theme-builder.astro +28 -0
  70. package/templates/elements/advanced-fields/src/lumen/advanced-fields.html +25 -0
  71. package/templates/elements/analytics-dashboard/src/lumen/analytics-dashboard.html +28 -0
  72. package/templates/elements/auth-onboarding/src/lumen/auth-onboarding.html +79 -0
  73. package/templates/elements/command-center/src/lumen/command-center.html +15 -0
  74. package/templates/elements/commerce-dashboard/src/lumen/commerce-dashboard.html +24 -0
  75. package/templates/elements/content-flow-actions/src/lumen/content-flow-actions.html +11 -0
  76. package/templates/elements/content-flow-header/src/lumen/content-flow-header.html +15 -0
  77. package/templates/elements/content-flow-list/src/lumen/content-flow-list.html +14 -0
  78. package/templates/elements/content-flow-settings/src/lumen/content-flow-settings.html +18 -0
  79. package/templates/elements/data-collections/src/lumen/data-collections.html +31 -0
  80. package/templates/elements/feature-preview/src/lumen/feature-preview.html +13 -0
  81. package/templates/elements/guided-onboarding/src/lumen/guided-onboarding.html +16 -0
  82. package/templates/elements/interactive-pricing/src/lumen/interactive-pricing.html +13 -0
  83. package/templates/elements/media-workspace/src/lumen/media-workspace.html +57 -0
  84. package/templates/elements/media-workspace/src/lumen/media-workspace.ts +163 -0
  85. package/templates/elements/page-header/src/lumen/page-header.html +20 -0
  86. package/templates/elements/project-workspace/src/lumen/project-workspace.html +17 -0
  87. package/templates/elements/rich-text-editor/src/lumen/rich-text-editor.html +17 -0
  88. package/templates/elements/saas-admin/src/lumen/saas-admin.html +18 -0
  89. package/templates/elements/scheduler/src/lumen/scheduler.html +27 -0
  90. package/templates/elements/section-header/src/lumen/section-header.html +21 -0
  91. package/templates/elements/theme-builder/src/lumen/theme-builder.html +59 -0
  92. package/templates/react/advanced-fields/src/lumen/advanced-fields.tsx +37 -0
  93. package/templates/react/analytics-dashboard/src/lumen/analytics-dashboard.tsx +143 -0
  94. package/templates/react/auth-onboarding/src/lumen/auth-onboarding.tsx +129 -0
  95. package/templates/react/command-center/src/lumen/command-center.tsx +85 -0
  96. package/templates/react/commerce-dashboard/src/lumen/commerce-dashboard.tsx +148 -0
  97. package/templates/react/content-flow-actions/src/lumen/content-flow-actions.tsx +11 -0
  98. package/templates/react/content-flow-header/src/lumen/content-flow-header.tsx +14 -0
  99. package/templates/react/content-flow-list/src/lumen/content-flow-list.tsx +19 -0
  100. package/templates/react/content-flow-settings/src/lumen/content-flow-settings.tsx +26 -0
  101. package/templates/react/data-collections/src/lumen/data-collections.tsx +60 -0
  102. package/templates/react/feature-preview/src/lumen/feature-preview.tsx +42 -0
  103. package/templates/react/guided-onboarding/src/lumen/guided-onboarding.tsx +100 -0
  104. package/templates/react/import-review/src/lumen/import-review.tsx +150 -0
  105. package/templates/react/interactive-pricing/src/lumen/interactive-pricing.tsx +60 -0
  106. package/templates/react/media-workspace/src/lumen/adjustment-controls.tsx +61 -0
  107. package/templates/react/media-workspace/src/lumen/media-processing.tsx +43 -0
  108. package/templates/react/media-workspace/src/lumen/media-workspace.tsx +100 -0
  109. package/templates/react/operational-records/src/lumen/operational-records.tsx +92 -0
  110. package/templates/react/page-header/src/lumen/page-header.tsx +41 -0
  111. package/templates/react/project-workspace/src/lumen/project-workspace.tsx +112 -0
  112. package/templates/react/record-workspace/src/lumen/record-workspace.tsx +67 -0
  113. package/templates/react/review-workflow/src/lumen/review-workflow.tsx +202 -0
  114. package/templates/react/rich-text-editor/src/lumen/rich-text-editor.tsx +33 -0
  115. package/templates/react/saas-admin/src/lumen/saas-admin.tsx +119 -0
  116. package/templates/react/scheduler/src/lumen/scheduler.tsx +45 -0
  117. package/templates/react/section-header/src/lumen/section-header.tsx +33 -0
  118. package/templates/react/styles.d.ts +1 -0
  119. package/templates/react/theme-builder/src/lumen/theme-builder.tsx +57 -0
  120. package/templates/react/tsconfig.json +14 -0
  121. package/templates/react/validated-form/src/lumen/validated-form.tsx +166 -0
  122. package/templates/shared/common/src/lumen/lumen-template.css +247 -0
  123. package/templates/shared/media-workspace/src/lumen/media-workspace.css +14 -0
  124. package/templates/shared/visual-blocks/src/lumen/product-blocks.ts +224 -0
  125. package/v4-migration.json +448 -0
@@ -2,6 +2,8 @@ import { createHash } from 'node:crypto';
2
2
  import { readdir, readFile, stat } from 'node:fs/promises';
3
3
  import { extname, join, relative, resolve, sep } from 'node:path';
4
4
  import { lumenComponentBehavior, lumenComponentNames, lumenGlobalBehaviors, lumenStylingContracts } from '@santi020k/lumen-core';
5
+ import { createSourceFile, forEachChild, isForOfStatement, isImportDeclaration, isNamedImports, isStringLiteral, ScriptKind, ScriptTarget, SyntaxKind } from 'typescript';
6
+ import { findMarkupTagEnd, getMarkupStart } from './v2-migration.js';
5
7
  const sourceExtensions = new Set(['.astro', '.css', '.js', '.jsx', '.mjs', '.ts', '.tsx']);
6
8
  const ignoredDirectories = new Set([
7
9
  '.astro',
@@ -330,6 +332,199 @@ const getGlobalRuntimeBehaviors = (sources) => lumenGlobalBehaviors
330
332
  return behavior.authoredBy.split(',').some(eventName => item.source.includes(eventName.trim()));
331
333
  }))
332
334
  .map(behavior => behavior.name);
335
+ const isRuntimeImport = (statement) => (isImportDeclaration(statement) && isStringLiteral(statement.moduleSpecifier) &&
336
+ statement.moduleSpecifier.text === '@santi020k/lumen-astro/runtime');
337
+ const getDefaultRuntimeName = (binding) => !binding.isTypeOnly && (binding.propertyName?.text ?? binding.name.text) === 'default' ? [binding.name.text] : [];
338
+ const getImportRuntimeNames = (statement) => {
339
+ const clause = statement.importClause;
340
+ if (!clause || clause.phaseModifier === SyntaxKind.TypeKeyword)
341
+ return [];
342
+ const names = clause.name ? [clause.name.text] : [];
343
+ const bindings = clause.namedBindings;
344
+ if (!bindings || !isNamedImports(bindings))
345
+ return names;
346
+ return [...names, ...bindings.elements.flatMap(getDefaultRuntimeName)];
347
+ };
348
+ const getRuntimeBindingNames = ({ file, source }) => {
349
+ if (!source.includes('@santi020k/lumen-astro/runtime'))
350
+ return new Set(['UIPrimitives']);
351
+ try {
352
+ const parsed = createSourceFile(file, source, ScriptTarget.Latest, false, ScriptKind.TS);
353
+ const imports = parsed.statements.filter(isRuntimeImport);
354
+ // Preserve canonical-name detection for legacy imports and wrapper components.
355
+ return imports.length > 0 ? new Set(imports.flatMap(getImportRuntimeNames)) : new Set(['UIPrimitives']);
356
+ }
357
+ catch (error) {
358
+ if (!(error instanceof RangeError))
359
+ throw error;
360
+ return new Set();
361
+ }
362
+ };
363
+ const runtimeTagDelimiter = /[\s/>]/u;
364
+ const getMarkupNameEnd = (source, start) => {
365
+ let end = start + 1;
366
+ while (end < source.length && source[end] !== '<' && !runtimeTagDelimiter.test(source[end] ?? ''))
367
+ end += 1;
368
+ return end;
369
+ };
370
+ const skipRuntimeQuotedText = (source, start) => {
371
+ let end = start + 1;
372
+ while (end < source.length) {
373
+ if (source[end] === '\\')
374
+ end += 2;
375
+ else if (source[end] === source[start])
376
+ return end + 1;
377
+ else
378
+ end += 1;
379
+ }
380
+ return source.length;
381
+ };
382
+ const runtimeRegexPrefixes = new Set(['{', '(', '[', '=', ':', ',', ';', '!', '?', '&', '|', '+', '*', '%', '~', '^', '<', '>', '-']);
383
+ const runtimeRegexKeywords = new Set(['return', 'throw', 'case', 'yield', 'typeof', 'void', 'delete', 'instanceof', 'in', 'new', 'await', 'else', 'do']);
384
+ const getForOfRegexStarts = (source) => {
385
+ const starts = new Set();
386
+ try {
387
+ const parsed = createSourceFile('runtime.tsx', source, ScriptTarget.Latest, true, ScriptKind.TSX);
388
+ const pending = [parsed];
389
+ while (pending.length > 0) {
390
+ const node = pending.pop();
391
+ if (!node)
392
+ continue;
393
+ if (isForOfStatement(node))
394
+ starts.add(node.expression.getStart(parsed));
395
+ forEachChild(node, child => {
396
+ pending.push(child);
397
+ });
398
+ }
399
+ }
400
+ catch (error) {
401
+ if (!(error instanceof RangeError))
402
+ throw error;
403
+ }
404
+ return starts;
405
+ };
406
+ const runtimeCodePointStart = (source, index) => {
407
+ const current = source.charCodeAt(index);
408
+ const previous = source.charCodeAt(index - 1);
409
+ return current >= 0xdc00 && current <= 0xdfff && previous >= 0xd800 && previous <= 0xdbff ? index - 1 : index;
410
+ };
411
+ const previousRuntimeCharacter = (source, start, pattern) => {
412
+ let previous = start;
413
+ while (previous >= 0) {
414
+ const pointStart = runtimeCodePointStart(source, previous);
415
+ if (!pattern.test(source.slice(pointStart, previous + 1)))
416
+ break;
417
+ previous = pointStart - 1;
418
+ }
419
+ return previous;
420
+ };
421
+ const isRuntimeRegexStart = (source, start, forOfStarts) => {
422
+ if (forOfStarts.has(start))
423
+ return true;
424
+ const previous = previousRuntimeCharacter(source, start - 1, /\s/u);
425
+ if (previous < 0 || runtimeRegexPrefixes.has(source[previous] ?? ''))
426
+ return true;
427
+ const wordEnd = previous + 1;
428
+ const wordStart = previousRuntimeCharacter(source, previous, /[$\u200c\u200d\p{ID_Continue}]/u) + 1;
429
+ const keyword = source.slice(wordStart, wordEnd);
430
+ if (!runtimeRegexKeywords.has(keyword))
431
+ return false;
432
+ return source[previousRuntimeCharacter(source, wordStart - 1, /\s/u)] !== '.';
433
+ };
434
+ const skipRuntimeRegex = (source, start) => {
435
+ let cursor = start + 1;
436
+ let inClass = false;
437
+ while (cursor < source.length) {
438
+ const character = source[cursor];
439
+ if (character === '\\')
440
+ cursor += 2;
441
+ else {
442
+ if (character === '[')
443
+ inClass = true;
444
+ else if (character === ']')
445
+ inClass = false;
446
+ else if (character === '/' && !inClass)
447
+ return cursor + 1;
448
+ cursor += 1;
449
+ }
450
+ }
451
+ return source.length;
452
+ };
453
+ const skipRuntimeExpressionTrivia = (source, start, depth, forOfStarts) => {
454
+ if (depth === 0)
455
+ return start;
456
+ if (/['"`]/u.test(source[start] ?? ''))
457
+ return skipRuntimeQuotedText(source, start);
458
+ if (source.startsWith('/*', start)) {
459
+ const end = source.indexOf('*/', start + 2);
460
+ return end < 0 ? source.length : end + 2;
461
+ }
462
+ if (source.startsWith('//', start)) {
463
+ const end = source.indexOf('\n', start + 2);
464
+ return end < 0 ? source.length : end + 1;
465
+ }
466
+ if (source[start] === '/' && isRuntimeRegexStart(source, start, forOfStarts))
467
+ return skipRuntimeRegex(source, start);
468
+ return start;
469
+ };
470
+ const skipRuntimeRawText = (lowerSource, name, start) => {
471
+ if (name !== 'script' && name !== 'style')
472
+ return start;
473
+ let closing = lowerSource.indexOf(`</${name}`, start);
474
+ while (closing >= 0 && !runtimeTagDelimiter.test(lowerSource[closing + name.length + 2] ?? '')) {
475
+ closing = lowerSource.indexOf(`</${name}`, closing + name.length + 2);
476
+ }
477
+ return closing < 0 ? lowerSource.length : closing;
478
+ };
479
+ const getRuntimeExpressionDepth = (character, depth) => {
480
+ if (character === '{')
481
+ return depth + 1;
482
+ return character === '}' ? Math.max(0, depth - 1) : depth;
483
+ };
484
+ const skipRuntimeMarkupTrivia = (source, start) => {
485
+ if (source.startsWith('<!--', start)) {
486
+ const end = source.indexOf('-->', start + 4);
487
+ return end < 0 ? source.length : end + 3;
488
+ }
489
+ return /[A-Za-z_$/]/u.test(source[start + 1] ?? '') ? start : start + 1;
490
+ };
491
+ const countRuntimeMounts = (entry) => {
492
+ const names = getRuntimeBindingNames(entry);
493
+ let count = 0;
494
+ let depth = 0;
495
+ let start = getMarkupStart(entry.source, entry.file);
496
+ const forOfStarts = new Set([...getForOfRegexStarts(entry.source.slice(start))].map(position => position + start));
497
+ const lowerSource = entry.source.replace(/[A-Z]/gu, character => character.toLowerCase());
498
+ while (start < entry.source.length) {
499
+ const skipped = skipRuntimeExpressionTrivia(entry.source, start, depth, forOfStarts);
500
+ if (skipped !== start) {
501
+ start = skipped;
502
+ continue;
503
+ }
504
+ const character = entry.source[start];
505
+ depth = getRuntimeExpressionDepth(character, depth);
506
+ if (character !== '<') {
507
+ start += 1;
508
+ continue;
509
+ }
510
+ const markupStart = skipRuntimeMarkupTrivia(entry.source, start);
511
+ if (markupStart !== start) {
512
+ start = markupStart;
513
+ continue;
514
+ }
515
+ const end = getMarkupNameEnd(entry.source, start);
516
+ const name = entry.source.slice(start + 1, end);
517
+ const tagEnd = findMarkupTagEnd(entry.source, end, true);
518
+ if (tagEnd < 0) {
519
+ start += 1;
520
+ continue;
521
+ }
522
+ if (names.has(name) && runtimeTagDelimiter.test(entry.source[end] ?? ''))
523
+ count += 1;
524
+ start = skipRuntimeRawText(lowerSource, name, tagEnd + 1);
525
+ }
526
+ return count;
527
+ };
333
528
  const collectRuntimeFindings = (repositoryRoot, boundary) => {
334
529
  const runtimeImports = getRuntimeImports(boundary.sources);
335
530
  const runtimeComponents = [
@@ -338,15 +533,16 @@ const collectRuntimeFindings = (repositoryRoot, boundary) => {
338
533
  ...getGlobalRuntimeBehaviors(boundary.sources)
339
534
  ])
340
535
  ];
341
- const mountSources = boundary.sources.filter(item => /<UIPrimitives(?:\s|\/|>)/u.test(item.source));
536
+ const mountSources = boundary.sources
537
+ .map(item => ({ ...item, mountCount: countRuntimeMounts(item) }))
538
+ .filter(item => item.mountCount > 0);
342
539
  const findings = [];
343
540
  if (runtimeComponents.length > 0 && mountSources.length === 0) {
344
541
  const firstRuntimeImport = runtimeImports[0];
345
542
  findings.push(finding(firstRuntimeImport ? relative(repositoryRoot, firstRuntimeImport.file) : relative(repositoryRoot, boundary.root), 'astro-runtime-missing', `Interactive Astro usage requires UIPrimitives: ${runtimeComponents.join(', ')}.`, 'Mount <UIPrimitives /> once in the application root, or use a documented controlled prop when application code owns the behavior.'));
346
543
  }
347
544
  for (const mount of mountSources) {
348
- const mountCount = [...mount.source.matchAll(/<UIPrimitives(?:\s|\/|>)/g)].length;
349
- if (mountCount > 1) {
545
+ if (mount.mountCount > 1) {
350
546
  findings.push(finding(relative(repositoryRoot, mount.file), 'astro-runtime-duplicate', 'UIPrimitives is mounted more than once in this file.', 'Keep one mount in the application root layout.'));
351
547
  }
352
548
  }
@@ -0,0 +1,2 @@
1
+ export declare const isSafeRegistryComponentName: (name: unknown) => name is string;
2
+ //# sourceMappingURL=registry-component-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-component-name.d.ts","sourceRoot":"","sources":["../src/registry-component-name.ts"],"names":[],"mappings":"AAqDA,eAAO,MAAM,2BAA2B,GAAI,MAAM,OAAO,KAAG,IAAI,IAAI,MAEnE,CAAA"}
@@ -0,0 +1,53 @@
1
+ const reservedNames = new Set([
2
+ 'arguments',
3
+ 'await',
4
+ 'break',
5
+ 'case',
6
+ 'catch',
7
+ 'class',
8
+ 'const',
9
+ 'continue',
10
+ 'debugger',
11
+ 'default',
12
+ 'delete',
13
+ 'do',
14
+ 'else',
15
+ 'enum',
16
+ 'eval',
17
+ 'export',
18
+ 'extends',
19
+ 'false',
20
+ 'finally',
21
+ 'for',
22
+ 'function',
23
+ 'if',
24
+ 'implements',
25
+ 'import',
26
+ 'in',
27
+ 'instanceof',
28
+ 'interface',
29
+ 'let',
30
+ 'new',
31
+ 'null',
32
+ 'package',
33
+ 'private',
34
+ 'protected',
35
+ 'public',
36
+ 'return',
37
+ 'static',
38
+ 'super',
39
+ 'switch',
40
+ 'this',
41
+ 'throw',
42
+ 'true',
43
+ 'try',
44
+ 'typeof',
45
+ 'var',
46
+ 'void',
47
+ 'while',
48
+ 'with',
49
+ 'yield'
50
+ ]);
51
+ // Names are interpolated into identifiers and custom-element tag names in the
52
+ // generated wrappers. Use their shared ASCII subset, without module keywords.
53
+ export const isSafeRegistryComponentName = (name) => (typeof name === 'string' && /^[A-Za-z_][A-Za-z0-9_]*(?![\s\S])/u.test(name) && !reservedNames.has(name));