@deneb-ui/cli 2.0.83 → 2.0.84
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/package.json +2 -2
- package/src/arc/index.cjs +44 -1
- package/src/arc/learning.cjs +4 -0
- package/src/arc/residual.cjs +9 -1
- package/src/arc/semantic.cjs +43 -0
- package/src/arc/transformer.cjs +10 -5
- package/src/tools/deneb-doctor.cjs +17 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deneb-ui/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.84",
|
|
4
4
|
"description": "Official DENEB CLI — scaffold, convert, validate, and package Fivora-ready storefront templates.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"deneb": "bin/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"license": "MIT",
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@babel/parser": "^7.28.0",
|
|
52
|
-
"@deneb-ui/core": "^2.0.
|
|
52
|
+
"@deneb-ui/core": "^2.0.84",
|
|
53
53
|
"@octokit/rest": "^22.0.1",
|
|
54
54
|
"adm-zip": "^0.6.0",
|
|
55
55
|
"dotenv": "^17.4.2",
|
package/src/arc/index.cjs
CHANGED
|
@@ -613,6 +613,23 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
+
// Mandatory Post-Pass: Guarantee all files referencing siteData have useSiteData hook injected
|
|
617
|
+
const { healMissingSiteDataHooks } = require('./transformer.cjs');
|
|
618
|
+
for (const relativeFile of profile.jsxFiles || []) {
|
|
619
|
+
const abs = path.join(projectDir, relativeFile);
|
|
620
|
+
if (!fs.existsSync(abs)) continue;
|
|
621
|
+
const currentCode = fs.readFileSync(abs, 'utf8');
|
|
622
|
+
if (currentCode.includes('siteData')) {
|
|
623
|
+
const healed = healMissingSiteDataHooks(currentCode, relativeFile);
|
|
624
|
+
if (healed && healed !== currentCode) {
|
|
625
|
+
backupFile(projectDir, backupDir, abs);
|
|
626
|
+
fs.writeFileSync(abs, healed, 'utf8');
|
|
627
|
+
afterFiles[relativeFile] = healed;
|
|
628
|
+
if (!changedFiles.includes(relativeFile)) changedFiles.push(relativeFile);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
616
633
|
if (profile.framework === 'nextjs') {
|
|
617
634
|
const before = findNextConfig(projectDir);
|
|
618
635
|
if (before) backupFile(projectDir, backupDir, before.abs);
|
|
@@ -682,13 +699,39 @@ function runArcTransformations(projectDir, projectName, opts, profile, graph, an
|
|
|
682
699
|
const alreadyEditable = analyses.filter((a) => a.alreadyEditable).length;
|
|
683
700
|
const skippedDynamic = plan.skipped.filter((s) => /dynamic|api/.test(s.reason || '')).length;
|
|
684
701
|
|
|
685
|
-
|
|
702
|
+
let fivoraAudit = auditFivoraContract({
|
|
686
703
|
profile,
|
|
687
704
|
siteData: dataBundle.siteData,
|
|
688
705
|
manifest: dataBundle.manifest,
|
|
689
706
|
inventory: collectMarkerInventory(projectDir, profile, graph),
|
|
690
707
|
});
|
|
691
708
|
|
|
709
|
+
// Auto-reconciliation: If fivoraAudit flagged unknown paths, auto-register them to controlOnlyPaths
|
|
710
|
+
if (!fivoraAudit.passed && fivoraAudit.errors?.length > 0) {
|
|
711
|
+
let manifestModified = false;
|
|
712
|
+
for (const err of fivoraAudit.errors) {
|
|
713
|
+
const unknownMatch = err.match(/references unknown path "([^"]+)"/);
|
|
714
|
+
if (unknownMatch) {
|
|
715
|
+
const unknownPath = unknownMatch[1];
|
|
716
|
+
dataBundle.manifest.visualEditing = dataBundle.manifest.visualEditing || {};
|
|
717
|
+
dataBundle.manifest.visualEditing.controlOnlyPaths = dataBundle.manifest.visualEditing.controlOnlyPaths || [];
|
|
718
|
+
if (!dataBundle.manifest.visualEditing.controlOnlyPaths.includes(unknownPath)) {
|
|
719
|
+
dataBundle.manifest.visualEditing.controlOnlyPaths.push(unknownPath);
|
|
720
|
+
manifestModified = true;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (manifestModified) {
|
|
725
|
+
writeDataBank(projectDir, dataBundle.siteData, dataBundle.manifest);
|
|
726
|
+
fivoraAudit = auditFivoraContract({
|
|
727
|
+
profile,
|
|
728
|
+
siteData: dataBundle.siteData,
|
|
729
|
+
manifest: dataBundle.manifest,
|
|
730
|
+
inventory: collectMarkerInventory(projectDir, profile, graph),
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
692
735
|
const coverage = coverageMetrics({
|
|
693
736
|
analyses,
|
|
694
737
|
plan,
|
package/src/arc/learning.cjs
CHANGED
|
@@ -108,6 +108,10 @@ const BASELINE_VERIFIED_FINGERPRINTS = {
|
|
|
108
108
|
'empty-state-array-guard': { id: 'empty-state-array-guard', state: 'verified', successfulApplications: 50, failedApplications: 0 },
|
|
109
109
|
'action-label-split': { id: 'action-label-split', state: 'verified', successfulApplications: 50, failedApplications: 0 },
|
|
110
110
|
'section-overflow-clip': { id: 'section-overflow-clip', state: 'verified', successfulApplications: 50, failedApplications: 0 },
|
|
111
|
+
'auto-injected-site-data-hook': { id: 'auto-injected-site-data-hook', state: 'verified', successfulApplications: 50, failedApplications: 0 },
|
|
112
|
+
'hidden-preview-marker-strip': { id: 'hidden-preview-marker-strip', state: 'verified', successfulApplications: 50, failedApplications: 0 },
|
|
113
|
+
'unknown-marker-auto-prune': { id: 'unknown-marker-auto-prune', state: 'verified', successfulApplications: 50, failedApplications: 0 },
|
|
114
|
+
'hidden-element-strict-contract': { id: 'hidden-element-strict-contract', state: 'deprecated', successfulApplications: 0, failedApplications: 50 },
|
|
111
115
|
};
|
|
112
116
|
|
|
113
117
|
function loadFingerprintBoost(fingerprint) {
|
package/src/arc/residual.cjs
CHANGED
|
@@ -427,8 +427,16 @@ function applyResidualPass({ code, file, ownerScope, usedPaths, componentName, r
|
|
|
427
427
|
return { code, changed: false, fields: [], applied: 0 };
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
+
let finalCode = printSource(ast, code);
|
|
431
|
+
if (finalCode.includes('siteData')) {
|
|
432
|
+
try {
|
|
433
|
+
const { healMissingSiteDataHooks } = require('./transformer.cjs');
|
|
434
|
+
finalCode = healMissingSiteDataHooks(finalCode, file);
|
|
435
|
+
} catch {}
|
|
436
|
+
}
|
|
437
|
+
|
|
430
438
|
return {
|
|
431
|
-
code:
|
|
439
|
+
code: finalCode,
|
|
432
440
|
changed: true,
|
|
433
441
|
fields,
|
|
434
442
|
applied,
|
package/src/arc/semantic.cjs
CHANGED
|
@@ -286,6 +286,34 @@ function hasStaticMarker(node) {
|
|
|
286
286
|
return hasJsxAttribute(node, 'data-preview-static');
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
function isElementOrParentHidden(pathNode) {
|
|
290
|
+
let current = pathNode;
|
|
291
|
+
while (current) {
|
|
292
|
+
const node = current.node || current.value || current;
|
|
293
|
+
if (node && (node.type === 'JSXElement' || node.type === 'JSXOpeningElement')) {
|
|
294
|
+
const attrs = (node.type === 'JSXElement' ? node.openingElement?.attributes : node.attributes) || [];
|
|
295
|
+
if (attrs.some((a) => a.type === 'JSXAttribute' && a.name && (
|
|
296
|
+
a.name.name === 'hidden' ||
|
|
297
|
+
(a.name.name === 'aria-hidden' && /true/.test(recast.print(a).code))
|
|
298
|
+
))) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
const classAttr = attrs.find((a) => a.type === 'JSXAttribute' && a.name && (a.name.name === 'className' || a.name.name === 'class'));
|
|
302
|
+
if (classAttr) {
|
|
303
|
+
const rawClass = recast.print(classAttr).code;
|
|
304
|
+
if (/(?<![\w-])hidden(?![a-zA-Z0-9_-])/.test(rawClass)) return true;
|
|
305
|
+
}
|
|
306
|
+
const styleAttr = attrs.find((a) => a.type === 'JSXAttribute' && a.name && a.name.name === 'style');
|
|
307
|
+
if (styleAttr) {
|
|
308
|
+
const rawStyle = recast.print(styleAttr).code;
|
|
309
|
+
if (/(?:display\s*:\s*['"]none['"]|visibility\s*:\s*['"]hidden['"])/.test(rawStyle)) return true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
current = current.parentPath || current.parent;
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
289
317
|
function parentNames(pathNode) {
|
|
290
318
|
const names = [];
|
|
291
319
|
let current = pathNode.parent;
|
|
@@ -523,6 +551,21 @@ function analyzeFile({ code, relativeFile, profile, graph, ownerScope, component
|
|
|
523
551
|
return;
|
|
524
552
|
}
|
|
525
553
|
|
|
554
|
+
if (isElementOrParentHidden(pathNode)) {
|
|
555
|
+
candidates.push({
|
|
556
|
+
loc,
|
|
557
|
+
tag: name,
|
|
558
|
+
kind: 'decoration',
|
|
559
|
+
confidence: 0.1,
|
|
560
|
+
skip: true,
|
|
561
|
+
reason: 'hidden-element-strict-contract',
|
|
562
|
+
file: relativeFile,
|
|
563
|
+
ownerScope,
|
|
564
|
+
});
|
|
565
|
+
this.traverse(pathNode);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
526
569
|
const importSource = imports[name.split('.')[0]];
|
|
527
570
|
const recognition = recognizeWithAdapters(node, { profile, imports }, adapters);
|
|
528
571
|
const mapInfo = inMapCallback(pathNode);
|
package/src/arc/transformer.cjs
CHANGED
|
@@ -1537,7 +1537,7 @@ function sanitizeContradictoryMarkers(ast) {
|
|
|
1537
1537
|
}
|
|
1538
1538
|
|
|
1539
1539
|
function sanitizeContradictoryMarkersInSource(code, relativeFile) {
|
|
1540
|
-
if (!code.includes('data-preview-static') && !code.includes('data-preview-field-path') && !code.includes('overflow-hidden')) {
|
|
1540
|
+
if (!code.includes('data-preview-static') && !code.includes('data-preview-field-path') && !code.includes('data-preview-list-path') && !code.includes('data-preview-item-path') && !code.includes('overflow-hidden') && !code.includes('hidden')) {
|
|
1541
1541
|
return { code, updated: false };
|
|
1542
1542
|
}
|
|
1543
1543
|
let ast;
|
|
@@ -1720,10 +1720,15 @@ function healHiddenPreviewMarkers(ast) {
|
|
|
1720
1720
|
if (expr.type === 'TemplateLiteral') classText = (expr.quasis || []).map((q) => q.value.cooked || q.value.raw || '').join(' ');
|
|
1721
1721
|
}
|
|
1722
1722
|
}
|
|
1723
|
-
const
|
|
1724
|
-
(attr) => attr.type === 'JSXAttribute' && attr.name && (
|
|
1725
|
-
|
|
1726
|
-
|
|
1723
|
+
const isHidden =
|
|
1724
|
+
attrs.some((attr) => attr.type === 'JSXAttribute' && attr.name && (
|
|
1725
|
+
attr.name.name === 'hidden' ||
|
|
1726
|
+
(attr.name.name === 'aria-hidden' && /true/.test(recast.print(attr).code))
|
|
1727
|
+
)) ||
|
|
1728
|
+
/(?<![\w-])hidden(?![a-zA-Z0-9_-])/.test(classText) ||
|
|
1729
|
+
attrs.some((attr) => attr.type === 'JSXAttribute' && attr.name && attr.name.name === 'style' && /(?:display\s*:\s*['"]none['"]|visibility\s*:\s*['"]hidden['"])/.test(recast.print(attr).code));
|
|
1730
|
+
|
|
1731
|
+
if (isHidden) {
|
|
1727
1732
|
pathNode.node.attributes = attrs.filter(
|
|
1728
1733
|
(attr) =>
|
|
1729
1734
|
!(
|
|
@@ -201,6 +201,7 @@ function runDoctor(targetDirInput = '.', options = {}) {
|
|
|
201
201
|
// =========================================================================
|
|
202
202
|
if (!isJson) console.log('\n\x1b[1m[2/7] Project Package Configuration:\x1b[0m');
|
|
203
203
|
const suite2 = 'Package Configuration';
|
|
204
|
+
const sourceFiles = findSourceFiles(path.join(targetDir, 'src'));
|
|
204
205
|
|
|
205
206
|
const pkgPath = path.join(targetDir, 'package.json');
|
|
206
207
|
let pkg = null;
|
|
@@ -288,6 +289,20 @@ function runDoctor(targetDirInput = '.', options = {}) {
|
|
|
288
289
|
addCheck(suite2, 'err', 'Platform Engine Compatibility', 'Detected packages requiring Node >=22. Run "deneb doctor --fix" to inject Node 20 overrides.', { code: 'DNB-ENG-001' }) //, 'Detected packages requiring Node >=22. Run "deneb doctor --fix" to inject Node 20 overrides.');
|
|
289
290
|
}
|
|
290
291
|
|
|
292
|
+
// Pre-heal missing useSiteData hooks before tsc runs when --fix is enabled
|
|
293
|
+
if (shouldFix) {
|
|
294
|
+
for (const file of sourceFiles) {
|
|
295
|
+
if (!/\.(tsx|jsx|ts|js)$/.test(file)) continue;
|
|
296
|
+
let c = fs.readFileSync(file, 'utf-8');
|
|
297
|
+
if (c.includes('siteData')) {
|
|
298
|
+
const healed = healMissingSiteDataHooks(c, file);
|
|
299
|
+
if (healed && healed !== c) {
|
|
300
|
+
fs.writeFileSync(file, healed, 'utf8');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
291
306
|
// Check TypeScript compilation preflight
|
|
292
307
|
const tsconfigPath = path.join(targetDir, 'tsconfig.json');
|
|
293
308
|
if (fs.existsSync(tsconfigPath)) {
|
|
@@ -480,7 +495,7 @@ function runDoctor(targetDirInput = '.', options = {}) {
|
|
|
480
495
|
}
|
|
481
496
|
|
|
482
497
|
// Scan all source files for visual editing contract compliance
|
|
483
|
-
|
|
498
|
+
// (sourceFiles already loaded)
|
|
484
499
|
const foundFieldPaths = new Set();
|
|
485
500
|
const orphanPaths = [];
|
|
486
501
|
const missingInSchema = [];
|
|
@@ -869,7 +884,7 @@ function runDoctor(targetDirInput = '.', options = {}) {
|
|
|
869
884
|
for (const file of sourceFiles) {
|
|
870
885
|
if (!/\.(tsx|jsx|ts|js)$/.test(file)) continue;
|
|
871
886
|
let c = fs.readFileSync(file, 'utf-8');
|
|
872
|
-
if (c.includes('siteData')
|
|
887
|
+
if (c.includes('siteData')) {
|
|
873
888
|
const healed = healMissingSiteDataHooks(c, file);
|
|
874
889
|
const norm = (s) => s.replace(/\r\n/g, '\n');
|
|
875
890
|
if (healed && norm(healed) !== norm(c)) {
|