@deneb-ui/cli 2.0.21 → 2.0.22
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 +67 -198
- package/package.json +1 -1
- package/src/recipes/cosmetics-beauty-store.json +1097 -0
- package/src/recipes/electronics-gadgets-store.json +1080 -0
- package/src/recipes/fashion-apparel-store.json +1074 -0
- package/src/tools/deneb-doctor.cjs +646 -0
- package/src/tools/recipe-engine.cjs +30 -0
- package/src/tools/template-converter.cjs +19 -6
package/bin/index.js
CHANGED
|
@@ -444,6 +444,31 @@ function getComponentRegistry(importPkg) {
|
|
|
444
444
|
component: 'EditableProductCard',
|
|
445
445
|
code: `'use client';\n\nimport { EditableProductCard, type EditableProductCardProps } from '${importPkg}';\n\nexport function ProductCard(props: EditableProductCardProps) {\n return <EditableProductCard {...props} />;\n}\n`,
|
|
446
446
|
},
|
|
447
|
+
'product-grid': {
|
|
448
|
+
file: 'ProductGrid.tsx',
|
|
449
|
+
component: 'EditableProductGrid',
|
|
450
|
+
code: `'use client';\n\nimport { EditableProductGrid, ProductGrid, type EditableProductGridProps, type ProductGridItem } from '${importPkg}';\n\nexport { EditableProductGrid, ProductGrid, type EditableProductGridProps, type ProductGridItem };\n`,
|
|
451
|
+
},
|
|
452
|
+
'product-detail': {
|
|
453
|
+
file: 'ProductDetail.tsx',
|
|
454
|
+
component: 'EditableProductDetail',
|
|
455
|
+
code: `'use client';\n\nimport { EditableProductDetail, ProductDetail, type EditableProductDetailProps, type ProductDetailItem } from '${importPkg}';\n\nexport { EditableProductDetail, ProductDetail, type EditableProductDetailProps, type ProductDetailItem };\n`,
|
|
456
|
+
},
|
|
457
|
+
'customer-reviews': {
|
|
458
|
+
file: 'CustomerReviews.tsx',
|
|
459
|
+
component: 'EditableCustomerReviews',
|
|
460
|
+
code: `'use client';\n\nimport { EditableCustomerReviews, CustomerReviews, type EditableCustomerReviewsProps, type CustomerReviewItem } from '${importPkg}';\n\nexport { EditableCustomerReviews, CustomerReviews, type EditableCustomerReviewsProps, type CustomerReviewItem };\n`,
|
|
461
|
+
},
|
|
462
|
+
'cart-drawer': {
|
|
463
|
+
file: 'CartDrawer.tsx',
|
|
464
|
+
component: 'EditableCartDrawer',
|
|
465
|
+
code: `'use client';\n\nimport { EditableCartDrawer, CartDrawer, type EditableCartDrawerProps } from '${importPkg}';\n\nexport { EditableCartDrawer, CartDrawer, type EditableCartDrawerProps };\n`,
|
|
466
|
+
},
|
|
467
|
+
'filter-sidebar': {
|
|
468
|
+
file: 'FilterSidebar.tsx',
|
|
469
|
+
component: 'EditableFilterSidebar',
|
|
470
|
+
code: `'use client';\n\nimport { EditableFilterSidebar, FilterSidebar, type EditableFilterSidebarProps, type FilterOptionGroup } from '${importPkg}';\n\nexport { EditableFilterSidebar, FilterSidebar, type EditableFilterSidebarProps, type FilterOptionGroup };\n`,
|
|
471
|
+
},
|
|
447
472
|
'pricing-card': {
|
|
448
473
|
file: 'PricingCard.tsx',
|
|
449
474
|
component: 'EditablePricingCard',
|
|
@@ -572,7 +597,7 @@ function getComponentRegistry(importPkg) {
|
|
|
572
597
|
};
|
|
573
598
|
}
|
|
574
599
|
|
|
575
|
-
function initProject(targetInput) {
|
|
600
|
+
function initProject(targetInput, options = {}) {
|
|
576
601
|
const targetDir = path.resolve(process.cwd(), targetInput || '.');
|
|
577
602
|
const pkgPath = path.join(targetDir, 'package.json');
|
|
578
603
|
|
|
@@ -621,7 +646,7 @@ function initProject(targetInput) {
|
|
|
621
646
|
let conversionRes = null;
|
|
622
647
|
try {
|
|
623
648
|
const { runUniversalTemplateConversion } = require('../src/tools/template-converter.cjs');
|
|
624
|
-
conversionRes = runUniversalTemplateConversion(targetDir, projectName, detectedPages);
|
|
649
|
+
conversionRes = runUniversalTemplateConversion(targetDir, projectName, detectedPages, options);
|
|
625
650
|
} catch (err) {
|
|
626
651
|
console.error(`\x1b[33mâš Note:\x1b[0m Automated conversion encountered an issue: ${err.message}. Falling back to default generation.`);
|
|
627
652
|
}
|
|
@@ -957,198 +982,9 @@ Options:
|
|
|
957
982
|
], 58) + '\n');
|
|
958
983
|
}
|
|
959
984
|
|
|
960
|
-
function runDoctor(targetDirInput) {
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
console.log('\n' + createBox([
|
|
964
|
-
'\x1b[1m\x1b[36m🩺 DENEB SYSTEM & TEMPLATE DOCTOR\x1b[0m',
|
|
965
|
-
'\x1b[90mComprehensive diagnostic analysis for Fivora & Next.js\x1b[0m',
|
|
966
|
-
`\x1b[37mTarget:\x1b[0m ${targetDir}`
|
|
967
|
-
], 60) + '\n');
|
|
968
|
-
|
|
969
|
-
let passed = 0;
|
|
970
|
-
let warnings = 0;
|
|
971
|
-
let errors = 0;
|
|
972
|
-
|
|
973
|
-
function report(type, title, detail) {
|
|
974
|
-
if (type === 'pass') {
|
|
975
|
-
passed++;
|
|
976
|
-
console.log(` \x1b[32m✔\x1b[0m \x1b[1m${title}\x1b[0m${detail ? ` \x1b[90m(${detail})\x1b[0m` : ''}`);
|
|
977
|
-
} else if (type === 'warn') {
|
|
978
|
-
warnings++;
|
|
979
|
-
console.log(` \x1b[33mâš \x1b[0m \x1b[33m${title}\x1b[0m${detail ? ` \x1b[90m- ${detail}\x1b[0m` : ''}`);
|
|
980
|
-
} else {
|
|
981
|
-
errors++;
|
|
982
|
-
console.log(` \x1b[31m✖\x1b[0m \x1b[31m${title}\x1b[0m${detail ? ` \x1b[90m- ${detail}\x1b[0m` : ''}`);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
console.log('\x1b[1m[1/6] System & Runtime Environment:\x1b[0m');
|
|
987
|
-
const nodeVersion = process.version;
|
|
988
|
-
const majorNode = parseInt(nodeVersion.replace(/^v/, '').split('.')[0], 10);
|
|
989
|
-
if (majorNode >= 18) {
|
|
990
|
-
report('pass', 'Node.js Runtime', `${nodeVersion} (Supported)`);
|
|
991
|
-
} else {
|
|
992
|
-
report('err', 'Node.js Runtime', `${nodeVersion} (Requires Node.js >= 18.0.0)`);
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
996
|
-
const npmCheck = spawnSync(npmBin, ['--version'], { encoding: 'utf-8', shell: process.platform === 'win32' });
|
|
997
|
-
if (!npmCheck.error && npmCheck.status === 0) {
|
|
998
|
-
report('pass', 'Package Manager', `npm v${npmCheck.stdout.trim()}`);
|
|
999
|
-
} else {
|
|
1000
|
-
report('warn', 'Package Manager', 'npm not found in system PATH');
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
console.log('\n\x1b[1m[2/6] Project Package Configuration:\x1b[0m');
|
|
1004
|
-
const pkgPath = path.join(targetDir, 'package.json');
|
|
1005
|
-
let pkg = null;
|
|
1006
|
-
if (fs.existsSync(pkgPath)) {
|
|
1007
|
-
try {
|
|
1008
|
-
pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
1009
|
-
report('pass', 'package.json', `Found "${pkg.name || 'unnamed'}"`);
|
|
1010
|
-
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
1011
|
-
|
|
1012
|
-
if (allDeps['next']) {
|
|
1013
|
-
report('pass', 'Next.js Framework', allDeps['next']);
|
|
1014
|
-
} else {
|
|
1015
|
-
report('err', 'Next.js Framework', 'next dependency missing in package.json');
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
if (allDeps['@deneb-ui/ui']) {
|
|
1019
|
-
report('pass', '@deneb-ui/ui Library', allDeps['@deneb-ui/ui']);
|
|
1020
|
-
} else {
|
|
1021
|
-
report('warn', '@deneb-ui/ui Library', 'Not installed (run "npm i @deneb-ui/ui")');
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
if (allDeps['@deneb-ui/cli']) {
|
|
1025
|
-
report('pass', '@deneb-ui/cli Tooling', allDeps['@deneb-ui/cli']);
|
|
1026
|
-
} else {
|
|
1027
|
-
report('warn', '@deneb-ui/cli Tooling', 'Recommended for local CLI scripts');
|
|
1028
|
-
}
|
|
1029
|
-
} catch (e) {
|
|
1030
|
-
report('err', 'package.json Syntax', e.message);
|
|
1031
|
-
}
|
|
1032
|
-
} else {
|
|
1033
|
-
report('err', 'package.json', `Not found at ${pkgPath}`);
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
console.log('\n\x1b[1m[3/6] Static Export Configuration:\x1b[0m');
|
|
1037
|
-
const nextConfigTs = path.join(targetDir, 'next.config.ts');
|
|
1038
|
-
const nextConfigMjs = path.join(targetDir, 'next.config.mjs');
|
|
1039
|
-
const nextConfigJs = path.join(targetDir, 'next.config.js');
|
|
1040
|
-
let nextConfigFile = [nextConfigTs, nextConfigMjs, nextConfigJs].find((p) => fs.existsSync(p));
|
|
1041
|
-
|
|
1042
|
-
if (nextConfigFile) {
|
|
1043
|
-
const content = fs.readFileSync(nextConfigFile, 'utf-8');
|
|
1044
|
-
if (content.includes("output: 'export'") || content.includes('output: "export"')) {
|
|
1045
|
-
report('pass', 'Next.js Static Export', `output: 'export' verified in ${path.basename(nextConfigFile)}`);
|
|
1046
|
-
} else {
|
|
1047
|
-
report('err', 'Next.js Static Export', `Missing output: 'export' in ${path.basename(nextConfigFile)} (Required by Fivora)`);
|
|
1048
|
-
}
|
|
1049
|
-
} else {
|
|
1050
|
-
report('err', 'Next.js Config', 'No next.config.ts, next.config.mjs, or next.config.js found');
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
console.log('\n\x1b[1m[4/6] Fivora Manifest v2 Contract:\x1b[0m');
|
|
1054
|
-
const manifestPath = path.join(targetDir, 'fivora-template.json');
|
|
1055
|
-
let manifestData = null;
|
|
1056
|
-
if (fs.existsSync(manifestPath)) {
|
|
1057
|
-
try {
|
|
1058
|
-
manifestData = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
1059
|
-
report('pass', 'fivora-template.json', `Valid JSON (strict=${manifestData.strict !== false})`);
|
|
1060
|
-
|
|
1061
|
-
if (manifestData.version === 2 || manifestData.version === '2') {
|
|
1062
|
-
report('pass', 'Manifest Version', 'Version 2 (Current standard)');
|
|
1063
|
-
} else {
|
|
1064
|
-
report('warn', 'Manifest Version', `Version ${manifestData.version} detected (Recommend version 2)`);
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
const hasHome = Array.isArray(manifestData.pages) && manifestData.pages.some((p) =>
|
|
1068
|
-
p.route === '/' || p.slug === '/' || p.path === '/' || p.id === 'home'
|
|
1069
|
-
);
|
|
1070
|
-
if (hasHome) {
|
|
1071
|
-
report('pass', 'Home Page Entry', 'Home page ("/") declared in manifest');
|
|
1072
|
-
} else {
|
|
1073
|
-
report('err', 'Home Page Entry', 'Manifest pages array missing root slug or route: "/"');
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
if (manifestData.theme && (manifestData.theme.primary || manifestData.theme.accent)) {
|
|
1077
|
-
report('pass', 'Theme Configuration', 'Primary and accent color tokens declared');
|
|
1078
|
-
} else {
|
|
1079
|
-
// Will check site-data.json below as alternative
|
|
1080
|
-
}
|
|
1081
|
-
} catch (e) {
|
|
1082
|
-
report('err', 'fivora-template.json Syntax', e.message);
|
|
1083
|
-
}
|
|
1084
|
-
} else {
|
|
1085
|
-
report('err', 'fivora-template.json', 'File not found. Run "deneb init" to generate it');
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
console.log('\n\x1b[1m[5/6] Reactive Site Data & Visual Editing:\x1b[0m');
|
|
1089
|
-
const siteDataPath = path.join(targetDir, 'src', 'data', 'site-data.json');
|
|
1090
|
-
if (fs.existsSync(siteDataPath)) {
|
|
1091
|
-
try {
|
|
1092
|
-
const siteData = JSON.parse(fs.readFileSync(siteDataPath, 'utf-8'));
|
|
1093
|
-
report('pass', 'site-data.json', 'src/data/site-data.json exists & valid');
|
|
1094
|
-
const merchantName = (siteData.merchant && (siteData.merchant.businessName || siteData.merchant.name)) || null;
|
|
1095
|
-
if (merchantName) {
|
|
1096
|
-
report('pass', 'Merchant Metadata', `Name: "${merchantName}"`);
|
|
1097
|
-
} else {
|
|
1098
|
-
report('warn', 'Merchant Metadata', 'Missing merchant name in site-data.json');
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
const themeTokens = manifestData?.theme || siteData?.template?.structure?.theme;
|
|
1102
|
-
if (themeTokens && (themeTokens.primaryColor || themeTokens.primary || themeTokens.accentColor || themeTokens.accent)) {
|
|
1103
|
-
report('pass', 'Theme Design Tokens', 'Theme color tokens declared');
|
|
1104
|
-
} else {
|
|
1105
|
-
report('warn', 'Theme Design Tokens', 'No theme color tokens found in manifest or site-data.json');
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
if (siteData.content) {
|
|
1109
|
-
report('pass', 'Visual Content Bindings', 'Content section ready for live sync');
|
|
1110
|
-
} else {
|
|
1111
|
-
report('warn', 'Visual Content Bindings', 'Missing content section in site-data.json');
|
|
1112
|
-
}
|
|
1113
|
-
} catch (e) {
|
|
1114
|
-
report('err', 'site-data.json Syntax', e.message);
|
|
1115
|
-
}
|
|
1116
|
-
} else {
|
|
1117
|
-
report('warn', 'site-data.json', 'src/data/site-data.json not found. Recommended for Fivora live editor');
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
console.log('\n\x1b[1m[6/6] Cleanliness & Security Check:\x1b[0m');
|
|
1121
|
-
const envFiles = ['.env', '.env.local', '.env.production', '.env.development'];
|
|
1122
|
-
const foundEnv = envFiles.filter((f) => fs.existsSync(path.join(targetDir, f)));
|
|
1123
|
-
if (foundEnv.length === 0) {
|
|
1124
|
-
report('pass', 'Secrets Isolation', 'No raw .env files detected in root directory');
|
|
1125
|
-
} else {
|
|
1126
|
-
report('warn', 'Secrets Isolation', `Active env files: ${foundEnv.join(', ')} (Excluded during packaging)`);
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
const previewExists = fs.existsSync(path.join(targetDir, 'preview.png')) ||
|
|
1130
|
-
fs.existsSync(path.join(targetDir, 'thumbnail.png')) ||
|
|
1131
|
-
fs.existsSync(path.join(targetDir, 'public', 'fivora-logo.png'));
|
|
1132
|
-
if (previewExists) {
|
|
1133
|
-
report('pass', 'Storefront Assets', 'Brand/preview graphics verified');
|
|
1134
|
-
} else {
|
|
1135
|
-
report('warn', 'Storefront Assets', 'preview.png not found in template root');
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
// Summary
|
|
1139
|
-
console.log('\n' + createBox([
|
|
1140
|
-
'\x1b[1mDOCTOR DIAGNOSTIC SUMMARY\x1b[0m',
|
|
1141
|
-
`\x1b[32m✔ Passed:\x1b[0m ${passed}`,
|
|
1142
|
-
`\x1b[33mâš Warnings:\x1b[0m ${warnings}`,
|
|
1143
|
-
`\x1b[31m✖ Errors:\x1b[0m ${errors}`,
|
|
1144
|
-
errors === 0
|
|
1145
|
-
? '\x1b[32mStatus: HEALTHY — Ready for Fivora packaging & build!\x1b[0m'
|
|
1146
|
-
: '\x1b[31mStatus: ATTENTION REQUIRED — Fix errors before deployment\x1b[0m'
|
|
1147
|
-
], 58) + '\n');
|
|
1148
|
-
|
|
1149
|
-
if (errors > 0) {
|
|
1150
|
-
process.exit(1);
|
|
1151
|
-
}
|
|
985
|
+
function runDoctor(targetDirInput, options = {}) {
|
|
986
|
+
const { runDoctor: executeDoctor } = require('../src/tools/deneb-doctor.cjs');
|
|
987
|
+
return executeDoctor(targetDirInput, options);
|
|
1152
988
|
}
|
|
1153
989
|
|
|
1154
990
|
// Normalize multi-word "validate and zip" or "validate & zip"
|
|
@@ -1161,13 +997,41 @@ if (command === 'validate' && (commandArgs[0] === 'and' || commandArgs[0] === '&
|
|
|
1161
997
|
}
|
|
1162
998
|
|
|
1163
999
|
if (command === 'init') {
|
|
1164
|
-
|
|
1000
|
+
let targetInput = '.';
|
|
1001
|
+
let recipeName = null;
|
|
1002
|
+
for (let i = 0; i < commandArgs.length; i++) {
|
|
1003
|
+
const arg = commandArgs[i];
|
|
1004
|
+
if (arg === '--recipe' || arg === '-r') {
|
|
1005
|
+
recipeName = commandArgs[++i];
|
|
1006
|
+
} else if (arg.startsWith('--recipe=')) {
|
|
1007
|
+
recipeName = arg.split('=')[1];
|
|
1008
|
+
} else if (!arg.startsWith('-')) {
|
|
1009
|
+
targetInput = arg;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
initProject(targetInput, { recipeName });
|
|
1165
1013
|
} else if (command === 'create') {
|
|
1166
1014
|
createTemplate(commandArgs[0]);
|
|
1167
1015
|
} else if (command === 'add') {
|
|
1168
1016
|
addComponent(commandArgs[0], commandArgs[1]);
|
|
1169
1017
|
} else if (command === 'doctor' || command === 'check') {
|
|
1170
|
-
|
|
1018
|
+
let targetInput = '.';
|
|
1019
|
+
let fix = false;
|
|
1020
|
+
let json = false;
|
|
1021
|
+
for (let i = 0; i < commandArgs.length; i++) {
|
|
1022
|
+
const arg = commandArgs[i];
|
|
1023
|
+
if (arg === '--fix' || arg === '-f') {
|
|
1024
|
+
fix = true;
|
|
1025
|
+
} else if (arg === '--json') {
|
|
1026
|
+
json = true;
|
|
1027
|
+
} else if (!arg.startsWith('-')) {
|
|
1028
|
+
targetInput = arg;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
const res = runDoctor(targetInput, { fix, json });
|
|
1032
|
+
if (res && res.errors > 0) {
|
|
1033
|
+
process.exit(1);
|
|
1034
|
+
}
|
|
1171
1035
|
} else if (command === 'lab') {
|
|
1172
1036
|
const script = path.join(toolsDir, 'local-template-lab.cjs');
|
|
1173
1037
|
const res = spawnSync(process.execPath, [script, ...commandArgs], { stdio: 'inherit' });
|
|
@@ -1208,12 +1072,12 @@ if (command === 'init') {
|
|
|
1208
1072
|
DENEB UI Framework — Powered by DENEB-UI Collaborate with FIVORA
|
|
1209
1073
|
|
|
1210
1074
|
Core Commands:
|
|
1211
|
-
init Auto-convert & configure existing Next.js
|
|
1075
|
+
init Auto-convert & configure existing Next.js into editable Fivora storefront (e.g. deneb init --recipe fashion)
|
|
1076
|
+
doctor Run comprehensive environment, manifest, visual editing AST & asset diagnostic checks (flags: --fix, --json)
|
|
1212
1077
|
save-recipe Learn and save calibrated fixes & schemas into reusable recipe bank (e.g. deneb save-recipe . shoes-store)
|
|
1213
1078
|
learn Alias for save-recipe
|
|
1214
1079
|
update Update DENEB packages (@deneb-ui/ui, @deneb-ui/cli) and UI components
|
|
1215
1080
|
validate Validate website configuration and visual editing contracts with Fivora platform
|
|
1216
|
-
doctor Run comprehensive environment, manifest & asset diagnostic checks
|
|
1217
1081
|
zip Zip the project without unnecessary folders or files (node_modules, .next, .git, .env)
|
|
1218
1082
|
validate-and-zip Validate website configuration and immediately package clean upload-ready ZIP
|
|
1219
1083
|
|
|
@@ -1226,7 +1090,12 @@ Development & Scaffolding:
|
|
|
1226
1090
|
|
|
1227
1091
|
Examples:
|
|
1228
1092
|
deneb doctor
|
|
1093
|
+
deneb doctor --fix
|
|
1094
|
+
deneb doctor --json
|
|
1229
1095
|
deneb init
|
|
1096
|
+
deneb init --recipe fashion
|
|
1097
|
+
deneb init --recipe electronics
|
|
1098
|
+
deneb init --recipe cosmetics
|
|
1230
1099
|
deneb update
|
|
1231
1100
|
deneb validate .
|
|
1232
1101
|
deneb validate --zip
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deneb-ui/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.22",
|
|
4
4
|
"description": "Official developer CLI for DENEB UI — Validating, scaffolding, testing, and packaging storefront templates. Created by Chamika Gayashan & Induranga Kawishwara.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"deneb": "bin/index.js",
|