@deneb-ui/cli 2.0.84 → 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 +82 -12
- package/package.json +2 -2
- package/src/arc/__tests__/arc.test.cjs +1251 -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/fs-utils.cjs +3 -0
- package/src/arc/index.cjs +126 -7
- 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 +819 -20
- package/src/arc/version.cjs +1 -1
- package/src/tools/deneb-doctor.cjs +53 -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/fs-utils.cjs
CHANGED
package/src/arc/index.cjs
CHANGED
|
@@ -15,12 +15,14 @@ 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');
|
|
21
22
|
const { applyResidualPass } = require('./residual.cjs');
|
|
22
23
|
const { parseSource } = require('./ast.cjs');
|
|
23
24
|
const { buildSiteDataAndManifest, writeDataBank, loadExistingData, countSchemaFields } = require('./manifest.cjs');
|
|
25
|
+
const { collectFontIdsFromSiteData } = require('./font-plan.cjs');
|
|
24
26
|
const { validateAstFiles, validateContracts, designPreservationScore, coverageMetrics } = require('./validator.cjs');
|
|
25
27
|
const { recordExperience, registryArchitecture } = require('./learning.cjs');
|
|
26
28
|
const { matchRecipeV2 } = require('./recipes-v2.cjs');
|
|
@@ -46,6 +48,8 @@ const { classifyComponents } = require('./component-registry.cjs');
|
|
|
46
48
|
const { checkAiReady, adaptComponent, generateDocsPage, loadEnv } = require('./ai-agent.cjs');
|
|
47
49
|
const { checkGithubReady, createComponentPR } = require('./pr-agent.cjs');
|
|
48
50
|
const { runAiEvaluatorPipeline } = require('./ai-evaluator.cjs');
|
|
51
|
+
const { explainFile } = require('./explain.cjs');
|
|
52
|
+
const { generateArcDiff } = require('./diff.cjs');
|
|
49
53
|
|
|
50
54
|
function parseArcOptions(raw = {}) {
|
|
51
55
|
return {
|
|
@@ -59,6 +63,8 @@ function parseArcOptions(raw = {}) {
|
|
|
59
63
|
aiEnabled: Boolean(raw.aiEnabled),
|
|
60
64
|
aiDryRun: Boolean(raw.aiDryRun),
|
|
61
65
|
strict: Boolean(raw.strict),
|
|
66
|
+
verifyRuntime: Boolean(raw.verifyRuntime || raw['verify-runtime']),
|
|
67
|
+
previewUrl: raw.previewUrl || raw['preview-url'] || null,
|
|
62
68
|
};
|
|
63
69
|
}
|
|
64
70
|
|
|
@@ -219,7 +225,7 @@ function auditFivoraContract({ profile, siteData, manifest, inventory }) {
|
|
|
219
225
|
};
|
|
220
226
|
}
|
|
221
227
|
|
|
222
|
-
function analyzeProjectFiles(profile, graph) {
|
|
228
|
+
function analyzeProjectFiles(profile, graph, ir) {
|
|
223
229
|
const analyses = [];
|
|
224
230
|
for (const relativeFile of profile.jsxFiles) {
|
|
225
231
|
const abs = path.join(profile.root, relativeFile);
|
|
@@ -244,6 +250,7 @@ function analyzeProjectFiles(profile, graph) {
|
|
|
244
250
|
graph,
|
|
245
251
|
ownerScope,
|
|
246
252
|
componentMeta,
|
|
253
|
+
ir,
|
|
247
254
|
});
|
|
248
255
|
analyses.push({
|
|
249
256
|
...result,
|
|
@@ -282,7 +289,8 @@ async function runDenebArcAsync(projectDir, projectName, options = {}) {
|
|
|
282
289
|
mergeDetectedPages(profile, opts.detectedPages);
|
|
283
290
|
printer.printProfile(profile);
|
|
284
291
|
const graph = buildDependencyGraph(profile);
|
|
285
|
-
const
|
|
292
|
+
const ir = buildProjectIR(profile);
|
|
293
|
+
const analyses = analyzeProjectFiles(profile, graph, ir);
|
|
286
294
|
|
|
287
295
|
const candidateCount = analyses.reduce(
|
|
288
296
|
(n, a) => n + (a.candidates || []).filter((c) => c.kind !== 'decoration' && c.kind !== 'already-editable' && !c.skip).length,
|
|
@@ -375,7 +383,7 @@ async function runDenebArcAsync(projectDir, projectName, options = {}) {
|
|
|
375
383
|
}
|
|
376
384
|
}
|
|
377
385
|
|
|
378
|
-
const result = runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt);
|
|
386
|
+
const result = runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt, ir);
|
|
379
387
|
|
|
380
388
|
if (!opts.dryRun && result && result.outcome === 'success') {
|
|
381
389
|
printer.printAiEvaluatorStart();
|
|
@@ -416,7 +424,8 @@ function runDenebArcSync(projectDir, projectName, options = {}) {
|
|
|
416
424
|
|
|
417
425
|
printer.printProfile(profile);
|
|
418
426
|
const graph = buildDependencyGraph(profile);
|
|
419
|
-
const
|
|
427
|
+
const ir = buildProjectIR(profile);
|
|
428
|
+
const analyses = analyzeProjectFiles(profile, graph, ir);
|
|
420
429
|
|
|
421
430
|
const candidateCount = analyses.reduce(
|
|
422
431
|
(n, a) => n + (a.candidates || []).filter((c) => c.kind !== 'decoration' && c.kind !== 'already-editable' && !c.skip).length,
|
|
@@ -428,7 +437,7 @@ function runDenebArcSync(projectDir, projectName, options = {}) {
|
|
|
428
437
|
);
|
|
429
438
|
printer.printScan(profile, graph, candidateCount, actionCount);
|
|
430
439
|
|
|
431
|
-
return runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt);
|
|
440
|
+
return runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt, ir);
|
|
432
441
|
}
|
|
433
442
|
|
|
434
443
|
function runDenebArc(projectDir, projectName, options = {}) {
|
|
@@ -439,7 +448,7 @@ function runDenebArc(projectDir, projectName, options = {}) {
|
|
|
439
448
|
return runDenebArcSync(projectDir, projectName, options);
|
|
440
449
|
}
|
|
441
450
|
|
|
442
|
-
function runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt) {
|
|
451
|
+
function runArcTransformations(projectDir, projectName, opts, profile, graph, analyses, runId, startedAt, ir) {
|
|
443
452
|
const sourceAbs = profile.jsxFiles.map((f) => path.join(projectDir, f));
|
|
444
453
|
const recipeMatch = matchRecipeV2(projectDir, profile, sourceAbs, opts.recipeName);
|
|
445
454
|
if (recipeMatch.recipe) {
|
|
@@ -450,6 +459,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
450
459
|
profile,
|
|
451
460
|
analyses,
|
|
452
461
|
recipe: recipeMatch.recipe,
|
|
462
|
+
ir,
|
|
453
463
|
});
|
|
454
464
|
printer.printPlan(plan);
|
|
455
465
|
|
|
@@ -585,6 +595,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
585
595
|
usedPaths,
|
|
586
596
|
componentName: analysis?.componentMeta?.name,
|
|
587
597
|
role: analysis?.componentMeta?.role,
|
|
598
|
+
ir,
|
|
588
599
|
});
|
|
589
600
|
if (!residual.changed) continue;
|
|
590
601
|
try {
|
|
@@ -744,6 +755,18 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
744
755
|
uncoveredVisibleText: fivoraAudit.uncoveredVisibleText,
|
|
745
756
|
});
|
|
746
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
|
+
|
|
747
770
|
const validation = {
|
|
748
771
|
syntaxPassed,
|
|
749
772
|
fivoraContractPassed: fivoraAudit.passed,
|
|
@@ -758,6 +781,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
758
781
|
astFailures: astResults.filter((r) => !r.passed),
|
|
759
782
|
transformFailures,
|
|
760
783
|
designPreservation: design.score,
|
|
784
|
+
runtimeVerification,
|
|
761
785
|
};
|
|
762
786
|
|
|
763
787
|
const criticalFailure = !syntaxPassed || (contracts.actionCollisions > 0 && appliedCount === 0);
|
|
@@ -785,7 +809,11 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
785
809
|
}
|
|
786
810
|
}
|
|
787
811
|
outcome = 'rolled-back';
|
|
788
|
-
|
|
812
|
+
const reasons = [];
|
|
813
|
+
if (!fivoraAudit.passed) reasons.push(`${fivoraAudit.errors.length} Fivora contract error(s)`);
|
|
814
|
+
if (fivoraAudit.uncoveredVisibleText.length > 0) reasons.push(`${fivoraAudit.uncoveredVisibleText.length} uncovered visible text node(s)`);
|
|
815
|
+
if (designFailure) reasons.push(`Design preservation score below threshold (${design.score} < 98)`);
|
|
816
|
+
printer.printRollback(`Strict Fivora contract failed: ${reasons.join(', ')}`);
|
|
789
817
|
} else if (contractFailure) {
|
|
790
818
|
outcome = 'contract-failed';
|
|
791
819
|
} else if (designFailure) {
|
|
@@ -862,6 +890,7 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
862
890
|
designPreservation: design.score,
|
|
863
891
|
validation,
|
|
864
892
|
outcome,
|
|
893
|
+
fontIds: collectFontIdsFromSiteData(dataBundle.siteData),
|
|
865
894
|
};
|
|
866
895
|
|
|
867
896
|
const report = buildReport({
|
|
@@ -886,6 +915,63 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
886
915
|
writeJson(path.join(journalDir, 'validation.json'), validation);
|
|
887
916
|
writeJson(path.join(projectDir, '.deneb', 'report.json'), report);
|
|
888
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
|
+
|
|
889
975
|
if (outcome === 'success') {
|
|
890
976
|
printer.printSuccess();
|
|
891
977
|
printer.printDeveloperNextSteps();
|
|
@@ -950,10 +1036,43 @@ function buildReport(args) {
|
|
|
950
1036
|
};
|
|
951
1037
|
}
|
|
952
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
|
+
|
|
953
1068
|
module.exports = {
|
|
954
1069
|
runDenebArc,
|
|
1070
|
+
runTransactionalPipeline,
|
|
1071
|
+
explainFile,
|
|
1072
|
+
generateArcDiff,
|
|
955
1073
|
parseArcOptions,
|
|
956
1074
|
scanProject,
|
|
1075
|
+
auditFivoraContract,
|
|
957
1076
|
ENGINE_ID,
|
|
958
1077
|
ARC_VERSION,
|
|
959
1078
|
};
|