@deneb-ui/cli 2.0.85 → 2.0.86
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/bin/index.js +39 -2
- package/package.json +2 -2
- package/src/arc/__tests__/arc.test.cjs +1145 -0
- package/src/arc/adapters/accordion.cjs +32 -0
- package/src/arc/adapters/dialog.cjs +26 -0
- package/src/arc/adapters/embla.cjs +29 -0
- package/src/arc/adapters/gallery.cjs +23 -0
- package/src/arc/adapters/picture-source.cjs +71 -0
- package/src/arc/adapters/registry.cjs +156 -0
- package/src/arc/adapters/slick.cjs +26 -0
- package/src/arc/adapters/swiper.cjs +29 -0
- package/src/arc/adapters/tabs.cjs +29 -0
- package/src/arc/adapters/ui-frameworks.cjs +140 -0
- package/src/arc/adapters.cjs +20 -151
- package/src/arc/canonical-paths.cjs +95 -0
- package/src/arc/data-flow.cjs +158 -0
- package/src/arc/diff.cjs +136 -0
- package/src/arc/explain.cjs +113 -0
- package/src/arc/field-paths.cjs +25 -13
- package/src/arc/index.cjs +118 -6
- package/src/arc/ir-builder.cjs +581 -0
- package/src/arc/manifest.cjs +18 -0
- package/src/arc/planner.cjs +106 -2
- package/src/arc/printer.cjs +18 -5
- package/src/arc/residual.cjs +9 -3
- package/src/arc/rsc-boundary.cjs +154 -0
- package/src/arc/runtime-validator.cjs +286 -0
- package/src/arc/semantic.cjs +217 -16
- package/src/arc/text-fragment-analyzer.cjs +173 -0
- package/src/arc/transformer.cjs +627 -9
package/src/arc/field-paths.cjs
CHANGED
|
@@ -44,16 +44,20 @@ function inferSection(context) {
|
|
|
44
44
|
['hero', /hero|banner|jumbotron/],
|
|
45
45
|
['navigation', /nav|menu|links/],
|
|
46
46
|
['feedback', /feedback|google-review/],
|
|
47
|
-
['testimonials', /testimonial/],
|
|
47
|
+
['testimonials', /testimonial|review/],
|
|
48
|
+
['featuredProducts', /featured|product-grid|catalog|goods|store/],
|
|
49
|
+
['services', /service|offering/],
|
|
50
|
+
['gallery', /gallery|portfolio|showcase/],
|
|
51
|
+
['team', /team|member|staff|author/],
|
|
52
|
+
['stats', /stat|counter|metric/],
|
|
48
53
|
['map', /map\b|location-map|google-map/],
|
|
49
54
|
['faq', /faq|accordion/],
|
|
50
55
|
['form', /form|booking|inquiry|registration/],
|
|
51
56
|
['contact', /contact|whatsapp|mailto/],
|
|
52
|
-
['featuredProducts', /featured|product-grid|collection/],
|
|
53
57
|
['newsletter', /newsletter|subscribe/],
|
|
54
58
|
['pricing', /pricing|plan/],
|
|
55
59
|
['features', /feature/],
|
|
56
|
-
['about', /about|story|brand/],
|
|
60
|
+
['about', /about|story|brand|history/],
|
|
57
61
|
];
|
|
58
62
|
for (const [name, re] of rules) {
|
|
59
63
|
if (re.test(haystack)) return name;
|
|
@@ -163,16 +167,24 @@ function listActionCtaItemFieldNames() {
|
|
|
163
167
|
return ['buttonLabel', 'buttonUrl'];
|
|
164
168
|
}
|
|
165
169
|
|
|
166
|
-
function classifyFieldType(kind, value) {
|
|
167
|
-
|
|
168
|
-
if (kind === '
|
|
169
|
-
if (kind === '
|
|
170
|
-
if (kind === '
|
|
171
|
-
if (kind === '
|
|
172
|
-
if (kind === '
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
function classifyFieldType(kind, value, fieldName = '') {
|
|
171
|
+
const name = String(fieldName || '').toLowerCase();
|
|
172
|
+
if (kind === 'image' || /image|thumbnail|avatar|picture|cover|photo/i.test(name)) return 'image';
|
|
173
|
+
if (kind === 'url' || /url|href|link|path$/i.test(name)) return 'url';
|
|
174
|
+
if (kind === 'email' || /email/i.test(name) || (typeof value === 'string' && /^mailto:/i.test(value))) return 'email';
|
|
175
|
+
if (kind === 'phone' || /phone|tel|whatsapp/i.test(name) || (typeof value === 'string' && /^(tel:|\+)/i.test(value))) return 'tel';
|
|
176
|
+
if (kind === 'color' || /color/i.test(name)) return 'text';
|
|
177
|
+
if (
|
|
178
|
+
kind === 'rating' ||
|
|
179
|
+
kind === 'number' ||
|
|
180
|
+
typeof value === 'number' ||
|
|
181
|
+
/price|amount|rating|count|score|stars|qty|quantity|discount|fee|cost/i.test(name)
|
|
182
|
+
) {
|
|
183
|
+
if (typeof value === 'string' && /\$|lkr|usd|rs\.?\s*\d/i.test(value)) return 'text';
|
|
184
|
+
return typeof value === 'number' ? 'number' : 'text';
|
|
185
|
+
}
|
|
186
|
+
if (typeof value === 'boolean' || /enabled|visible|show|active/i.test(name)) return 'boolean';
|
|
187
|
+
if (kind === 'textarea' || (typeof value === 'string' && (value.length > 70 || value.includes('\n')))) return 'textarea';
|
|
176
188
|
return 'text';
|
|
177
189
|
}
|
|
178
190
|
|
package/src/arc/index.cjs
CHANGED
|
@@ -15,6 +15,7 @@ const path = require('path');
|
|
|
15
15
|
const { ARC_NAME, ARC_VERSION, SCHEMA_VERSION, ENGINE_ID } = require('./version.cjs');
|
|
16
16
|
const { walkFiles, isJsxFile, rel, copyFilePreserve, writeJson, readJsonSafe, findFirstExisting } = require('./fs-utils.cjs');
|
|
17
17
|
const { scanProject, buildDependencyGraph, inferOwnerScope, resolvePageFileOnDisk } = require('./scanner.cjs');
|
|
18
|
+
const { buildProjectIR } = require('./ir-builder.cjs');
|
|
18
19
|
const { analyzeFile, collectDesignSnapshot } = require('./semantic.cjs');
|
|
19
20
|
const { planTransformations } = require('./planner.cjs');
|
|
20
21
|
const { applyFilePlan, instrumentLayoutSource, instrumentPageKey, resolveSiteDataSpecifier, resolveSiteDataRuntimeSpecifier, rewriteRecursiveSiteDataContext, ensureJsonModule, sanitizeContradictoryMarkersInSource } = require('./transformer.cjs');
|
|
@@ -47,6 +48,8 @@ const { classifyComponents } = require('./component-registry.cjs');
|
|
|
47
48
|
const { checkAiReady, adaptComponent, generateDocsPage, loadEnv } = require('./ai-agent.cjs');
|
|
48
49
|
const { checkGithubReady, createComponentPR } = require('./pr-agent.cjs');
|
|
49
50
|
const { runAiEvaluatorPipeline } = require('./ai-evaluator.cjs');
|
|
51
|
+
const { explainFile } = require('./explain.cjs');
|
|
52
|
+
const { generateArcDiff } = require('./diff.cjs');
|
|
50
53
|
|
|
51
54
|
function parseArcOptions(raw = {}) {
|
|
52
55
|
return {
|
|
@@ -60,6 +63,8 @@ function parseArcOptions(raw = {}) {
|
|
|
60
63
|
aiEnabled: Boolean(raw.aiEnabled),
|
|
61
64
|
aiDryRun: Boolean(raw.aiDryRun),
|
|
62
65
|
strict: Boolean(raw.strict),
|
|
66
|
+
verifyRuntime: Boolean(raw.verifyRuntime || raw['verify-runtime']),
|
|
67
|
+
previewUrl: raw.previewUrl || raw['preview-url'] || null,
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -220,7 +225,7 @@ function auditFivoraContract({ profile, siteData, manifest, inventory }) {
|
|
|
220
225
|
};
|
|
221
226
|
}
|
|
222
227
|
|
|
223
|
-
function analyzeProjectFiles(profile, graph) {
|
|
228
|
+
function analyzeProjectFiles(profile, graph, ir) {
|
|
224
229
|
const analyses = [];
|
|
225
230
|
for (const relativeFile of profile.jsxFiles) {
|
|
226
231
|
const abs = path.join(profile.root, relativeFile);
|
|
@@ -245,6 +250,7 @@ function analyzeProjectFiles(profile, graph) {
|
|
|
245
250
|
graph,
|
|
246
251
|
ownerScope,
|
|
247
252
|
componentMeta,
|
|
253
|
+
ir,
|
|
248
254
|
});
|
|
249
255
|
analyses.push({
|
|
250
256
|
...result,
|
|
@@ -283,7 +289,8 @@ async function runDenebArcAsync(projectDir, projectName, options = {}) {
|
|
|
283
289
|
mergeDetectedPages(profile, opts.detectedPages);
|
|
284
290
|
printer.printProfile(profile);
|
|
285
291
|
const graph = buildDependencyGraph(profile);
|
|
286
|
-
const
|
|
292
|
+
const ir = buildProjectIR(profile);
|
|
293
|
+
const analyses = analyzeProjectFiles(profile, graph, ir);
|
|
287
294
|
|
|
288
295
|
const candidateCount = analyses.reduce(
|
|
289
296
|
(n, a) => n + (a.candidates || []).filter((c) => c.kind !== 'decoration' && c.kind !== 'already-editable' && !c.skip).length,
|
|
@@ -376,7 +383,7 @@ async function runDenebArcAsync(projectDir, projectName, options = {}) {
|
|
|
376
383
|
}
|
|
377
384
|
}
|
|
378
385
|
|
|
379
|
-
const result = runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt);
|
|
386
|
+
const result = runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt, ir);
|
|
380
387
|
|
|
381
388
|
if (!opts.dryRun && result && result.outcome === 'success') {
|
|
382
389
|
printer.printAiEvaluatorStart();
|
|
@@ -417,7 +424,8 @@ function runDenebArcSync(projectDir, projectName, options = {}) {
|
|
|
417
424
|
|
|
418
425
|
printer.printProfile(profile);
|
|
419
426
|
const graph = buildDependencyGraph(profile);
|
|
420
|
-
const
|
|
427
|
+
const ir = buildProjectIR(profile);
|
|
428
|
+
const analyses = analyzeProjectFiles(profile, graph, ir);
|
|
421
429
|
|
|
422
430
|
const candidateCount = analyses.reduce(
|
|
423
431
|
(n, a) => n + (a.candidates || []).filter((c) => c.kind !== 'decoration' && c.kind !== 'already-editable' && !c.skip).length,
|
|
@@ -429,7 +437,7 @@ function runDenebArcSync(projectDir, projectName, options = {}) {
|
|
|
429
437
|
);
|
|
430
438
|
printer.printScan(profile, graph, candidateCount, actionCount);
|
|
431
439
|
|
|
432
|
-
return runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt);
|
|
440
|
+
return runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt, ir);
|
|
433
441
|
}
|
|
434
442
|
|
|
435
443
|
function runDenebArc(projectDir, projectName, options = {}) {
|
|
@@ -440,7 +448,7 @@ function runDenebArc(projectDir, projectName, options = {}) {
|
|
|
440
448
|
return runDenebArcSync(projectDir, projectName, options);
|
|
441
449
|
}
|
|
442
450
|
|
|
443
|
-
function runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt) {
|
|
451
|
+
function runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt, ir) {
|
|
444
452
|
const sourceAbs = profile.jsxFiles.map((f) => path.join(projectDir, f));
|
|
445
453
|
const recipeMatch = matchRecipeV2(projectDir, profile, sourceAbs, opts.recipeName);
|
|
446
454
|
if (recipeMatch.recipe) {
|
|
@@ -451,6 +459,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
451
459
|
profile,
|
|
452
460
|
analyses,
|
|
453
461
|
recipe: recipeMatch.recipe,
|
|
462
|
+
ir,
|
|
454
463
|
});
|
|
455
464
|
printer.printPlan(plan);
|
|
456
465
|
|
|
@@ -586,6 +595,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
586
595
|
usedPaths,
|
|
587
596
|
componentName: analysis?.componentMeta?.name,
|
|
588
597
|
role: analysis?.componentMeta?.role,
|
|
598
|
+
ir,
|
|
589
599
|
});
|
|
590
600
|
if (!residual.changed) continue;
|
|
591
601
|
try {
|
|
@@ -745,6 +755,18 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
745
755
|
uncoveredVisibleText: fivoraAudit.uncoveredVisibleText,
|
|
746
756
|
});
|
|
747
757
|
|
|
758
|
+
const { validateRuntimeEditabilitySync } = require('./runtime-validator.cjs');
|
|
759
|
+
let runtimeVerification = null;
|
|
760
|
+
try {
|
|
761
|
+
runtimeVerification = validateRuntimeEditabilitySync({
|
|
762
|
+
projectDir,
|
|
763
|
+
siteData: dataBundle.siteData,
|
|
764
|
+
manifest: dataBundle.manifest,
|
|
765
|
+
});
|
|
766
|
+
} catch (err) {
|
|
767
|
+
runtimeVerification = { passed: false, error: err.message, runtimeEditabilityScore: 0 };
|
|
768
|
+
}
|
|
769
|
+
|
|
748
770
|
const validation = {
|
|
749
771
|
syntaxPassed,
|
|
750
772
|
fivoraContractPassed: fivoraAudit.passed,
|
|
@@ -759,6 +781,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
759
781
|
astFailures: astResults.filter((r) => !r.passed),
|
|
760
782
|
transformFailures,
|
|
761
783
|
designPreservation: design.score,
|
|
784
|
+
runtimeVerification,
|
|
762
785
|
};
|
|
763
786
|
|
|
764
787
|
const criticalFailure = !syntaxPassed || (contracts.actionCollisions > 0 && appliedCount === 0);
|
|
@@ -892,6 +915,63 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
892
915
|
writeJson(path.join(journalDir, 'validation.json'), validation);
|
|
893
916
|
writeJson(path.join(projectDir, '.deneb', 'report.json'), report);
|
|
894
917
|
|
|
918
|
+
function classifyDiagnosticSeverity(item) {
|
|
919
|
+
if (item.blocking || /syntax|ast-invalid|fatal/i.test(item.reason || '')) {
|
|
920
|
+
return 'BLOCKING';
|
|
921
|
+
}
|
|
922
|
+
if (/contract|collision|unresolved-binding|failed/i.test(item.reason || '') || item.type === 'error') {
|
|
923
|
+
return 'ERROR';
|
|
924
|
+
}
|
|
925
|
+
if (/dynamic|uncovered|compound|complex|skip/i.test(item.reason || '') && !/icon|decorative|hidden|picture-source/i.test(item.reason || '')) {
|
|
926
|
+
return 'WARNING';
|
|
927
|
+
}
|
|
928
|
+
return 'INFO';
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const unresolvedList = (plan.skipped || []).map((s) => ({
|
|
932
|
+
file: s.file,
|
|
933
|
+
loc: s.loc,
|
|
934
|
+
type: s.kind || 'unknown',
|
|
935
|
+
reason: s.reason || 'skipped',
|
|
936
|
+
confidence: s.confidence,
|
|
937
|
+
severity: classifyDiagnosticSeverity(s),
|
|
938
|
+
}));
|
|
939
|
+
|
|
940
|
+
const diagnosticsBySeverity = {
|
|
941
|
+
info: unresolvedList.filter((u) => u.severity === 'INFO').length,
|
|
942
|
+
warning: unresolvedList.filter((u) => u.severity === 'WARNING').length,
|
|
943
|
+
error: unresolvedList.filter((u) => u.severity === 'ERROR').length,
|
|
944
|
+
blocking: unresolvedList.filter((u) => u.severity === 'BLOCKING').length,
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
const conversionReport = {
|
|
948
|
+
runId,
|
|
949
|
+
timestamp: startedAt,
|
|
950
|
+
projectName: projectName || profile.packageName,
|
|
951
|
+
outcome,
|
|
952
|
+
scorecard: {
|
|
953
|
+
contractValidity: validation.fivoraContractPassed ? '100%' : 'Failed',
|
|
954
|
+
editabilityCoverage: `${coverage.visualCoverage != null ? coverage.visualCoverage : coverage.editableCoverage}%`,
|
|
955
|
+
visualBound: coverage.visualCovered != null ? `${coverage.visualCovered}/${coverage.visualRequired}` : null,
|
|
956
|
+
designPreservation: `${design.score}%`,
|
|
957
|
+
runtimeEditability: runtimeVerification ? `${runtimeVerification.runtimeEditabilityScore}%` : '100%',
|
|
958
|
+
},
|
|
959
|
+
runtimeVerification,
|
|
960
|
+
diagnosticsBySeverity,
|
|
961
|
+
unresolvedCount: unresolvedList.length,
|
|
962
|
+
unresolved: unresolvedList,
|
|
963
|
+
categories: {
|
|
964
|
+
text: { planned: plan.files.reduce((n, f) => n + f.transformations.filter((t) => /text|heading|label/.test(t.fieldType || '')).length, 0) },
|
|
965
|
+
images: { planned: plan.files.reduce((n, f) => n + f.transformations.filter((t) => t.fieldType === 'image').length, 0) },
|
|
966
|
+
links: { planned: plan.files.reduce((n, f) => n + f.transformations.filter((t) => t.fieldType === 'url').length, 0) },
|
|
967
|
+
collections: { planned: plan.files.reduce((n, f) => n + f.transformations.filter((t) => t.operation === 'collection-conversion').length, 0) },
|
|
968
|
+
backgrounds: { planned: plan.files.reduce((n, f) => n + f.transformations.filter((t) => t.operation === 'extract-tailwind-bg').length, 0) },
|
|
969
|
+
componentProps: { planned: plan.files.reduce((n, f) => n + f.transformations.filter((t) => t.operation === 'extract-prop' || t.operation === 'prop-flow-callsite').length, 0) },
|
|
970
|
+
},
|
|
971
|
+
};
|
|
972
|
+
writeJson(path.join(projectDir, 'deneb-conversion-report.json'), conversionReport);
|
|
973
|
+
writeJson(path.join(journalDir, 'conversion-report.json'), conversionReport);
|
|
974
|
+
|
|
895
975
|
if (outcome === 'success') {
|
|
896
976
|
printer.printSuccess();
|
|
897
977
|
printer.printDeveloperNextSteps();
|
|
@@ -956,8 +1036,40 @@ function buildReport(args) {
|
|
|
956
1036
|
};
|
|
957
1037
|
}
|
|
958
1038
|
|
|
1039
|
+
function runTransactionalPipeline(targetDirInput = '.', options = {}) {
|
|
1040
|
+
const opts = { ...options, strict: options.strict ?? true };
|
|
1041
|
+
const projectDir = path.resolve(targetDirInput);
|
|
1042
|
+
try {
|
|
1043
|
+
const result = runArc(targetDirInput, opts);
|
|
1044
|
+
return {
|
|
1045
|
+
success: result.outcome === 'success',
|
|
1046
|
+
rolledBack: result.outcome === 'rolled-back',
|
|
1047
|
+
outcome: result.outcome,
|
|
1048
|
+
result,
|
|
1049
|
+
};
|
|
1050
|
+
} catch (err) {
|
|
1051
|
+
const runsDir = path.join(projectDir, '.deneb', 'backups');
|
|
1052
|
+
if (fs.existsSync(runsDir)) {
|
|
1053
|
+
const backups = fs.readdirSync(runsDir).sort();
|
|
1054
|
+
const latest = backups[backups.length - 1];
|
|
1055
|
+
if (latest) {
|
|
1056
|
+
restoreBackup(projectDir, path.join(runsDir, latest));
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return {
|
|
1060
|
+
success: false,
|
|
1061
|
+
rolledBack: true,
|
|
1062
|
+
outcome: 'rolled-back',
|
|
1063
|
+
error: err.message,
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
959
1068
|
module.exports = {
|
|
960
1069
|
runDenebArc,
|
|
1070
|
+
runTransactionalPipeline,
|
|
1071
|
+
explainFile,
|
|
1072
|
+
generateArcDiff,
|
|
961
1073
|
parseArcOptions,
|
|
962
1074
|
scanProject,
|
|
963
1075
|
auditFivoraContract,
|