@onexapis/cli 1.1.66 → 1.1.70
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/dist/cli.js +901 -695
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +898 -692
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +571 -411
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +568 -408
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/templates/default/package.json +5 -0
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import chalk4 from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
-
import
|
|
3
|
+
import fs3 from 'fs';
|
|
4
|
+
import path12 from 'path';
|
|
4
5
|
import { glob } from 'glob';
|
|
5
6
|
import fs from 'fs-extra';
|
|
6
7
|
import crypto from 'crypto';
|
|
8
|
+
import fs10 from 'fs/promises';
|
|
7
9
|
import * as esbuild from 'esbuild';
|
|
8
|
-
import fs8 from 'fs/promises';
|
|
9
10
|
import { createRequire } from 'module';
|
|
10
|
-
import fs3 from 'fs';
|
|
11
11
|
import { execSync, spawn } from 'child_process';
|
|
12
12
|
import inquirer from 'inquirer';
|
|
13
13
|
import ejs from 'ejs';
|
|
@@ -85,6 +85,13 @@ var init_logger = __esm({
|
|
|
85
85
|
logger = new Logger();
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
+
function isNextjsProject(dir) {
|
|
89
|
+
return fs3.existsSync(path12.join(dir, "next.config.ts")) || fs3.existsSync(path12.join(dir, "next.config.js")) || fs3.existsSync(path12.join(dir, "next.config.mjs"));
|
|
90
|
+
}
|
|
91
|
+
var init_detect_nextjs = __esm({
|
|
92
|
+
"src/utils/detect-nextjs.ts"() {
|
|
93
|
+
}
|
|
94
|
+
});
|
|
88
95
|
function sortedCopy(value) {
|
|
89
96
|
if (Array.isArray(value)) {
|
|
90
97
|
return value.map((v) => sortedCopy(v));
|
|
@@ -167,7 +174,7 @@ async function extractSchemas(themePath) {
|
|
|
167
174
|
const sections = {};
|
|
168
175
|
for (const file of schemaFiles) {
|
|
169
176
|
try {
|
|
170
|
-
const mod = await jiti.import(
|
|
177
|
+
const mod = await jiti.import(path12.join(themePath, file));
|
|
171
178
|
const exports$1 = mod;
|
|
172
179
|
for (const value of Object.values(exports$1)) {
|
|
173
180
|
if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
|
|
@@ -195,7 +202,7 @@ var init_extract_schemas = __esm({
|
|
|
195
202
|
}
|
|
196
203
|
});
|
|
197
204
|
function mimeFor(filename) {
|
|
198
|
-
const ext =
|
|
205
|
+
const ext = path12.extname(filename).toLowerCase();
|
|
199
206
|
return MIME_MAP[ext] || "application/octet-stream";
|
|
200
207
|
}
|
|
201
208
|
async function sha256Prefix(absPath, len) {
|
|
@@ -203,15 +210,15 @@ async function sha256Prefix(absPath, len) {
|
|
|
203
210
|
return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
|
|
204
211
|
}
|
|
205
212
|
function insertHashIntoName(relPath, hash) {
|
|
206
|
-
const dir =
|
|
207
|
-
const base =
|
|
208
|
-
const ext =
|
|
213
|
+
const dir = path12.posix.dirname(relPath);
|
|
214
|
+
const base = path12.posix.basename(relPath);
|
|
215
|
+
const ext = path12.posix.extname(base);
|
|
209
216
|
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
210
217
|
const hashed = `${stem}-${hash}${ext}`;
|
|
211
218
|
return dir === "." ? hashed : `${dir}/${hashed}`;
|
|
212
219
|
}
|
|
213
220
|
async function scanThemeAssets(distDir) {
|
|
214
|
-
const assetsDir =
|
|
221
|
+
const assetsDir = path12.join(distDir, "theme-assets");
|
|
215
222
|
if (!await fs.pathExists(assetsDir)) return [];
|
|
216
223
|
const files = await glob("**/*", {
|
|
217
224
|
cwd: assetsDir,
|
|
@@ -220,10 +227,10 @@ async function scanThemeAssets(distDir) {
|
|
|
220
227
|
});
|
|
221
228
|
const results = [];
|
|
222
229
|
for (const rel of files) {
|
|
223
|
-
const absPath =
|
|
230
|
+
const absPath = path12.join(assetsDir, rel);
|
|
224
231
|
const stat = await fs.stat(absPath);
|
|
225
232
|
if (!stat.isFile()) continue;
|
|
226
|
-
const originalPath = rel.split(
|
|
233
|
+
const originalPath = rel.split(path12.sep).join("/");
|
|
227
234
|
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
228
235
|
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
229
236
|
const contentType = mimeFor(rel);
|
|
@@ -266,6 +273,101 @@ var init_scan_theme_assets = __esm({
|
|
|
266
273
|
HASH_LEN = 8;
|
|
267
274
|
}
|
|
268
275
|
});
|
|
276
|
+
async function scanAppDirectory(themePath) {
|
|
277
|
+
const appDir = path12.join(themePath, "app");
|
|
278
|
+
let pageFiles;
|
|
279
|
+
try {
|
|
280
|
+
pageFiles = await glob("**/page.{tsx,ts,jsx,js}", { cwd: appDir });
|
|
281
|
+
} catch {
|
|
282
|
+
return [];
|
|
283
|
+
}
|
|
284
|
+
if (pageFiles.length === 0) return [];
|
|
285
|
+
const pages = [];
|
|
286
|
+
for (const pageFile of pageFiles) {
|
|
287
|
+
const routePath = deriveRoutePath(pageFile);
|
|
288
|
+
const absPageFile = path12.join(appDir, pageFile);
|
|
289
|
+
let source;
|
|
290
|
+
try {
|
|
291
|
+
source = await fs10.readFile(absPageFile, "utf-8");
|
|
292
|
+
} catch {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const sections = await extractSectionsFromPage(source, themePath);
|
|
296
|
+
pages.push({
|
|
297
|
+
routePath,
|
|
298
|
+
sourceFile: path12.join("app", pageFile),
|
|
299
|
+
sections
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return pages;
|
|
303
|
+
}
|
|
304
|
+
function deriveRoutePath(pageFile) {
|
|
305
|
+
const dir = path12.dirname(pageFile);
|
|
306
|
+
if (dir === ".") return "/";
|
|
307
|
+
return "/" + dir;
|
|
308
|
+
}
|
|
309
|
+
async function extractSectionsFromPage(source, themePath) {
|
|
310
|
+
const importRegex = /import\s+\w+\s+from\s+["'](@\/|\.\.?\/)(components\/[^"']+)["']/g;
|
|
311
|
+
const sections = [];
|
|
312
|
+
const seen = /* @__PURE__ */ new Set();
|
|
313
|
+
for (const match of source.matchAll(importRegex)) {
|
|
314
|
+
const rawImportPath = match[2];
|
|
315
|
+
const componentDir = path12.dirname(rawImportPath);
|
|
316
|
+
const absComponentDir = path12.join(themePath, componentDir);
|
|
317
|
+
if (seen.has(componentDir)) continue;
|
|
318
|
+
seen.add(componentDir);
|
|
319
|
+
const sectionJsonPath = path12.join(absComponentDir, "section.json");
|
|
320
|
+
let sectionJson;
|
|
321
|
+
try {
|
|
322
|
+
const raw = await fs10.readFile(sectionJsonPath, "utf-8");
|
|
323
|
+
sectionJson = JSON.parse(raw);
|
|
324
|
+
} catch {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (sectionJson.type !== "opaque-react") continue;
|
|
328
|
+
if (!sectionJson.entry) continue;
|
|
329
|
+
sections.push({
|
|
330
|
+
type: "opaque-react",
|
|
331
|
+
name: sectionJson.name ?? path12.basename(componentDir),
|
|
332
|
+
entry: path12.join(componentDir, sectionJson.entry),
|
|
333
|
+
componentDir
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return sections;
|
|
337
|
+
}
|
|
338
|
+
function buildNextjsPagesMap(pages, themeId) {
|
|
339
|
+
const result = {};
|
|
340
|
+
for (const page of pages) {
|
|
341
|
+
const id = page.routePath === "/" ? "home" : page.routePath.replace(/\//g, "-").replace(/^-/, "");
|
|
342
|
+
const makeSectionType = (name) => `${themeId}-${name.toLowerCase().replace(/\s+/g, "-")}`;
|
|
343
|
+
result[id] = {
|
|
344
|
+
id,
|
|
345
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
346
|
+
path: page.routePath,
|
|
347
|
+
config: {
|
|
348
|
+
id,
|
|
349
|
+
path: page.routePath,
|
|
350
|
+
sections: page.sections.map((s, i) => ({
|
|
351
|
+
id: `${id}-section-${i}`,
|
|
352
|
+
type: makeSectionType(s.name),
|
|
353
|
+
sectionType: "opaque-react",
|
|
354
|
+
settings: {}
|
|
355
|
+
}))
|
|
356
|
+
},
|
|
357
|
+
sections: page.sections.map((s, i) => ({
|
|
358
|
+
id: `${id}-section-${i}`,
|
|
359
|
+
type: makeSectionType(s.name),
|
|
360
|
+
sectionType: "opaque-react",
|
|
361
|
+
settings: {}
|
|
362
|
+
}))
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
return result;
|
|
366
|
+
}
|
|
367
|
+
var init_nextjs_page_scanner = __esm({
|
|
368
|
+
"src/utils/nextjs-page-scanner.ts"() {
|
|
369
|
+
}
|
|
370
|
+
});
|
|
269
371
|
|
|
270
372
|
// src/utils/compile-theme.ts
|
|
271
373
|
var compile_theme_exports = {};
|
|
@@ -281,8 +383,8 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
281
383
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
282
384
|
const tailwindConfig = {
|
|
283
385
|
content: [
|
|
284
|
-
|
|
285
|
-
|
|
386
|
+
path12.join(themePath, "sections/**/*.{ts,tsx}"),
|
|
387
|
+
path12.join(themePath, "components/**/*.{ts,tsx}")
|
|
286
388
|
],
|
|
287
389
|
theme: { extend: {} },
|
|
288
390
|
plugins: []
|
|
@@ -292,7 +394,7 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
292
394
|
inputCSS,
|
|
293
395
|
{ from: void 0 }
|
|
294
396
|
);
|
|
295
|
-
await
|
|
397
|
+
await fs10.writeFile(path12.join(outDir, "bundle.css"), result.css);
|
|
296
398
|
logger.info("Generated bundle.css");
|
|
297
399
|
} catch (err) {
|
|
298
400
|
logger.warning(
|
|
@@ -303,12 +405,12 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
303
405
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
304
406
|
let dir = startDir;
|
|
305
407
|
while (true) {
|
|
306
|
-
const candidate =
|
|
408
|
+
const candidate = path12.join(dir, "node_modules", relativePath);
|
|
307
409
|
try {
|
|
308
|
-
await
|
|
410
|
+
await fs10.access(candidate);
|
|
309
411
|
return candidate;
|
|
310
412
|
} catch {
|
|
311
|
-
const parent =
|
|
413
|
+
const parent = path12.dirname(dir);
|
|
312
414
|
if (parent === dir) break;
|
|
313
415
|
dir = parent;
|
|
314
416
|
}
|
|
@@ -332,7 +434,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
|
|
|
332
434
|
});
|
|
333
435
|
for (const file of sourceFiles) {
|
|
334
436
|
try {
|
|
335
|
-
const content = await
|
|
437
|
+
const content = await fs10.readFile(path12.join(sourceDir, file), "utf-8");
|
|
336
438
|
for (const match of content.matchAll(namespaceImportRegex)) {
|
|
337
439
|
const subpath = match[1] ? match[1].slice(1) : "";
|
|
338
440
|
if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
|
|
@@ -386,17 +488,17 @@ function createCoreGlobalPlugin(themePath) {
|
|
|
386
488
|
const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
|
|
387
489
|
let distPath = await resolveNodeModulesFile(
|
|
388
490
|
themePath,
|
|
389
|
-
|
|
491
|
+
path12.join("@onexapis", "core", "dist", distFileName)
|
|
390
492
|
);
|
|
391
493
|
if (!distPath) {
|
|
392
494
|
distPath = await resolveNodeModulesFile(
|
|
393
495
|
__dirname,
|
|
394
|
-
|
|
496
|
+
path12.join("@onexapis", "core", "dist", distFileName)
|
|
395
497
|
);
|
|
396
498
|
}
|
|
397
499
|
try {
|
|
398
500
|
if (!distPath) throw new Error("not found");
|
|
399
|
-
const distContent = await
|
|
501
|
+
const distContent = await fs10.readFile(distPath, "utf-8");
|
|
400
502
|
const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
|
|
401
503
|
for (const m of exportMatches) {
|
|
402
504
|
const names = m[1].split(",").map((n) => {
|
|
@@ -443,180 +545,6 @@ ${namedExportLines}
|
|
|
443
545
|
}
|
|
444
546
|
};
|
|
445
547
|
}
|
|
446
|
-
function createThemeDepsStubPlugin(themePath) {
|
|
447
|
-
return {
|
|
448
|
-
name: "theme-deps-stub",
|
|
449
|
-
setup(build2) {
|
|
450
|
-
const tryResolveOrStub = (filter, namespace) => {
|
|
451
|
-
build2.onResolve({ filter }, async (args) => {
|
|
452
|
-
if (args.pluginData?.skipStub) return void 0;
|
|
453
|
-
try {
|
|
454
|
-
const result = await build2.resolve(args.path, {
|
|
455
|
-
kind: args.kind,
|
|
456
|
-
resolveDir: args.resolveDir || themePath,
|
|
457
|
-
importer: args.importer,
|
|
458
|
-
namespace: "file",
|
|
459
|
-
pluginData: { skipStub: true }
|
|
460
|
-
});
|
|
461
|
-
if (!result.errors.length) return result;
|
|
462
|
-
} catch {
|
|
463
|
-
}
|
|
464
|
-
try {
|
|
465
|
-
const req = createRequire(import.meta.url || __filename);
|
|
466
|
-
const resolved = req.resolve(args.path);
|
|
467
|
-
if (resolved) return { path: resolved, namespace: "file" };
|
|
468
|
-
} catch {
|
|
469
|
-
}
|
|
470
|
-
return { path: args.path, namespace };
|
|
471
|
-
});
|
|
472
|
-
};
|
|
473
|
-
tryResolveOrStub(/^next\//, "next-stub");
|
|
474
|
-
build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
|
|
475
|
-
const stubs = {
|
|
476
|
-
"next/image": `
|
|
477
|
-
import React from 'react';
|
|
478
|
-
const Image = React.forwardRef((props, ref) => {
|
|
479
|
-
const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
|
|
480
|
-
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
481
|
-
const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
|
|
482
|
-
const mergedStyle = { ...fillStyle, ...style };
|
|
483
|
-
return React.createElement('img', {
|
|
484
|
-
ref, src: imgSrc, alt,
|
|
485
|
-
width: fill ? undefined : width, height: fill ? undefined : height,
|
|
486
|
-
loading: priority ? 'eager' : 'lazy',
|
|
487
|
-
style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
|
|
488
|
-
className, onLoad, onError, ...rest,
|
|
489
|
-
});
|
|
490
|
-
});
|
|
491
|
-
export default Image;
|
|
492
|
-
`,
|
|
493
|
-
"next/link": `
|
|
494
|
-
import React from 'react';
|
|
495
|
-
const Link = ({ href, children, ...rest }) => React.createElement('a', { href, ...rest }, children);
|
|
496
|
-
export default Link;
|
|
497
|
-
`,
|
|
498
|
-
"next/navigation": `
|
|
499
|
-
export function useRouter() { return { push(u){window.location.href=u}, replace(u){window.location.href=u}, back(){window.history.back()}, forward(){window.history.forward()}, refresh(){window.location.reload()}, prefetch(){} }; }
|
|
500
|
-
export function usePathname() { return window.location.pathname; }
|
|
501
|
-
export function useSearchParams() { return new URLSearchParams(window.location.search); }
|
|
502
|
-
export function useParams() { return {}; }
|
|
503
|
-
export function redirect(url) { window.location.href = url; }
|
|
504
|
-
export function notFound() { throw new Error('Not Found'); }
|
|
505
|
-
`,
|
|
506
|
-
"next/headers": `
|
|
507
|
-
export function cookies() { return { get(){}, getAll(){ return []; }, set(){}, delete(){}, has(){ return false; } }; }
|
|
508
|
-
export function headers() { return new Headers(); }
|
|
509
|
-
`
|
|
510
|
-
};
|
|
511
|
-
return {
|
|
512
|
-
contents: stubs[args.path] || "export default {};",
|
|
513
|
-
loader: "jsx",
|
|
514
|
-
resolveDir: themePath
|
|
515
|
-
};
|
|
516
|
-
});
|
|
517
|
-
const lucideImports = /* @__PURE__ */ new Set();
|
|
518
|
-
let lucideThemeScanned = false;
|
|
519
|
-
tryResolveOrStub(/^lucide-react/, "lucide-stub");
|
|
520
|
-
build2.onLoad({ filter: /.*/, namespace: "lucide-stub" }, async () => {
|
|
521
|
-
if (!lucideThemeScanned) {
|
|
522
|
-
lucideThemeScanned = true;
|
|
523
|
-
try {
|
|
524
|
-
const scanned = await scanImportsFromPackage(
|
|
525
|
-
themePath,
|
|
526
|
-
"lucide-react"
|
|
527
|
-
);
|
|
528
|
-
for (const names of Object.values(scanned)) {
|
|
529
|
-
for (const name of names) lucideImports.add(name);
|
|
530
|
-
}
|
|
531
|
-
} catch {
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
const iconNames = [...lucideImports];
|
|
535
|
-
const exports$1 = iconNames.map((n) => `icon as ${n}`).join(", ");
|
|
536
|
-
return {
|
|
537
|
-
contents: `
|
|
538
|
-
const icon = (props) => null;
|
|
539
|
-
export { ${exports$1} };
|
|
540
|
-
export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true : icon });
|
|
541
|
-
`.trim(),
|
|
542
|
-
loader: "jsx"
|
|
543
|
-
};
|
|
544
|
-
});
|
|
545
|
-
tryResolveOrStub(/^framer-motion/, "motion-stub");
|
|
546
|
-
build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
|
|
547
|
-
contents: `
|
|
548
|
-
import React from 'react';
|
|
549
|
-
const handler = { get: (_, name) => {
|
|
550
|
-
if (name === '__esModule') return true;
|
|
551
|
-
return React.forwardRef((props, ref) => React.createElement(name, { ...props, ref }));
|
|
552
|
-
}};
|
|
553
|
-
export const motion = new Proxy({}, handler);
|
|
554
|
-
export const AnimatePresence = ({ children }) => children || null;
|
|
555
|
-
export function useInView() { return true; }
|
|
556
|
-
export default { motion, AnimatePresence, useInView };
|
|
557
|
-
`.trim(),
|
|
558
|
-
loader: "jsx",
|
|
559
|
-
resolveDir: themePath
|
|
560
|
-
}));
|
|
561
|
-
tryResolveOrStub(/^sonner$/, "sonner-stub");
|
|
562
|
-
build2.onLoad({ filter: /.*/, namespace: "sonner-stub" }, () => ({
|
|
563
|
-
contents: `
|
|
564
|
-
export const toast = new Proxy(() => {}, { get: () => () => {} });
|
|
565
|
-
export const Toaster = () => null;
|
|
566
|
-
export default { toast, Toaster };
|
|
567
|
-
`.trim(),
|
|
568
|
-
loader: "jsx"
|
|
569
|
-
}));
|
|
570
|
-
tryResolveOrStub(/^react-hook-form$/, "rhf-stub");
|
|
571
|
-
build2.onLoad({ filter: /.*/, namespace: "rhf-stub" }, () => ({
|
|
572
|
-
contents: `
|
|
573
|
-
export function useForm() {
|
|
574
|
-
return {
|
|
575
|
-
register: () => ({}),
|
|
576
|
-
handleSubmit: (fn) => (e) => { e?.preventDefault?.(); fn({}); },
|
|
577
|
-
formState: { errors: {}, isSubmitting: false, isValid: true },
|
|
578
|
-
watch: () => undefined,
|
|
579
|
-
setValue: () => {},
|
|
580
|
-
reset: () => {},
|
|
581
|
-
control: {},
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
export function useController() { return { field: {}, fieldState: {} }; }
|
|
585
|
-
export function useFormContext() { return useForm(); }
|
|
586
|
-
`.trim(),
|
|
587
|
-
loader: "js"
|
|
588
|
-
}));
|
|
589
|
-
tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
|
|
590
|
-
build2.onLoad(
|
|
591
|
-
{ filter: /.*/, namespace: "hookform-resolvers-stub" },
|
|
592
|
-
() => ({
|
|
593
|
-
contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
|
|
594
|
-
loader: "js"
|
|
595
|
-
})
|
|
596
|
-
);
|
|
597
|
-
tryResolveOrStub(/^next-intl$/, "next-intl-stub");
|
|
598
|
-
build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
|
|
599
|
-
contents: `
|
|
600
|
-
export function useTranslations(ns) {
|
|
601
|
-
return (key) => ns ? ns + '.' + key : key;
|
|
602
|
-
}
|
|
603
|
-
export function useLocale() { return 'en'; }
|
|
604
|
-
export function useMessages() { return {}; }
|
|
605
|
-
`.trim(),
|
|
606
|
-
loader: "js"
|
|
607
|
-
}));
|
|
608
|
-
tryResolveOrStub(/^zod$/, "zod-stub");
|
|
609
|
-
build2.onLoad({ filter: /.*/, namespace: "zod-stub" }, () => ({
|
|
610
|
-
contents: `
|
|
611
|
-
const schema = () => ({ parse: (v) => v, safeParse: (v) => ({ success: true, data: v }), optional: schema, min: schema, max: schema, email: schema, url: schema, regex: schema, refine: schema, transform: schema });
|
|
612
|
-
export const z = { string: schema, number: schema, boolean: schema, object: (s) => ({ ...schema(), shape: s }), array: schema, enum: schema, union: schema, literal: schema, infer: undefined };
|
|
613
|
-
export default z;
|
|
614
|
-
`.trim(),
|
|
615
|
-
loader: "js"
|
|
616
|
-
}));
|
|
617
|
-
}
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
548
|
async function generateThemeData(themePath, outputDir, themeId) {
|
|
621
549
|
const { createJiti } = await import('jiti');
|
|
622
550
|
const jiti = createJiti(import.meta.url);
|
|
@@ -625,7 +553,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
625
553
|
const pages = {};
|
|
626
554
|
for (const ext of [".ts", ".js"]) {
|
|
627
555
|
try {
|
|
628
|
-
const mod = await jiti.import(
|
|
556
|
+
const mod = await jiti.import(path12.join(themePath, `theme.config${ext}`));
|
|
629
557
|
themeConfig = mod.default || mod;
|
|
630
558
|
break;
|
|
631
559
|
} catch {
|
|
@@ -633,20 +561,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
633
561
|
}
|
|
634
562
|
for (const ext of [".ts", ".js"]) {
|
|
635
563
|
try {
|
|
636
|
-
const mod = await jiti.import(
|
|
564
|
+
const mod = await jiti.import(path12.join(themePath, `theme.layout${ext}`));
|
|
637
565
|
layoutConfig = mod.default || mod;
|
|
638
566
|
break;
|
|
639
567
|
} catch {
|
|
640
568
|
}
|
|
641
569
|
}
|
|
642
570
|
const schemas = {};
|
|
643
|
-
const sectionsDir =
|
|
571
|
+
const sectionsDir = path12.join(themePath, "sections");
|
|
644
572
|
try {
|
|
645
|
-
const sectionDirs = await
|
|
573
|
+
const sectionDirs = await fs10.readdir(sectionsDir);
|
|
646
574
|
for (const dir of sectionDirs) {
|
|
647
|
-
const schemaFile =
|
|
575
|
+
const schemaFile = path12.join(sectionsDir, dir, `${dir}.schema.ts`);
|
|
648
576
|
try {
|
|
649
|
-
await
|
|
577
|
+
await fs10.access(schemaFile);
|
|
650
578
|
const mod = await jiti.import(schemaFile);
|
|
651
579
|
for (const [key, value] of Object.entries(mod)) {
|
|
652
580
|
if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
|
|
@@ -658,14 +586,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
658
586
|
}
|
|
659
587
|
} catch {
|
|
660
588
|
}
|
|
661
|
-
const pagesDir =
|
|
589
|
+
const pagesDir = path12.join(themePath, "pages");
|
|
662
590
|
try {
|
|
663
|
-
const files = await
|
|
591
|
+
const files = await fs10.readdir(pagesDir);
|
|
664
592
|
for (const file of files) {
|
|
665
593
|
if (!file.match(/\.(ts|js)$/)) continue;
|
|
666
594
|
const name = file.replace(/\.(ts|js)$/, "");
|
|
667
595
|
try {
|
|
668
|
-
const mod = await jiti.import(
|
|
596
|
+
const mod = await jiti.import(path12.join(pagesDir, file));
|
|
669
597
|
const config = mod.default || mod;
|
|
670
598
|
const sections = (config.sections || []).map((section) => {
|
|
671
599
|
const schema = schemas[section.type];
|
|
@@ -693,8 +621,16 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
693
621
|
}
|
|
694
622
|
} catch {
|
|
695
623
|
}
|
|
696
|
-
|
|
697
|
-
|
|
624
|
+
if (isNextjsProject(themePath)) {
|
|
625
|
+
const nextjsPages = await scanAppDirectory(themePath);
|
|
626
|
+
if (nextjsPages.length > 0) {
|
|
627
|
+
const nextjsPagesMap = buildNextjsPagesMap(nextjsPages, themeId);
|
|
628
|
+
Object.assign(pages, nextjsPagesMap);
|
|
629
|
+
logger.info(`Scanned ${nextjsPages.length} Next.js app/ pages`);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
await fs10.writeFile(
|
|
633
|
+
path12.join(outputDir, "theme-data.json"),
|
|
698
634
|
JSON.stringify(
|
|
699
635
|
{
|
|
700
636
|
themeId,
|
|
@@ -717,22 +653,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
717
653
|
logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
|
|
718
654
|
}
|
|
719
655
|
async function contentHashEntry(outputDir) {
|
|
720
|
-
const entryPath =
|
|
721
|
-
const mapPath =
|
|
656
|
+
const entryPath = path12.join(outputDir, "bundle-entry.js");
|
|
657
|
+
const mapPath = path12.join(outputDir, "bundle-entry.js.map");
|
|
722
658
|
let entryContent;
|
|
723
659
|
try {
|
|
724
|
-
entryContent = await
|
|
660
|
+
entryContent = await fs10.readFile(entryPath, "utf-8");
|
|
725
661
|
} catch {
|
|
726
|
-
const indexPath =
|
|
662
|
+
const indexPath = path12.join(outputDir, "index.js");
|
|
727
663
|
try {
|
|
728
|
-
entryContent = await
|
|
664
|
+
entryContent = await fs10.readFile(indexPath, "utf-8");
|
|
729
665
|
} catch {
|
|
730
666
|
logger.warning("No entry file found in output, skipping content hash");
|
|
731
667
|
return;
|
|
732
668
|
}
|
|
733
669
|
const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
734
670
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
735
|
-
const indexMapPath =
|
|
671
|
+
const indexMapPath = path12.join(outputDir, "index.js.map");
|
|
736
672
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
737
673
|
entryContent = entryContent.replace(
|
|
738
674
|
/\/\/# sourceMappingURL=index\.js\.map/,
|
|
@@ -740,18 +676,18 @@ async function contentHashEntry(outputDir) {
|
|
|
740
676
|
);
|
|
741
677
|
const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
742
678
|
for (const f of oldFiles2) {
|
|
743
|
-
await
|
|
679
|
+
await fs10.unlink(path12.join(outputDir, f));
|
|
744
680
|
}
|
|
745
|
-
await
|
|
746
|
-
await
|
|
681
|
+
await fs10.writeFile(path12.join(outputDir, hashedName2), entryContent);
|
|
682
|
+
await fs10.unlink(indexPath);
|
|
747
683
|
try {
|
|
748
|
-
await
|
|
684
|
+
await fs10.unlink(entryPath);
|
|
749
685
|
} catch {
|
|
750
686
|
}
|
|
751
|
-
await
|
|
687
|
+
await fs10.writeFile(entryPath, entryContent);
|
|
752
688
|
try {
|
|
753
|
-
await
|
|
754
|
-
await
|
|
689
|
+
await fs10.access(indexMapPath);
|
|
690
|
+
await fs10.rename(indexMapPath, path12.join(outputDir, hashedMapName2));
|
|
755
691
|
} catch {
|
|
756
692
|
}
|
|
757
693
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
@@ -766,17 +702,17 @@ async function contentHashEntry(outputDir) {
|
|
|
766
702
|
);
|
|
767
703
|
const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
768
704
|
for (const f of oldFiles) {
|
|
769
|
-
await
|
|
705
|
+
await fs10.unlink(path12.join(outputDir, f));
|
|
770
706
|
}
|
|
771
|
-
await
|
|
707
|
+
await fs10.writeFile(path12.join(outputDir, hashedName), entryContent);
|
|
772
708
|
try {
|
|
773
|
-
await
|
|
709
|
+
await fs10.unlink(entryPath);
|
|
774
710
|
} catch {
|
|
775
711
|
}
|
|
776
|
-
await
|
|
712
|
+
await fs10.writeFile(entryPath, entryContent);
|
|
777
713
|
try {
|
|
778
|
-
await
|
|
779
|
-
await
|
|
714
|
+
await fs10.access(mapPath);
|
|
715
|
+
await fs10.rename(mapPath, path12.join(outputDir, hashedMapName));
|
|
780
716
|
} catch {
|
|
781
717
|
}
|
|
782
718
|
logger.info(`Entry hashed: ${hashedName}`);
|
|
@@ -788,7 +724,7 @@ async function extractDataRequirements(themePath) {
|
|
|
788
724
|
const requirements = {};
|
|
789
725
|
for (const file of schemaFiles) {
|
|
790
726
|
try {
|
|
791
|
-
const mod = await jiti.import(
|
|
727
|
+
const mod = await jiti.import(path12.join(themePath, file));
|
|
792
728
|
const exports$1 = mod;
|
|
793
729
|
for (const value of Object.values(exports$1)) {
|
|
794
730
|
if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
|
|
@@ -806,8 +742,8 @@ async function extractDataRequirements(themePath) {
|
|
|
806
742
|
async function writeGateManifests(themePath, outputDir) {
|
|
807
743
|
try {
|
|
808
744
|
const schemas = await extractSchemas(themePath);
|
|
809
|
-
await
|
|
810
|
-
|
|
745
|
+
await fs10.writeFile(
|
|
746
|
+
path12.join(outputDir, "schemas.json"),
|
|
811
747
|
serializeManifest(schemas)
|
|
812
748
|
);
|
|
813
749
|
logger.info(
|
|
@@ -826,8 +762,8 @@ async function writeGateManifests(themePath, outputDir) {
|
|
|
826
762
|
size: e.size,
|
|
827
763
|
contentType: e.contentType
|
|
828
764
|
}));
|
|
829
|
-
await
|
|
830
|
-
|
|
765
|
+
await fs10.writeFile(
|
|
766
|
+
path12.join(outputDir, "asset-manifest.json"),
|
|
831
767
|
JSON.stringify({ manifestVersion: 1, assets }, null, 2)
|
|
832
768
|
);
|
|
833
769
|
logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
|
|
@@ -837,12 +773,71 @@ async function writeGateManifests(themePath, outputDir) {
|
|
|
837
773
|
);
|
|
838
774
|
}
|
|
839
775
|
}
|
|
776
|
+
async function compileSections(themePath, outputDir) {
|
|
777
|
+
const sectionsDir = path12.join(themePath, "sections");
|
|
778
|
+
let sectionDirs;
|
|
779
|
+
try {
|
|
780
|
+
sectionDirs = await fs10.readdir(sectionsDir);
|
|
781
|
+
} catch {
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
for (const dirName of sectionDirs) {
|
|
785
|
+
const sectionSrc = path12.join(sectionsDir, dirName);
|
|
786
|
+
const sectionOut = path12.join(outputDir, "sections", dirName);
|
|
787
|
+
let section = null;
|
|
788
|
+
try {
|
|
789
|
+
const raw = await fs10.readFile(
|
|
790
|
+
path12.join(sectionSrc, "section.manifest.json"),
|
|
791
|
+
"utf-8"
|
|
792
|
+
);
|
|
793
|
+
section = JSON.parse(raw);
|
|
794
|
+
} catch {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
switch (section.type) {
|
|
798
|
+
case "editable":
|
|
799
|
+
case "opaque-react":
|
|
800
|
+
break;
|
|
801
|
+
case "html": {
|
|
802
|
+
await fs10.mkdir(sectionOut, { recursive: true });
|
|
803
|
+
const htmlSrc = path12.join(sectionSrc, section.html);
|
|
804
|
+
let htmlContent = await fs10.readFile(htmlSrc, "utf-8");
|
|
805
|
+
htmlContent = htmlContent.replace(
|
|
806
|
+
/<script[^>]+src=["']https?:\/\/[^"']*["'][^>]*><\/script>/gi,
|
|
807
|
+
""
|
|
808
|
+
);
|
|
809
|
+
await fs10.writeFile(path12.join(sectionOut, path12.basename(section.html)), htmlContent);
|
|
810
|
+
if (section.css) {
|
|
811
|
+
await fs10.copyFile(
|
|
812
|
+
path12.join(sectionSrc, section.css),
|
|
813
|
+
path12.join(sectionOut, path12.basename(section.css))
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
case "iframe":
|
|
819
|
+
break;
|
|
820
|
+
case "webcomponent": {
|
|
821
|
+
await fs10.mkdir(sectionOut, { recursive: true });
|
|
822
|
+
await fs10.copyFile(
|
|
823
|
+
path12.join(sectionSrc, section.bundle),
|
|
824
|
+
path12.join(sectionOut, path12.basename(section.bundle))
|
|
825
|
+
);
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
default:
|
|
829
|
+
throw new Error(
|
|
830
|
+
`Unknown section type. Valid types: editable, opaque-react, html, iframe, webcomponent`
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
840
835
|
async function generateManifest(themeName, themePath, outputDir) {
|
|
841
836
|
let version = "1.0.0";
|
|
842
837
|
let themeId = themeName;
|
|
843
838
|
try {
|
|
844
|
-
const pkgContent = await
|
|
845
|
-
|
|
839
|
+
const pkgContent = await fs10.readFile(
|
|
840
|
+
path12.join(themePath, "package.json"),
|
|
846
841
|
"utf-8"
|
|
847
842
|
);
|
|
848
843
|
const pkg = JSON.parse(pkgContent);
|
|
@@ -860,7 +855,7 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
860
855
|
const dataRequirements = await extractDataRequirements(themePath);
|
|
861
856
|
let hasThemeConfig = false;
|
|
862
857
|
try {
|
|
863
|
-
await
|
|
858
|
+
await fs10.access(path12.join(themePath, "theme.config.ts"));
|
|
864
859
|
hasThemeConfig = true;
|
|
865
860
|
} catch {
|
|
866
861
|
}
|
|
@@ -901,24 +896,34 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
901
896
|
// Section data requirements for server-side prefetching (keyed by section type)
|
|
902
897
|
dataRequirements
|
|
903
898
|
};
|
|
904
|
-
await
|
|
905
|
-
|
|
899
|
+
await fs10.writeFile(
|
|
900
|
+
path12.join(outputDir, "manifest.json"),
|
|
906
901
|
JSON.stringify(manifest, null, 2)
|
|
907
902
|
);
|
|
908
903
|
}
|
|
909
904
|
async function compileStandaloneTheme(themePath, themeName) {
|
|
910
|
-
const outputDir =
|
|
911
|
-
const
|
|
912
|
-
|
|
905
|
+
const outputDir = path12.join(themePath, "dist");
|
|
906
|
+
const isNextjs = isNextjsProject(themePath);
|
|
907
|
+
if (isNextjs) {
|
|
908
|
+
logger.info("Detected Next.js project \u2014 using next/* shims");
|
|
909
|
+
}
|
|
910
|
+
const bundleEntry = path12.join(themePath, "bundle-entry.ts");
|
|
911
|
+
const indexEntry = path12.join(themePath, "index.ts");
|
|
913
912
|
let entryPoint = indexEntry;
|
|
914
913
|
try {
|
|
915
|
-
await
|
|
914
|
+
await fs10.access(bundleEntry);
|
|
916
915
|
entryPoint = bundleEntry;
|
|
917
916
|
} catch {
|
|
918
917
|
}
|
|
919
|
-
const shimPath =
|
|
920
|
-
await
|
|
921
|
-
await
|
|
918
|
+
const shimPath = path12.join(outputDir, ".process-shim.js");
|
|
919
|
+
await fs10.mkdir(outputDir, { recursive: true });
|
|
920
|
+
await fs10.writeFile(shimPath, PROCESS_SHIM);
|
|
921
|
+
const plugins = [
|
|
922
|
+
reactGlobalPlugin,
|
|
923
|
+
reactQueryGlobalPlugin,
|
|
924
|
+
createCoreGlobalPlugin(themePath)
|
|
925
|
+
];
|
|
926
|
+
if (isNextjs) plugins.unshift(nextShimPlugin);
|
|
922
927
|
const buildOptions = {
|
|
923
928
|
entryPoints: [entryPoint],
|
|
924
929
|
bundle: true,
|
|
@@ -930,12 +935,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
930
935
|
banner: {
|
|
931
936
|
js: '"use client";'
|
|
932
937
|
},
|
|
933
|
-
plugins
|
|
934
|
-
reactGlobalPlugin,
|
|
935
|
-
reactQueryGlobalPlugin,
|
|
936
|
-
createCoreGlobalPlugin(themePath),
|
|
937
|
-
createThemeDepsStubPlugin(themePath)
|
|
938
|
-
],
|
|
938
|
+
plugins,
|
|
939
939
|
external: [],
|
|
940
940
|
alias: {
|
|
941
941
|
events: "events/",
|
|
@@ -969,15 +969,16 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
969
969
|
try {
|
|
970
970
|
const result = await esbuild.build(buildOptions);
|
|
971
971
|
try {
|
|
972
|
-
await
|
|
972
|
+
await fs10.unlink(shimPath);
|
|
973
973
|
} catch {
|
|
974
974
|
}
|
|
975
|
+
await compileSections(themePath, outputDir);
|
|
975
976
|
await contentHashEntry(outputDir);
|
|
976
|
-
const themeAssetsDir =
|
|
977
|
-
const distThemeAssets =
|
|
977
|
+
const themeAssetsDir = path12.join(themePath, "assets");
|
|
978
|
+
const distThemeAssets = path12.join(outputDir, "theme-assets");
|
|
978
979
|
try {
|
|
979
|
-
await
|
|
980
|
-
await
|
|
980
|
+
await fs10.access(themeAssetsDir);
|
|
981
|
+
await fs10.cp(themeAssetsDir, distThemeAssets, { recursive: true });
|
|
981
982
|
logger.info("Copied static assets to dist/theme-assets/");
|
|
982
983
|
} catch {
|
|
983
984
|
}
|
|
@@ -997,7 +998,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
997
998
|
return true;
|
|
998
999
|
} catch (error) {
|
|
999
1000
|
try {
|
|
1000
|
-
await
|
|
1001
|
+
await fs10.unlink(shimPath);
|
|
1001
1002
|
} catch {
|
|
1002
1003
|
}
|
|
1003
1004
|
logger.error(`esbuild compilation failed: ${error}`);
|
|
@@ -1005,18 +1006,25 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
1005
1006
|
}
|
|
1006
1007
|
}
|
|
1007
1008
|
async function compileStandaloneThemeDev(themePath, themeName) {
|
|
1008
|
-
const outputDir =
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1009
|
+
const outputDir = path12.join(themePath, "dist");
|
|
1010
|
+
const isNextjs = isNextjsProject(themePath);
|
|
1011
|
+
const bundleEntry = path12.join(themePath, "bundle-entry.ts");
|
|
1012
|
+
const indexEntry = path12.join(themePath, "index.ts");
|
|
1011
1013
|
let entryPoint = indexEntry;
|
|
1012
1014
|
try {
|
|
1013
|
-
await
|
|
1015
|
+
await fs10.access(bundleEntry);
|
|
1014
1016
|
entryPoint = bundleEntry;
|
|
1015
1017
|
} catch {
|
|
1016
1018
|
}
|
|
1017
|
-
const shimPath =
|
|
1018
|
-
await
|
|
1019
|
-
await
|
|
1019
|
+
const shimPath = path12.join(outputDir, ".process-shim.js");
|
|
1020
|
+
await fs10.mkdir(outputDir, { recursive: true });
|
|
1021
|
+
await fs10.writeFile(shimPath, PROCESS_SHIM);
|
|
1022
|
+
const devPlugins = [
|
|
1023
|
+
reactGlobalPlugin,
|
|
1024
|
+
reactQueryGlobalPlugin,
|
|
1025
|
+
createCoreGlobalPlugin(themePath)
|
|
1026
|
+
];
|
|
1027
|
+
if (isNextjs) devPlugins.unshift(nextShimPlugin);
|
|
1020
1028
|
const buildOptions = {
|
|
1021
1029
|
entryPoints: [entryPoint],
|
|
1022
1030
|
bundle: true,
|
|
@@ -1027,12 +1035,7 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
1027
1035
|
banner: {
|
|
1028
1036
|
js: '"use client";'
|
|
1029
1037
|
},
|
|
1030
|
-
plugins:
|
|
1031
|
-
reactGlobalPlugin,
|
|
1032
|
-
reactQueryGlobalPlugin,
|
|
1033
|
-
createCoreGlobalPlugin(themePath),
|
|
1034
|
-
createThemeDepsStubPlugin(themePath)
|
|
1035
|
-
],
|
|
1038
|
+
plugins: devPlugins,
|
|
1036
1039
|
external: [],
|
|
1037
1040
|
alias: {
|
|
1038
1041
|
events: "events/",
|
|
@@ -1070,18 +1073,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
1070
1073
|
return { context: context2, outputDir };
|
|
1071
1074
|
}
|
|
1072
1075
|
async function compilePreviewRuntime(themePath) {
|
|
1073
|
-
const outputDir =
|
|
1074
|
-
await
|
|
1075
|
-
const outputPath =
|
|
1076
|
+
const outputDir = path12.join(themePath, "dist");
|
|
1077
|
+
await fs10.mkdir(outputDir, { recursive: true });
|
|
1078
|
+
const outputPath = path12.join(outputDir, "preview-runtime.js");
|
|
1076
1079
|
const locations = [
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
+
path12.join(__dirname, "..", "preview", "preview-app.tsx"),
|
|
1081
|
+
path12.join(__dirname, "preview", "preview-app.tsx"),
|
|
1082
|
+
path12.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
|
|
1080
1083
|
];
|
|
1081
1084
|
let previewEntryPath = null;
|
|
1082
1085
|
for (const loc of locations) {
|
|
1083
1086
|
try {
|
|
1084
|
-
await
|
|
1087
|
+
await fs10.access(loc);
|
|
1085
1088
|
previewEntryPath = loc;
|
|
1086
1089
|
break;
|
|
1087
1090
|
} catch {
|
|
@@ -1164,10 +1167,10 @@ ${locations.join("\n")}`
|
|
|
1164
1167
|
if (!lucideScanned) {
|
|
1165
1168
|
lucideScanned = true;
|
|
1166
1169
|
const coreSrcCandidates = [
|
|
1167
|
-
|
|
1168
|
-
|
|
1170
|
+
path12.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
1171
|
+
path12.join(themePath, "..", "..", "packages", "core", "src"),
|
|
1169
1172
|
// monorepo sibling
|
|
1170
|
-
|
|
1173
|
+
path12.join(
|
|
1171
1174
|
__dirname,
|
|
1172
1175
|
"..",
|
|
1173
1176
|
"..",
|
|
@@ -1182,7 +1185,7 @@ ${locations.join("\n")}`
|
|
|
1182
1185
|
let coreSourceDir = null;
|
|
1183
1186
|
for (const candidate of coreSrcCandidates) {
|
|
1184
1187
|
try {
|
|
1185
|
-
await
|
|
1188
|
+
await fs10.access(candidate);
|
|
1186
1189
|
coreSourceDir = candidate;
|
|
1187
1190
|
break;
|
|
1188
1191
|
} catch {
|
|
@@ -1201,21 +1204,21 @@ ${locations.join("\n")}`
|
|
|
1201
1204
|
}
|
|
1202
1205
|
} else {
|
|
1203
1206
|
const coreDistCandidates = [
|
|
1204
|
-
|
|
1207
|
+
path12.join(themePath, "node_modules", "@onexapis", "core", "dist")
|
|
1205
1208
|
];
|
|
1206
1209
|
const resolvedDist = await resolveNodeModulesFile(
|
|
1207
1210
|
__dirname,
|
|
1208
|
-
|
|
1211
|
+
path12.join("@onexapis", "core", "dist")
|
|
1209
1212
|
);
|
|
1210
1213
|
if (resolvedDist) coreDistCandidates.push(resolvedDist);
|
|
1211
1214
|
for (const candidate of coreDistCandidates) {
|
|
1212
1215
|
try {
|
|
1213
|
-
await
|
|
1216
|
+
await fs10.access(candidate);
|
|
1214
1217
|
const mjsFiles = await glob("*.mjs", { cwd: candidate });
|
|
1215
1218
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
1216
1219
|
for (const file of mjsFiles) {
|
|
1217
|
-
const content = await
|
|
1218
|
-
|
|
1220
|
+
const content = await fs10.readFile(
|
|
1221
|
+
path12.join(candidate, file),
|
|
1219
1222
|
"utf-8"
|
|
1220
1223
|
);
|
|
1221
1224
|
for (const match of content.matchAll(importRegex)) {
|
|
@@ -1270,7 +1273,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
1270
1273
|
const req = createRequire(import.meta.url || __filename);
|
|
1271
1274
|
const cjsPath = req.resolve("framer-motion");
|
|
1272
1275
|
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1273
|
-
const esmEntry =
|
|
1276
|
+
const esmEntry = path12.join(pkgDir, "dist", "es", "index.mjs");
|
|
1274
1277
|
const { existsSync } = await import('fs');
|
|
1275
1278
|
if (existsSync(esmEntry)) {
|
|
1276
1279
|
return { path: esmEntry, namespace: "file" };
|
|
@@ -1369,8 +1372,8 @@ export function headers() { return new Headers(); }
|
|
|
1369
1372
|
});
|
|
1370
1373
|
}
|
|
1371
1374
|
};
|
|
1372
|
-
const shimPath =
|
|
1373
|
-
await
|
|
1375
|
+
const shimPath = path12.join(outputDir, ".process-shim-preview.js");
|
|
1376
|
+
await fs10.writeFile(shimPath, PROCESS_SHIM);
|
|
1374
1377
|
await esbuild.build({
|
|
1375
1378
|
entryPoints: [previewEntryPath],
|
|
1376
1379
|
bundle: true,
|
|
@@ -1405,17 +1408,19 @@ export function headers() { return new Headers(); }
|
|
|
1405
1408
|
}
|
|
1406
1409
|
});
|
|
1407
1410
|
try {
|
|
1408
|
-
await
|
|
1411
|
+
await fs10.unlink(shimPath);
|
|
1409
1412
|
} catch {
|
|
1410
1413
|
}
|
|
1411
1414
|
return outputPath;
|
|
1412
1415
|
}
|
|
1413
|
-
var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
|
|
1416
|
+
var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin, nextShimPlugin;
|
|
1414
1417
|
var init_compile_theme = __esm({
|
|
1415
1418
|
"src/utils/compile-theme.ts"() {
|
|
1416
1419
|
init_logger();
|
|
1417
1420
|
init_extract_schemas();
|
|
1418
1421
|
init_scan_theme_assets();
|
|
1422
|
+
init_detect_nextjs();
|
|
1423
|
+
init_nextjs_page_scanner();
|
|
1419
1424
|
PROCESS_SHIM = `
|
|
1420
1425
|
if (typeof process === "undefined") {
|
|
1421
1426
|
globalThis.process = {
|
|
@@ -1561,6 +1566,145 @@ export const {
|
|
|
1561
1566
|
}));
|
|
1562
1567
|
}
|
|
1563
1568
|
};
|
|
1569
|
+
nextShimPlugin = {
|
|
1570
|
+
name: "next-shim",
|
|
1571
|
+
setup(build2) {
|
|
1572
|
+
for (const serverModule of ["next/headers", "next/server", "next/cache"]) {
|
|
1573
|
+
build2.onResolve({ filter: new RegExp(`^${serverModule.replace("/", "\\/")}`) }, (args) => ({
|
|
1574
|
+
path: args.path,
|
|
1575
|
+
namespace: "next-server-error"
|
|
1576
|
+
}));
|
|
1577
|
+
}
|
|
1578
|
+
build2.onLoad({ filter: /.*/, namespace: "next-server-error" }, (args) => ({
|
|
1579
|
+
errors: [
|
|
1580
|
+
{
|
|
1581
|
+
text: `"${args.path}" is server-only and cannot be used in a OneX theme bundle. Use client-side equivalents or remove the import.`
|
|
1582
|
+
}
|
|
1583
|
+
]
|
|
1584
|
+
}));
|
|
1585
|
+
build2.onResolve({ filter: /^next\/navigation$/ }, () => ({
|
|
1586
|
+
path: "next-navigation-shim",
|
|
1587
|
+
namespace: "next-shim"
|
|
1588
|
+
}));
|
|
1589
|
+
build2.onLoad({ filter: /^next-navigation-shim$/, namespace: "next-shim" }, () => ({
|
|
1590
|
+
contents: `
|
|
1591
|
+
export function usePathname() {
|
|
1592
|
+
if (typeof window === 'undefined') return '/';
|
|
1593
|
+
return window.location.pathname;
|
|
1594
|
+
}
|
|
1595
|
+
export function useSearchParams() {
|
|
1596
|
+
if (typeof window === 'undefined') return new URLSearchParams();
|
|
1597
|
+
return new URLSearchParams(window.location.search);
|
|
1598
|
+
}
|
|
1599
|
+
export function useParams() {
|
|
1600
|
+
if (typeof window === 'undefined') return {};
|
|
1601
|
+
return (globalThis.__ONEX_ROUTE_PARAMS__) ?? {};
|
|
1602
|
+
}
|
|
1603
|
+
export function useRouter() {
|
|
1604
|
+
return {
|
|
1605
|
+
push(url) { if (typeof window !== 'undefined') window.location.href = url; },
|
|
1606
|
+
replace(url) { if (typeof window !== 'undefined') window.location.replace(url); },
|
|
1607
|
+
back() { if (typeof window !== 'undefined') window.history.back(); },
|
|
1608
|
+
forward() { if (typeof window !== 'undefined') window.history.forward(); },
|
|
1609
|
+
refresh() { if (typeof window !== 'undefined') window.location.reload(); },
|
|
1610
|
+
prefetch() {},
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
export function redirect(url) {
|
|
1614
|
+
if (typeof window !== 'undefined') window.location.href = url;
|
|
1615
|
+
throw new Error('redirect');
|
|
1616
|
+
}
|
|
1617
|
+
export function notFound() { throw new Error('not-found'); }
|
|
1618
|
+
`.trim(),
|
|
1619
|
+
loader: "js"
|
|
1620
|
+
}));
|
|
1621
|
+
build2.onResolve({ filter: /^next\/font\// }, () => ({
|
|
1622
|
+
path: "next-font-shim",
|
|
1623
|
+
namespace: "next-shim"
|
|
1624
|
+
}));
|
|
1625
|
+
build2.onLoad({ filter: /^next-font-shim$/, namespace: "next-shim" }, () => ({
|
|
1626
|
+
contents: `
|
|
1627
|
+
function makeFont(family) {
|
|
1628
|
+
return function(_opts) {
|
|
1629
|
+
return {
|
|
1630
|
+
className: '',
|
|
1631
|
+
style: { fontFamily: family + ', system-ui, sans-serif' },
|
|
1632
|
+
variable: '--font-' + family.toLowerCase().replace(/\\s+/g, '-'),
|
|
1633
|
+
};
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
export const Inter = makeFont('Inter');
|
|
1637
|
+
export const Roboto = makeFont('Roboto');
|
|
1638
|
+
export const Open_Sans = makeFont('Open Sans');
|
|
1639
|
+
export const Lato = makeFont('Lato');
|
|
1640
|
+
export const Montserrat = makeFont('Montserrat');
|
|
1641
|
+
export const Poppins = makeFont('Poppins');
|
|
1642
|
+
export const Raleway = makeFont('Raleway');
|
|
1643
|
+
export const Nunito = makeFont('Nunito');
|
|
1644
|
+
export const Geist = makeFont('Geist');
|
|
1645
|
+
export const Geist_Mono = makeFont('Geist Mono');
|
|
1646
|
+
export const DM_Sans = makeFont('DM Sans');
|
|
1647
|
+
export const Plus_Jakarta_Sans = makeFont('Plus Jakarta Sans');
|
|
1648
|
+
export function localFont(_opts) {
|
|
1649
|
+
return { className: '', style: { fontFamily: 'system-ui, sans-serif' }, variable: '--font-local' };
|
|
1650
|
+
}
|
|
1651
|
+
`.trim(),
|
|
1652
|
+
loader: "js"
|
|
1653
|
+
}));
|
|
1654
|
+
build2.onResolve({ filter: /^next\/dynamic$/ }, () => ({
|
|
1655
|
+
path: "next-dynamic-shim",
|
|
1656
|
+
namespace: "next-shim"
|
|
1657
|
+
}));
|
|
1658
|
+
build2.onLoad({ filter: /^next-dynamic-shim$/, namespace: "next-shim" }, () => ({
|
|
1659
|
+
contents: `
|
|
1660
|
+
import { lazy, Suspense, createElement } from 'react';
|
|
1661
|
+
export default function dynamic(loader, opts) {
|
|
1662
|
+
const Lazy = lazy(loader);
|
|
1663
|
+
return function DynamicComponent(props) {
|
|
1664
|
+
return createElement(Suspense, { fallback: opts?.loading ? createElement(opts.loading) : null },
|
|
1665
|
+
createElement(Lazy, props));
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
`.trim(),
|
|
1669
|
+
loader: "js"
|
|
1670
|
+
}));
|
|
1671
|
+
build2.onResolve({ filter: /^next\/image$/ }, () => ({
|
|
1672
|
+
path: "next-image-shim",
|
|
1673
|
+
namespace: "next-shim"
|
|
1674
|
+
}));
|
|
1675
|
+
build2.onLoad({ filter: /^next-image-shim$/, namespace: "next-shim" }, () => ({
|
|
1676
|
+
contents: `
|
|
1677
|
+
import { createElement } from 'react';
|
|
1678
|
+
export default function Image({ src, alt, width, height, style, className, ...rest }) {
|
|
1679
|
+
return createElement('img', { src, alt, width, height, style, className, ...rest });
|
|
1680
|
+
}
|
|
1681
|
+
`.trim(),
|
|
1682
|
+
loader: "js"
|
|
1683
|
+
}));
|
|
1684
|
+
build2.onResolve({ filter: /^next\/link$/ }, () => ({
|
|
1685
|
+
path: "next-link-shim",
|
|
1686
|
+
namespace: "next-shim"
|
|
1687
|
+
}));
|
|
1688
|
+
build2.onLoad({ filter: /^next-link-shim$/, namespace: "next-shim" }, () => ({
|
|
1689
|
+
contents: `
|
|
1690
|
+
import { createElement } from 'react';
|
|
1691
|
+
export default function Link({ href, children, className, style, ...rest }) {
|
|
1692
|
+
return createElement('a', { href, className, style, ...rest }, children);
|
|
1693
|
+
}
|
|
1694
|
+
`.trim(),
|
|
1695
|
+
loader: "js"
|
|
1696
|
+
}));
|
|
1697
|
+
build2.onResolve({ filter: /^next\// }, () => ({
|
|
1698
|
+
path: "next-noop-shim",
|
|
1699
|
+
namespace: "next-shim"
|
|
1700
|
+
}));
|
|
1701
|
+
build2.onLoad({ filter: /^next-noop-shim$/, namespace: "next-shim" }, () => ({
|
|
1702
|
+
contents: `export default {};
|
|
1703
|
+
`,
|
|
1704
|
+
loader: "js"
|
|
1705
|
+
}));
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1564
1708
|
}
|
|
1565
1709
|
});
|
|
1566
1710
|
|
|
@@ -1585,8 +1729,8 @@ function validateThemeName(name) {
|
|
|
1585
1729
|
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
1586
1730
|
}
|
|
1587
1731
|
function pathExists(filePath) {
|
|
1588
|
-
const
|
|
1589
|
-
return
|
|
1732
|
+
const fs14 = __require("fs-extra");
|
|
1733
|
+
return fs14.existsSync(filePath);
|
|
1590
1734
|
}
|
|
1591
1735
|
function validateCategory(category) {
|
|
1592
1736
|
const validCategories = [
|
|
@@ -1627,18 +1771,18 @@ async function renderTemplate(templatePath, data) {
|
|
|
1627
1771
|
return ejs.render(template, data);
|
|
1628
1772
|
}
|
|
1629
1773
|
async function writeFile(filePath, content) {
|
|
1630
|
-
await fs.ensureDir(
|
|
1774
|
+
await fs.ensureDir(path12.dirname(filePath));
|
|
1631
1775
|
await fs.writeFile(filePath, content, "utf-8");
|
|
1632
1776
|
}
|
|
1633
1777
|
function getTemplatesDir() {
|
|
1634
1778
|
const locations = [
|
|
1635
|
-
|
|
1779
|
+
path12.join(__dirname, "../../templates"),
|
|
1636
1780
|
// Development
|
|
1637
|
-
|
|
1781
|
+
path12.join(__dirname, "../templates"),
|
|
1638
1782
|
// Production (dist/)
|
|
1639
|
-
|
|
1783
|
+
path12.join(process.cwd(), "templates"),
|
|
1640
1784
|
// Fallback
|
|
1641
|
-
|
|
1785
|
+
path12.join(process.cwd(), "packages/cli/templates")
|
|
1642
1786
|
// Monorepo
|
|
1643
1787
|
];
|
|
1644
1788
|
for (const location of locations) {
|
|
@@ -1650,7 +1794,7 @@ function getTemplatesDir() {
|
|
|
1650
1794
|
}
|
|
1651
1795
|
async function copyTemplate(templateName, targetDir, data) {
|
|
1652
1796
|
const templatesDir = getTemplatesDir();
|
|
1653
|
-
const templateDir =
|
|
1797
|
+
const templateDir = path12.join(templatesDir, templateName);
|
|
1654
1798
|
if (!fs.existsSync(templateDir)) {
|
|
1655
1799
|
throw new Error(
|
|
1656
1800
|
`Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
|
|
@@ -1659,8 +1803,8 @@ async function copyTemplate(templateName, targetDir, data) {
|
|
|
1659
1803
|
await fs.ensureDir(targetDir);
|
|
1660
1804
|
const files = await fs.readdir(templateDir);
|
|
1661
1805
|
for (const file of files) {
|
|
1662
|
-
const templatePath =
|
|
1663
|
-
const targetPath =
|
|
1806
|
+
const templatePath = path12.join(templateDir, file);
|
|
1807
|
+
const targetPath = path12.join(targetDir, file);
|
|
1664
1808
|
const stat = await fs.stat(templatePath);
|
|
1665
1809
|
if (stat.isDirectory()) {
|
|
1666
1810
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1677,8 +1821,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1677
1821
|
await fs.ensureDir(targetDir);
|
|
1678
1822
|
const files = await fs.readdir(templateDir);
|
|
1679
1823
|
for (const file of files) {
|
|
1680
|
-
const templatePath =
|
|
1681
|
-
const targetPath =
|
|
1824
|
+
const templatePath = path12.join(templateDir, file);
|
|
1825
|
+
const targetPath = path12.join(targetDir, file);
|
|
1682
1826
|
const stat = await fs.stat(templatePath);
|
|
1683
1827
|
if (stat.isDirectory()) {
|
|
1684
1828
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1693,32 +1837,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1693
1837
|
}
|
|
1694
1838
|
function getProjectRoot() {
|
|
1695
1839
|
let currentDir = process.cwd();
|
|
1696
|
-
while (currentDir !==
|
|
1697
|
-
const packageJsonPath =
|
|
1840
|
+
while (currentDir !== path12.parse(currentDir).root) {
|
|
1841
|
+
const packageJsonPath = path12.join(currentDir, "package.json");
|
|
1698
1842
|
if (fs.existsSync(packageJsonPath)) {
|
|
1699
1843
|
const packageJson = fs.readJsonSync(packageJsonPath);
|
|
1700
|
-
if (packageJson.workspaces || fs.existsSync(
|
|
1844
|
+
if (packageJson.workspaces || fs.existsSync(path12.join(currentDir, "src/themes")) || fs.existsSync(path12.join(currentDir, "themes"))) {
|
|
1701
1845
|
return currentDir;
|
|
1702
1846
|
}
|
|
1703
1847
|
}
|
|
1704
|
-
currentDir =
|
|
1848
|
+
currentDir = path12.dirname(currentDir);
|
|
1705
1849
|
}
|
|
1706
1850
|
return process.cwd();
|
|
1707
1851
|
}
|
|
1708
1852
|
function getThemesDir() {
|
|
1709
1853
|
const root = getProjectRoot();
|
|
1710
|
-
if (fs.existsSync(
|
|
1711
|
-
return
|
|
1712
|
-
if (fs.existsSync(
|
|
1713
|
-
return
|
|
1714
|
-
return
|
|
1854
|
+
if (fs.existsSync(path12.join(root, "themes")))
|
|
1855
|
+
return path12.join(root, "themes");
|
|
1856
|
+
if (fs.existsSync(path12.join(root, "src/themes")))
|
|
1857
|
+
return path12.join(root, "src/themes");
|
|
1858
|
+
return path12.dirname(root);
|
|
1715
1859
|
}
|
|
1716
1860
|
function getFeaturesDir() {
|
|
1717
|
-
return
|
|
1861
|
+
return path12.join(getProjectRoot(), "src/features");
|
|
1718
1862
|
}
|
|
1719
1863
|
function isOneXProject() {
|
|
1720
1864
|
const root = getProjectRoot();
|
|
1721
|
-
return fs.existsSync(
|
|
1865
|
+
return fs.existsSync(path12.join(root, "themes")) || fs.existsSync(path12.join(root, "src/themes")) || fs.existsSync(path12.join(root, "theme.config.ts")) || fs.existsSync(path12.join(root, "bundle-entry.ts"));
|
|
1722
1866
|
}
|
|
1723
1867
|
function ensureOneXProject() {
|
|
1724
1868
|
if (!isOneXProject()) {
|
|
@@ -1734,13 +1878,13 @@ function listThemes() {
|
|
|
1734
1878
|
return [];
|
|
1735
1879
|
}
|
|
1736
1880
|
return fs.readdirSync(themesDir).filter((name) => {
|
|
1737
|
-
const themePath =
|
|
1738
|
-
return fs.statSync(themePath).isDirectory() && (fs.existsSync(
|
|
1881
|
+
const themePath = path12.join(themesDir, name);
|
|
1882
|
+
return fs.statSync(themePath).isDirectory() && (fs.existsSync(path12.join(themePath, "theme.config.ts")) || fs.existsSync(path12.join(themePath, "bundle-entry.ts")) || fs.existsSync(path12.join(themePath, "manifest.ts")));
|
|
1739
1883
|
});
|
|
1740
1884
|
}
|
|
1741
1885
|
function themeExists(themeName) {
|
|
1742
|
-
const themePath =
|
|
1743
|
-
return fs.existsSync(themePath) && (fs.existsSync(
|
|
1886
|
+
const themePath = path12.join(getThemesDir(), themeName);
|
|
1887
|
+
return fs.existsSync(themePath) && (fs.existsSync(path12.join(themePath, "theme.config.ts")) || fs.existsSync(path12.join(themePath, "bundle-entry.ts")) || fs.existsSync(path12.join(themePath, "manifest.ts")));
|
|
1744
1888
|
}
|
|
1745
1889
|
function detectPackageManager() {
|
|
1746
1890
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -1748,9 +1892,9 @@ function detectPackageManager() {
|
|
|
1748
1892
|
if (userAgent.includes("yarn")) return "yarn";
|
|
1749
1893
|
if (userAgent.includes("bun")) return "bun";
|
|
1750
1894
|
const cwd = process.cwd();
|
|
1751
|
-
if (fs.existsSync(
|
|
1752
|
-
if (fs.existsSync(
|
|
1753
|
-
if (fs.existsSync(
|
|
1895
|
+
if (fs.existsSync(path12.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
1896
|
+
if (fs.existsSync(path12.join(cwd, "yarn.lock"))) return "yarn";
|
|
1897
|
+
if (fs.existsSync(path12.join(cwd, "bun.lockb"))) return "bun";
|
|
1754
1898
|
return "npm";
|
|
1755
1899
|
}
|
|
1756
1900
|
async function installDependencies(projectPath, packageManager = "npm") {
|
|
@@ -1767,16 +1911,16 @@ async function installDependencies(projectPath, packageManager = "npm") {
|
|
|
1767
1911
|
}
|
|
1768
1912
|
});
|
|
1769
1913
|
}
|
|
1770
|
-
var AUTH_DIR =
|
|
1914
|
+
var AUTH_DIR = path12.join(os.homedir(), ".onexthm");
|
|
1771
1915
|
var ENV_URLS = {
|
|
1772
1916
|
dev: "https://platform-dev.onexeos.com",
|
|
1773
1917
|
staging: "https://platform-staging.onexeos.com",
|
|
1774
1918
|
prod: "https://platform-apis.onexeos.com"
|
|
1775
1919
|
};
|
|
1776
1920
|
function getAuthFile(env = "dev") {
|
|
1777
|
-
const newFile =
|
|
1921
|
+
const newFile = path12.join(AUTH_DIR, `auth-${env}.json`);
|
|
1778
1922
|
if (env === "dev") {
|
|
1779
|
-
const legacyFile =
|
|
1923
|
+
const legacyFile = path12.join(AUTH_DIR, "auth.json");
|
|
1780
1924
|
if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
|
|
1781
1925
|
try {
|
|
1782
1926
|
fs.moveSync(legacyFile, newFile);
|
|
@@ -1903,7 +2047,7 @@ function decrypt(text, key) {
|
|
|
1903
2047
|
}
|
|
1904
2048
|
|
|
1905
2049
|
// src/commands/init.ts
|
|
1906
|
-
async function initCommand(projectName, options
|
|
2050
|
+
async function initCommand(projectName, options) {
|
|
1907
2051
|
logger.header("Create New OneX Theme Project");
|
|
1908
2052
|
let name;
|
|
1909
2053
|
if (!projectName) {
|
|
@@ -1918,7 +2062,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1918
2062
|
if (!validateThemeName(kebabName)) {
|
|
1919
2063
|
return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
|
|
1920
2064
|
}
|
|
1921
|
-
if (fs3.existsSync(
|
|
2065
|
+
if (fs3.existsSync(path12.join(process.cwd(), kebabName))) {
|
|
1922
2066
|
return `Directory "${kebabName}" already exists`;
|
|
1923
2067
|
}
|
|
1924
2068
|
return true;
|
|
@@ -1929,14 +2073,14 @@ async function initCommand(projectName, options = {}) {
|
|
|
1929
2073
|
} else {
|
|
1930
2074
|
name = toKebabCase(projectName);
|
|
1931
2075
|
}
|
|
1932
|
-
const projectPath =
|
|
2076
|
+
const projectPath = path12.join(process.cwd(), name);
|
|
1933
2077
|
if (fs3.existsSync(projectPath)) {
|
|
1934
2078
|
logger.error(`Directory "${name}" already exists.`);
|
|
1935
2079
|
process.exit(1);
|
|
1936
2080
|
}
|
|
1937
2081
|
if (!options.yes) {
|
|
1938
2082
|
try {
|
|
1939
|
-
const apiUrl = getApiUrl(options.env
|
|
2083
|
+
const apiUrl = getApiUrl(options.env);
|
|
1940
2084
|
const controller = new AbortController();
|
|
1941
2085
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
1942
2086
|
const response = await fetch(
|
|
@@ -2045,7 +2189,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2045
2189
|
description,
|
|
2046
2190
|
author
|
|
2047
2191
|
);
|
|
2048
|
-
const mcpJsonPath =
|
|
2192
|
+
const mcpJsonPath = path12.join(projectPath, ".mcp.json");
|
|
2049
2193
|
if (fs3.existsSync(mcpJsonPath)) {
|
|
2050
2194
|
let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
|
|
2051
2195
|
if (figmaApiKey) {
|
|
@@ -2125,7 +2269,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2125
2269
|
}
|
|
2126
2270
|
}
|
|
2127
2271
|
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
2128
|
-
const configPath =
|
|
2272
|
+
const configPath = path12.join(projectPath, "theme.config.ts");
|
|
2129
2273
|
if (fs3.existsSync(configPath)) {
|
|
2130
2274
|
let content = fs3.readFileSync(configPath, "utf-8");
|
|
2131
2275
|
content = content.replace(
|
|
@@ -2138,7 +2282,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
2138
2282
|
);
|
|
2139
2283
|
fs3.writeFileSync(configPath, content, "utf-8");
|
|
2140
2284
|
}
|
|
2141
|
-
const pkgPath =
|
|
2285
|
+
const pkgPath = path12.join(projectPath, "package.json");
|
|
2142
2286
|
if (fs3.existsSync(pkgPath)) {
|
|
2143
2287
|
let content = fs3.readFileSync(pkgPath, "utf-8");
|
|
2144
2288
|
content = content.replace(
|
|
@@ -2160,10 +2304,10 @@ async function createSectionCommand(name, options) {
|
|
|
2160
2304
|
ensureOneXProject();
|
|
2161
2305
|
if (!options.theme) {
|
|
2162
2306
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2163
|
-
(f) => fs.existsSync(
|
|
2307
|
+
(f) => fs.existsSync(path12.join(process.cwd(), f))
|
|
2164
2308
|
);
|
|
2165
2309
|
if (isStandaloneTheme) {
|
|
2166
|
-
options.theme =
|
|
2310
|
+
options.theme = path12.basename(process.cwd());
|
|
2167
2311
|
}
|
|
2168
2312
|
}
|
|
2169
2313
|
const sectionName = toKebabCase(name);
|
|
@@ -2226,35 +2370,35 @@ async function createSectionCommand(name, options) {
|
|
|
2226
2370
|
};
|
|
2227
2371
|
logger.startSpinner("Creating section files...");
|
|
2228
2372
|
try {
|
|
2229
|
-
const themePath =
|
|
2230
|
-
const sectionPath =
|
|
2373
|
+
const themePath = path12.join(getThemesDir(), themeName);
|
|
2374
|
+
const sectionPath = path12.join(themePath, "sections", sectionName);
|
|
2231
2375
|
const schemaContent = generateSectionSchema(data);
|
|
2232
2376
|
await writeFile(
|
|
2233
|
-
|
|
2377
|
+
path12.join(sectionPath, `${sectionName}.schema.ts`),
|
|
2234
2378
|
schemaContent
|
|
2235
2379
|
);
|
|
2236
2380
|
if (createTemplate) {
|
|
2237
2381
|
const templateContent = generateSectionTemplate(data);
|
|
2238
2382
|
await writeFile(
|
|
2239
|
-
|
|
2383
|
+
path12.join(sectionPath, `${sectionName}-default.tsx`),
|
|
2240
2384
|
templateContent
|
|
2241
2385
|
);
|
|
2242
2386
|
}
|
|
2243
2387
|
const indexContent = generateSectionIndex(data, createTemplate);
|
|
2244
|
-
await writeFile(
|
|
2388
|
+
await writeFile(path12.join(sectionPath, "index.ts"), indexContent);
|
|
2245
2389
|
logger.stopSpinner(true, "Section files created successfully!");
|
|
2246
2390
|
logger.newLine();
|
|
2247
2391
|
logger.section("Next steps:");
|
|
2248
2392
|
logger.log(
|
|
2249
|
-
` 1. Edit schema: ${
|
|
2393
|
+
` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(sectionPath, `${sectionName}.schema.ts`))}`
|
|
2250
2394
|
);
|
|
2251
2395
|
if (createTemplate) {
|
|
2252
2396
|
logger.log(
|
|
2253
|
-
` 2. Edit template: ${
|
|
2397
|
+
` 2. Edit template: ${path12.relative(process.cwd(), path12.join(sectionPath, `${sectionName}-default.tsx`))}`
|
|
2254
2398
|
);
|
|
2255
2399
|
}
|
|
2256
2400
|
logger.log(
|
|
2257
|
-
` 3. Add to theme manifest: ${
|
|
2401
|
+
` 3. Add to theme manifest: ${path12.relative(process.cwd(), path12.join(themePath, "manifest.ts"))}`
|
|
2258
2402
|
);
|
|
2259
2403
|
logger.newLine();
|
|
2260
2404
|
logger.success("Section created successfully!");
|
|
@@ -2402,10 +2546,10 @@ async function createBlockCommand(name, options) {
|
|
|
2402
2546
|
ensureOneXProject();
|
|
2403
2547
|
if (!options.theme) {
|
|
2404
2548
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2405
|
-
(f) => fs.existsSync(
|
|
2549
|
+
(f) => fs.existsSync(path12.join(process.cwd(), f))
|
|
2406
2550
|
);
|
|
2407
2551
|
if (isStandaloneTheme) {
|
|
2408
|
-
options.theme =
|
|
2552
|
+
options.theme = path12.basename(process.cwd());
|
|
2409
2553
|
}
|
|
2410
2554
|
}
|
|
2411
2555
|
const blockName = toKebabCase(name);
|
|
@@ -2480,24 +2624,24 @@ async function createBlockCommand(name, options) {
|
|
|
2480
2624
|
};
|
|
2481
2625
|
logger.startSpinner("Creating block files...");
|
|
2482
2626
|
try {
|
|
2483
|
-
const blockPath = scope === "shared" ?
|
|
2627
|
+
const blockPath = scope === "shared" ? path12.join(getFeaturesDir(), "blocks", blockName) : path12.join(getThemesDir(), themeName, "blocks", blockName);
|
|
2484
2628
|
const schemaContent = generateBlockSchema(data);
|
|
2485
2629
|
await writeFile(
|
|
2486
|
-
|
|
2630
|
+
path12.join(blockPath, `${blockName}.schema.ts`),
|
|
2487
2631
|
schemaContent
|
|
2488
2632
|
);
|
|
2489
2633
|
const componentContent = generateBlockComponent(data);
|
|
2490
|
-
await writeFile(
|
|
2634
|
+
await writeFile(path12.join(blockPath, `${blockName}.tsx`), componentContent);
|
|
2491
2635
|
const indexContent = generateBlockIndex(data);
|
|
2492
|
-
await writeFile(
|
|
2636
|
+
await writeFile(path12.join(blockPath, "index.ts"), indexContent);
|
|
2493
2637
|
logger.stopSpinner(true, "Block files created successfully!");
|
|
2494
2638
|
logger.newLine();
|
|
2495
2639
|
logger.section("Next steps:");
|
|
2496
2640
|
logger.log(
|
|
2497
|
-
` 1. Edit schema: ${
|
|
2641
|
+
` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(blockPath, `${blockName}.schema.ts`))}`
|
|
2498
2642
|
);
|
|
2499
2643
|
logger.log(
|
|
2500
|
-
` 2. Edit component: ${
|
|
2644
|
+
` 2. Edit component: ${path12.relative(process.cwd(), path12.join(blockPath, `${blockName}.tsx`))}`
|
|
2501
2645
|
);
|
|
2502
2646
|
logger.log(
|
|
2503
2647
|
` 3. Register in block registry: src/lib/registry/block-registry.ts`
|
|
@@ -2675,31 +2819,31 @@ async function createComponentCommand(name, options) {
|
|
|
2675
2819
|
};
|
|
2676
2820
|
logger.startSpinner("Creating component files...");
|
|
2677
2821
|
try {
|
|
2678
|
-
const componentPath =
|
|
2822
|
+
const componentPath = path12.join(
|
|
2679
2823
|
getFeaturesDir(),
|
|
2680
2824
|
"components",
|
|
2681
2825
|
componentName
|
|
2682
2826
|
);
|
|
2683
2827
|
const schemaContent = generateComponentSchema(data);
|
|
2684
2828
|
await writeFile(
|
|
2685
|
-
|
|
2829
|
+
path12.join(componentPath, `${componentName}.schema.ts`),
|
|
2686
2830
|
schemaContent
|
|
2687
2831
|
);
|
|
2688
2832
|
const componentContent = generateComponent(data);
|
|
2689
2833
|
await writeFile(
|
|
2690
|
-
|
|
2834
|
+
path12.join(componentPath, `${componentName}.tsx`),
|
|
2691
2835
|
componentContent
|
|
2692
2836
|
);
|
|
2693
2837
|
const indexContent = generateComponentIndex(data);
|
|
2694
|
-
await writeFile(
|
|
2838
|
+
await writeFile(path12.join(componentPath, "index.ts"), indexContent);
|
|
2695
2839
|
logger.stopSpinner(true, "Component files created successfully!");
|
|
2696
2840
|
logger.newLine();
|
|
2697
2841
|
logger.section("Next steps:");
|
|
2698
2842
|
logger.log(
|
|
2699
|
-
` 1. Edit schema: ${
|
|
2843
|
+
` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(componentPath, `${componentName}.schema.ts`))}`
|
|
2700
2844
|
);
|
|
2701
2845
|
logger.log(
|
|
2702
|
-
` 2. Edit component: ${
|
|
2846
|
+
` 2. Edit component: ${path12.relative(process.cwd(), path12.join(componentPath, `${componentName}.tsx`))}`
|
|
2703
2847
|
);
|
|
2704
2848
|
logger.log(
|
|
2705
2849
|
` 3. Register in component registry: src/lib/registry/component-registry.ts`
|
|
@@ -2856,13 +3000,13 @@ async function listSections(themeFilter) {
|
|
|
2856
3000
|
return;
|
|
2857
3001
|
}
|
|
2858
3002
|
for (const theme of themes) {
|
|
2859
|
-
const sectionsDir =
|
|
3003
|
+
const sectionsDir = path12.join(getThemesDir(), theme, "sections");
|
|
2860
3004
|
if (!fs.existsSync(sectionsDir)) {
|
|
2861
3005
|
continue;
|
|
2862
3006
|
}
|
|
2863
3007
|
const sections = fs.readdirSync(sectionsDir).filter((name) => {
|
|
2864
|
-
const sectionPath =
|
|
2865
|
-
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(
|
|
3008
|
+
const sectionPath = path12.join(sectionsDir, name);
|
|
3009
|
+
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path12.join(sectionPath, "index.ts"));
|
|
2866
3010
|
});
|
|
2867
3011
|
if (sections.length > 0) {
|
|
2868
3012
|
logger.log(chalk4.cyan(`
|
|
@@ -2876,11 +3020,11 @@ async function listSections(themeFilter) {
|
|
|
2876
3020
|
}
|
|
2877
3021
|
async function listBlocks(themeFilter) {
|
|
2878
3022
|
logger.section("\u{1F9F1} Blocks");
|
|
2879
|
-
const sharedBlocksDir =
|
|
3023
|
+
const sharedBlocksDir = path12.join(getFeaturesDir(), "blocks");
|
|
2880
3024
|
if (fs.existsSync(sharedBlocksDir)) {
|
|
2881
3025
|
const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
|
|
2882
|
-
const blockPath =
|
|
2883
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
3026
|
+
const blockPath = path12.join(sharedBlocksDir, name);
|
|
3027
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path12.join(blockPath, "index.ts"));
|
|
2884
3028
|
});
|
|
2885
3029
|
if (sharedBlocks.length > 0) {
|
|
2886
3030
|
logger.log(chalk4.cyan("\n Shared:"));
|
|
@@ -2891,13 +3035,13 @@ async function listBlocks(themeFilter) {
|
|
|
2891
3035
|
}
|
|
2892
3036
|
const themes = themeFilter ? [themeFilter] : listThemes();
|
|
2893
3037
|
for (const theme of themes) {
|
|
2894
|
-
const blocksDir =
|
|
3038
|
+
const blocksDir = path12.join(getThemesDir(), theme, "blocks");
|
|
2895
3039
|
if (!fs.existsSync(blocksDir)) {
|
|
2896
3040
|
continue;
|
|
2897
3041
|
}
|
|
2898
3042
|
const blocks = fs.readdirSync(blocksDir).filter((name) => {
|
|
2899
|
-
const blockPath =
|
|
2900
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
3043
|
+
const blockPath = path12.join(blocksDir, name);
|
|
3044
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path12.join(blockPath, "index.ts"));
|
|
2901
3045
|
});
|
|
2902
3046
|
if (blocks.length > 0) {
|
|
2903
3047
|
logger.log(chalk4.cyan(`
|
|
@@ -2911,14 +3055,14 @@ async function listBlocks(themeFilter) {
|
|
|
2911
3055
|
}
|
|
2912
3056
|
async function listComponents() {
|
|
2913
3057
|
logger.section("\u2699\uFE0F Components");
|
|
2914
|
-
const componentsDir =
|
|
3058
|
+
const componentsDir = path12.join(getFeaturesDir(), "components");
|
|
2915
3059
|
if (!fs.existsSync(componentsDir)) {
|
|
2916
3060
|
logger.warning("No components directory found");
|
|
2917
3061
|
return;
|
|
2918
3062
|
}
|
|
2919
3063
|
const components = fs.readdirSync(componentsDir).filter((name) => {
|
|
2920
|
-
const componentPath =
|
|
2921
|
-
return fs.statSync(componentPath).isDirectory() && fs.existsSync(
|
|
3064
|
+
const componentPath = path12.join(componentsDir, name);
|
|
3065
|
+
return fs.statSync(componentPath).isDirectory() && fs.existsSync(path12.join(componentPath, "index.ts"));
|
|
2922
3066
|
});
|
|
2923
3067
|
if (components.length === 0) {
|
|
2924
3068
|
logger.warning("No components found");
|
|
@@ -2939,11 +3083,11 @@ async function listThemesInfo() {
|
|
|
2939
3083
|
}
|
|
2940
3084
|
logger.log("");
|
|
2941
3085
|
for (const theme of themes) {
|
|
2942
|
-
const themeDir =
|
|
3086
|
+
const themeDir = path12.join(getThemesDir(), theme);
|
|
2943
3087
|
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
2944
3088
|
let manifestContent = "";
|
|
2945
3089
|
for (const candidate of candidates) {
|
|
2946
|
-
const candidatePath =
|
|
3090
|
+
const candidatePath = path12.join(themeDir, candidate);
|
|
2947
3091
|
if (fs.existsSync(candidatePath)) {
|
|
2948
3092
|
manifestContent = fs.readFileSync(candidatePath, "utf-8");
|
|
2949
3093
|
break;
|
|
@@ -2965,6 +3109,7 @@ async function listThemesInfo() {
|
|
|
2965
3109
|
|
|
2966
3110
|
// src/commands/build.ts
|
|
2967
3111
|
init_logger();
|
|
3112
|
+
init_detect_nextjs();
|
|
2968
3113
|
async function buildCommand(options) {
|
|
2969
3114
|
logger.header("Build Theme");
|
|
2970
3115
|
let themePath;
|
|
@@ -2972,14 +3117,14 @@ async function buildCommand(options) {
|
|
|
2972
3117
|
if (options.theme) {
|
|
2973
3118
|
themeName = options.theme;
|
|
2974
3119
|
try {
|
|
2975
|
-
const workspaceThemePath =
|
|
3120
|
+
const workspaceThemePath = path12.join(getThemesDir(), themeName);
|
|
2976
3121
|
if (fs.existsSync(workspaceThemePath)) {
|
|
2977
3122
|
themePath = workspaceThemePath;
|
|
2978
3123
|
} else {
|
|
2979
|
-
themePath =
|
|
3124
|
+
themePath = path12.join(process.cwd(), themeName);
|
|
2980
3125
|
}
|
|
2981
3126
|
} catch {
|
|
2982
|
-
themePath =
|
|
3127
|
+
themePath = path12.join(process.cwd(), themeName);
|
|
2983
3128
|
}
|
|
2984
3129
|
if (!fs.existsSync(themePath)) {
|
|
2985
3130
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -2989,11 +3134,14 @@ async function buildCommand(options) {
|
|
|
2989
3134
|
const isThemeDir = [
|
|
2990
3135
|
"theme.config.ts",
|
|
2991
3136
|
"bundle-entry.ts",
|
|
2992
|
-
"manifest.ts"
|
|
2993
|
-
|
|
3137
|
+
"manifest.ts",
|
|
3138
|
+
"next.config.ts",
|
|
3139
|
+
"next.config.js",
|
|
3140
|
+
"next.config.mjs"
|
|
3141
|
+
].some((f) => fs.existsSync(path12.join(process.cwd(), f)));
|
|
2994
3142
|
if (isThemeDir) {
|
|
2995
3143
|
themePath = process.cwd();
|
|
2996
|
-
themeName =
|
|
3144
|
+
themeName = path12.basename(themePath);
|
|
2997
3145
|
logger.info(`Building current theme: ${themeName}`);
|
|
2998
3146
|
} else {
|
|
2999
3147
|
logger.error(
|
|
@@ -3002,7 +3150,7 @@ async function buildCommand(options) {
|
|
|
3002
3150
|
process.exit(1);
|
|
3003
3151
|
}
|
|
3004
3152
|
}
|
|
3005
|
-
const packageJsonPath =
|
|
3153
|
+
const packageJsonPath = path12.join(themePath, "package.json");
|
|
3006
3154
|
const hasPkgJson = fs.existsSync(packageJsonPath);
|
|
3007
3155
|
if (!hasPkgJson) {
|
|
3008
3156
|
logger.warning(
|
|
@@ -3018,30 +3166,42 @@ async function buildCommand(options) {
|
|
|
3018
3166
|
}
|
|
3019
3167
|
logger.newLine();
|
|
3020
3168
|
logger.section("Build Steps");
|
|
3021
|
-
logger.startSpinner("Running type check...");
|
|
3022
|
-
const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
|
|
3023
|
-
if (!typeCheckSuccess) {
|
|
3024
|
-
logger.stopSpinner(false, "Type check failed");
|
|
3025
|
-
logger.error("Fix type errors before building.");
|
|
3026
|
-
process.exit(1);
|
|
3027
|
-
}
|
|
3028
|
-
logger.stopSpinner(true, "Type check passed");
|
|
3029
|
-
logger.startSpinner("Running linter...");
|
|
3030
|
-
const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
|
|
3031
|
-
if (!lintSuccess) {
|
|
3032
|
-
logger.stopSpinner(false, "Lint failed");
|
|
3033
|
-
logger.error("Fix lint errors before building.");
|
|
3034
|
-
process.exit(1);
|
|
3035
|
-
}
|
|
3036
|
-
logger.stopSpinner(true, "Lint passed");
|
|
3037
3169
|
const pkgJson = fs.readJsonSync(packageJsonPath);
|
|
3170
|
+
if (pkgJson.scripts?.["type-check"]) {
|
|
3171
|
+
logger.startSpinner("Running type check...");
|
|
3172
|
+
const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
|
|
3173
|
+
if (!typeCheckSuccess) {
|
|
3174
|
+
logger.stopSpinner(false, "Type check failed");
|
|
3175
|
+
logger.error("Fix type errors before building.");
|
|
3176
|
+
process.exit(1);
|
|
3177
|
+
}
|
|
3178
|
+
logger.stopSpinner(true, "Type check passed");
|
|
3179
|
+
} else {
|
|
3180
|
+
logger.info("Skipping type check (no type-check script in package.json)");
|
|
3181
|
+
}
|
|
3182
|
+
const isNextjsForLint = isNextjsProject(themePath);
|
|
3183
|
+
if (!isNextjsForLint && pkgJson.scripts?.lint) {
|
|
3184
|
+
logger.startSpinner("Running linter...");
|
|
3185
|
+
const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
|
|
3186
|
+
if (!lintSuccess) {
|
|
3187
|
+
logger.stopSpinner(false, "Lint failed");
|
|
3188
|
+
logger.error("Fix lint errors before building.");
|
|
3189
|
+
process.exit(1);
|
|
3190
|
+
}
|
|
3191
|
+
logger.stopSpinner(true, "Lint passed");
|
|
3192
|
+
} else if (isNextjsForLint) {
|
|
3193
|
+
logger.info("Skipping lint (Next.js project compiled via esbuild)");
|
|
3194
|
+
} else {
|
|
3195
|
+
logger.info("Skipping lint (no lint script in package.json)");
|
|
3196
|
+
}
|
|
3038
3197
|
const buildScript = pkgJson.scripts?.build || "";
|
|
3039
3198
|
const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex build") || buildScript.includes("onex-cli build");
|
|
3199
|
+
const isNextjs = isNextjsProject(themePath);
|
|
3040
3200
|
logger.startSpinner(
|
|
3041
3201
|
options.watch ? "Building (watch mode)..." : "Building..."
|
|
3042
3202
|
);
|
|
3043
3203
|
let buildSuccess;
|
|
3044
|
-
if (isRecursive) {
|
|
3204
|
+
if (isRecursive || isNextjs) {
|
|
3045
3205
|
const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
|
|
3046
3206
|
buildSuccess = await compileStandaloneTheme2(themePath, themeName);
|
|
3047
3207
|
} else {
|
|
@@ -3058,9 +3218,9 @@ async function buildCommand(options) {
|
|
|
3058
3218
|
logger.success("\u2713 Theme built successfully!");
|
|
3059
3219
|
logger.newLine();
|
|
3060
3220
|
logger.info(`Theme: ${themeName}`);
|
|
3061
|
-
const distPath =
|
|
3221
|
+
const distPath = path12.join(themePath, "dist");
|
|
3062
3222
|
if (fs.existsSync(distPath)) {
|
|
3063
|
-
logger.log(`Output: ${
|
|
3223
|
+
logger.log(`Output: ${path12.relative(process.cwd(), distPath)}`);
|
|
3064
3224
|
const files = fs.readdirSync(distPath);
|
|
3065
3225
|
logger.log(`Files: ${files.length}`);
|
|
3066
3226
|
}
|
|
@@ -3201,8 +3361,8 @@ async function downloadBundleZip(apiUrl, themeId, version) {
|
|
|
3201
3361
|
async function createCompatibilityFiles(outputDir, manifest) {
|
|
3202
3362
|
const entryFile = manifest.output?.entry || "bundle-entry.js";
|
|
3203
3363
|
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
3204
|
-
const hashedPath =
|
|
3205
|
-
const stablePath =
|
|
3364
|
+
const hashedPath = path12.join(outputDir, entryFile);
|
|
3365
|
+
const stablePath = path12.join(outputDir, "bundle-entry.js");
|
|
3206
3366
|
if (await fs.pathExists(hashedPath)) {
|
|
3207
3367
|
await fs.copy(hashedPath, stablePath);
|
|
3208
3368
|
const mapPath = hashedPath + ".map";
|
|
@@ -3211,13 +3371,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
|
|
|
3211
3371
|
}
|
|
3212
3372
|
}
|
|
3213
3373
|
}
|
|
3214
|
-
const sectionsRegistryPath =
|
|
3374
|
+
const sectionsRegistryPath = path12.join(outputDir, "sections-registry.js");
|
|
3215
3375
|
const content = `// Re-export all sections from bundle-entry
|
|
3216
3376
|
// This file exists to maintain compatibility with the import path
|
|
3217
3377
|
export * from './bundle-entry.js';
|
|
3218
3378
|
`;
|
|
3219
3379
|
await fs.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
3220
|
-
const pkgJsonPath =
|
|
3380
|
+
const pkgJsonPath = path12.join(outputDir, "package.json");
|
|
3221
3381
|
await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
3222
3382
|
}
|
|
3223
3383
|
function showDownloadFailureHelp(themeId, apiUrl) {
|
|
@@ -3258,7 +3418,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3258
3418
|
}
|
|
3259
3419
|
async function downloadCommand(options) {
|
|
3260
3420
|
logger.header("Download Theme");
|
|
3261
|
-
const env = options.env
|
|
3421
|
+
const env = options.env;
|
|
3262
3422
|
const apiUrl = getApiUrl(env);
|
|
3263
3423
|
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3264
3424
|
const spinner = ora("Initializing download...").start();
|
|
@@ -3316,7 +3476,7 @@ async function downloadCommand(options) {
|
|
|
3316
3476
|
zip.extractAllTo(outputDir, true);
|
|
3317
3477
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
3318
3478
|
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
3319
|
-
const manifestPath =
|
|
3479
|
+
const manifestPath = path12.join(outputDir, "manifest.json");
|
|
3320
3480
|
const manifest = await fs.readJson(manifestPath);
|
|
3321
3481
|
await createCompatibilityFiles(outputDir, manifest);
|
|
3322
3482
|
console.log();
|
|
@@ -3437,7 +3597,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3437
3597
|
const oldPrefix = `${oldName}-`;
|
|
3438
3598
|
const newPrefix = `${newName}-`;
|
|
3439
3599
|
const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3440
|
-
const pkgPath =
|
|
3600
|
+
const pkgPath = path12.join(themeDir, "package.json");
|
|
3441
3601
|
if (await fs.pathExists(pkgPath)) {
|
|
3442
3602
|
const pkg = await fs.readJson(pkgPath);
|
|
3443
3603
|
pkg.name = `@onex-themes/${newName}`;
|
|
@@ -3453,7 +3613,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3453
3613
|
}
|
|
3454
3614
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3455
3615
|
}
|
|
3456
|
-
const configPath =
|
|
3616
|
+
const configPath = path12.join(themeDir, "theme.config.ts");
|
|
3457
3617
|
if (await fs.pathExists(configPath)) {
|
|
3458
3618
|
let content = await fs.readFile(configPath, "utf-8");
|
|
3459
3619
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -3463,7 +3623,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3463
3623
|
);
|
|
3464
3624
|
await fs.writeFile(configPath, content);
|
|
3465
3625
|
}
|
|
3466
|
-
const layoutPath =
|
|
3626
|
+
const layoutPath = path12.join(themeDir, "theme.layout.ts");
|
|
3467
3627
|
if (await fs.pathExists(layoutPath)) {
|
|
3468
3628
|
let content = await fs.readFile(layoutPath, "utf-8");
|
|
3469
3629
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -3476,7 +3636,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3476
3636
|
const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3477
3637
|
const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
|
|
3478
3638
|
for (const file of tsFiles) {
|
|
3479
|
-
const filePath =
|
|
3639
|
+
const filePath = path12.join(themeDir, file);
|
|
3480
3640
|
let content = await fs.readFile(filePath, "utf-8");
|
|
3481
3641
|
const original = content;
|
|
3482
3642
|
content = content.replace(
|
|
@@ -3498,7 +3658,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3498
3658
|
}
|
|
3499
3659
|
async function cloneCommand(themeName, options) {
|
|
3500
3660
|
logger.header("Clone Theme Source");
|
|
3501
|
-
const env = options.env
|
|
3661
|
+
const env = options.env;
|
|
3502
3662
|
const apiUrl = getApiUrl(env);
|
|
3503
3663
|
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3504
3664
|
if (options.bucket) {
|
|
@@ -3519,7 +3679,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3519
3679
|
}
|
|
3520
3680
|
const spinner = ora("Initializing clone...").start();
|
|
3521
3681
|
try {
|
|
3522
|
-
const outputDir = options.output ||
|
|
3682
|
+
const outputDir = options.output || path12.resolve(process.cwd(), newName);
|
|
3523
3683
|
if (await fs.pathExists(outputDir)) {
|
|
3524
3684
|
spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
|
|
3525
3685
|
logger.info(
|
|
@@ -3565,7 +3725,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3565
3725
|
spinner.succeed(
|
|
3566
3726
|
`Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
|
|
3567
3727
|
);
|
|
3568
|
-
const envExamplePath =
|
|
3728
|
+
const envExamplePath = path12.join(outputDir, ".env.example");
|
|
3569
3729
|
if (!await fs.pathExists(envExamplePath)) {
|
|
3570
3730
|
await fs.writeFile(
|
|
3571
3731
|
envExamplePath,
|
|
@@ -3578,7 +3738,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3578
3738
|
].join("\n")
|
|
3579
3739
|
);
|
|
3580
3740
|
}
|
|
3581
|
-
const mcpJsonPath =
|
|
3741
|
+
const mcpJsonPath = path12.join(outputDir, ".mcp.json");
|
|
3582
3742
|
if (await fs.pathExists(mcpJsonPath)) {
|
|
3583
3743
|
const { default: inquirerMod } = await import('inquirer');
|
|
3584
3744
|
const { figmaApiKey } = await inquirerMod.prompt([
|
|
@@ -3603,7 +3763,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3603
3763
|
}
|
|
3604
3764
|
if (options.install !== false) {
|
|
3605
3765
|
const hasPkgJson = await fs.pathExists(
|
|
3606
|
-
|
|
3766
|
+
path12.join(outputDir, "package.json")
|
|
3607
3767
|
);
|
|
3608
3768
|
if (hasPkgJson) {
|
|
3609
3769
|
spinner.start("Installing dependencies...");
|
|
@@ -3631,7 +3791,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3631
3791
|
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
3632
3792
|
console.log();
|
|
3633
3793
|
console.log(chalk4.cyan("Next steps:"));
|
|
3634
|
-
console.log(chalk4.gray(` cd ${
|
|
3794
|
+
console.log(chalk4.gray(` cd ${path12.relative(process.cwd(), outputDir)}`));
|
|
3635
3795
|
console.log(
|
|
3636
3796
|
chalk4.gray(" cp .env.example .env # then add your Company ID")
|
|
3637
3797
|
);
|