@supernovaio/cli 2.0.37 → 2.0.38
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/commands/template-upload.d.ts +4 -2
- package/dist/commands/template-upload.d.ts.map +1 -1
- package/dist/commands/template-upload.js +47 -17
- package/dist/commands/template-upload.js.map +1 -1
- package/dist/utils/discover.d.ts +21 -0
- package/dist/utils/discover.d.ts.map +1 -0
- package/dist/utils/discover.js +305 -0
- package/dist/utils/discover.js.map +1 -0
- package/dist/utils/validate-templates.d.ts +16 -0
- package/dist/utils/validate-templates.d.ts.map +1 -0
- package/dist/utils/validate-templates.js +140 -0
- package/dist/utils/validate-templates.js.map +1 -0
- package/oclif.manifest.json +18 -3
- package/package.json +1 -1
|
@@ -8,10 +8,12 @@ export default class TemplateUpload extends SentryCommand<TemplateUploadConfig>
|
|
|
8
8
|
static examples: string[];
|
|
9
9
|
static hidden: boolean;
|
|
10
10
|
static flags: {
|
|
11
|
-
workspaceId: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
-
designSystemId: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
workspaceId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
designSystemId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
13
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
14
|
npmToken: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
discover: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
17
|
};
|
|
16
18
|
get commandId(): string;
|
|
17
19
|
get configSchema(): ZodType<TemplateUploadConfig>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-upload.d.ts","sourceRoot":"","sources":["../../src/commands/template-upload.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAIhC,OAAO,EAAe,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"template-upload.d.ts","sourceRoot":"","sources":["../../src/commands/template-upload.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAIhC,OAAO,EAAe,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAc9D,QAAA,MAAM,oBAAoB,gDAAe,CAAA;AAEzC,KAAK,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAahE,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,aAAa,CAAC,oBAAoB,CAAC;IAC7E,OAAgB,IAAI,KAAK;IACzB,OAAgB,WAAW,SAAqD;IAChF,OAAgB,QAAQ,WAA0D;IAClF,OAAgB,MAAM,EAAE,OAAO,CAAQ;IACvC,OAAgB,KAAK;;;;;;;MA4BpB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,YAAY,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAEhD;IAGY,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA8FnB,oBAAoB;IAMlC,OAAO,CAAC,cAAc;YAIR,cAAc;YAId,kBAAkB;YAclB,gBAAgB;YAyBhB,eAAe;YAkBf,mBAAmB;YA0BnB,iCAAiC;CA8FhD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b80a82ae-3a40-5488-a3cf-4d8210ab28a6")}catch(e){}}();
|
|
3
3
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
4
4
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5
5
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -23,17 +23,10 @@ import crypto from "node:crypto";
|
|
|
23
23
|
import { commonFlags, SentryCommand } from "../types/index.js";
|
|
24
24
|
import { sleep } from "../utils/common.js";
|
|
25
25
|
import { tmpdir } from "node:os";
|
|
26
|
+
import { discoverAndUpdatePackageJson, discoverFilesForTemplates } from "../utils/discover.js";
|
|
27
|
+
import { validateTemplates, fileExists } from "../utils/validate-templates.js";
|
|
26
28
|
const exec = promisify(execCallback);
|
|
27
29
|
const TemplateUploadConfig = z.object({});
|
|
28
|
-
async function fileExists(p) {
|
|
29
|
-
try {
|
|
30
|
-
await fs.access(p);
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
30
|
const dockerfileTemplate = `
|
|
38
31
|
FROM node:22-slim
|
|
39
32
|
|
|
@@ -52,11 +45,11 @@ export default class TemplateUpload extends SentryCommand {
|
|
|
52
45
|
static hidden = false;
|
|
53
46
|
static flags = {
|
|
54
47
|
...commonFlags,
|
|
55
|
-
workspaceId: Flags.string({ char: "w", description: "Workspace ID to upload the template to", required:
|
|
48
|
+
workspaceId: Flags.string({ char: "w", description: "Workspace ID to upload the template to", required: false }),
|
|
56
49
|
designSystemId: Flags.string({
|
|
57
50
|
char: "d",
|
|
58
51
|
description: "Design system ID to upload the template to",
|
|
59
|
-
required:
|
|
52
|
+
required: false,
|
|
60
53
|
}),
|
|
61
54
|
force: Flags.boolean({
|
|
62
55
|
char: "f",
|
|
@@ -67,6 +60,15 @@ export default class TemplateUpload extends SentryCommand {
|
|
|
67
60
|
description: "Allows passing NPM token as a Docker secret. The token will be available as a NPM_TOKEN env variable",
|
|
68
61
|
required: false,
|
|
69
62
|
}),
|
|
63
|
+
discover: Flags.boolean({
|
|
64
|
+
description: "Run template and pattern discovery before upload to update package.json",
|
|
65
|
+
required: false,
|
|
66
|
+
}),
|
|
67
|
+
debug: Flags.boolean({
|
|
68
|
+
description: "Preserve shell directory and App.tsx on template build failures for debugging",
|
|
69
|
+
required: false,
|
|
70
|
+
hidden: true,
|
|
71
|
+
}),
|
|
70
72
|
};
|
|
71
73
|
get commandId() {
|
|
72
74
|
return TemplateUpload.id;
|
|
@@ -77,6 +79,31 @@ export default class TemplateUpload extends SentryCommand {
|
|
|
77
79
|
async run() {
|
|
78
80
|
const apiClient = await this.apiClient();
|
|
79
81
|
const { flags } = await this.parse();
|
|
82
|
+
if (flags.discover) {
|
|
83
|
+
action.start("🔍 Running template and pattern discovery");
|
|
84
|
+
try {
|
|
85
|
+
const { templates, patterns } = await discoverAndUpdatePackageJson(process.cwd());
|
|
86
|
+
action.stop(`found ${Object.keys(templates).length} templates, ${Object.keys(patterns).length} patterns`);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
action.stop("failed");
|
|
90
|
+
if (error instanceof Error)
|
|
91
|
+
this.error(`Discovery failed: ${error.message}`);
|
|
92
|
+
else
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const isDiscoverOnly = flags.discover && !flags.workspaceId && !flags.designSystemId;
|
|
97
|
+
if (isDiscoverOnly) {
|
|
98
|
+
this.log("✅ Discovery completed. Use --workspaceId and --designSystemId to upload templates.");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!flags.workspaceId) {
|
|
102
|
+
this.error("Missing required flag workspaceId");
|
|
103
|
+
}
|
|
104
|
+
if (!flags.designSystemId) {
|
|
105
|
+
this.error("Missing required flag designSystemId");
|
|
106
|
+
}
|
|
80
107
|
let pkg;
|
|
81
108
|
try {
|
|
82
109
|
pkg = await readPackageJson();
|
|
@@ -98,9 +125,12 @@ export default class TemplateUpload extends SentryCommand {
|
|
|
98
125
|
this.warn(`package.json doesn't contain 'supernova.privateDependencies' declaration.`);
|
|
99
126
|
this.warn(`Dependencies coming from private registries will fail`);
|
|
100
127
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
let templatesWithThumbnailUrls;
|
|
129
|
+
if (pkg.supernova?.templates) {
|
|
130
|
+
const templates = await discoverFilesForTemplates(pkg.supernova.templates, process.cwd());
|
|
131
|
+
await validateTemplates(templates, this, flags.debug);
|
|
132
|
+
templatesWithThumbnailUrls = await this.uploadThumbnailsAndBuildTemplates(apiClient, flags.workspaceId, templates);
|
|
133
|
+
}
|
|
104
134
|
const buildData = await apiClient.sandboxes.builds.start({
|
|
105
135
|
workspaceId: flags.workspaceId,
|
|
106
136
|
designSystemId: flags.designSystemId,
|
|
@@ -334,7 +364,7 @@ async function uploadFilesToUrls(uploadUrls, fileResponses, thumbnailFiles) {
|
|
|
334
364
|
function buildTemplateUrlMap(thumbnailFiles, fileResponses) {
|
|
335
365
|
const thumbnailUrlMap = {};
|
|
336
366
|
for (const thumbnailFile of thumbnailFiles) {
|
|
337
|
-
const fileResponse = fileResponses.find(f => f.
|
|
367
|
+
const fileResponse = fileResponses.find(f => f.deduplicationKey === thumbnailFile.checksum);
|
|
338
368
|
if (fileResponse) {
|
|
339
369
|
thumbnailUrlMap[thumbnailFile.templateId] = fileResponse.url;
|
|
340
370
|
}
|
|
@@ -351,4 +381,4 @@ async function getFileSize(filePath) {
|
|
|
351
381
|
return stats.size;
|
|
352
382
|
}
|
|
353
383
|
//# sourceMappingURL=template-upload.js.map
|
|
354
|
-
//# debugId=
|
|
384
|
+
//# debugId=b80a82ae-3a40-5488-a3cf-4d8210ab28a6
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-upload.js","sources":["../../src/commands/template-upload.ts"],"sourceRoot":"","sourcesContent":["import fetch from \"node-fetch\"\nimport { Flags } from \"@oclif/core\"\nimport { action } from \"@oclif/core/ux\"\nimport { SentryTraced } from \"@sentry/nestjs\"\nimport { exec as execCallback } from \"node:child_process\"\nimport * as fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { promisify } from \"node:util\"\nimport { z, ZodType } from \"zod\"\nimport fsx from \"fs-extra\"\nimport crypto from \"node:crypto\"\n\nimport { commonFlags, SentryCommand } from \"../types/index.js\"\n\nimport {\n DTOSandboxTemplateBuildCreateResponse,\n DTOSandboxTemplateBuildCreateInput,\n SupernovaApiClient,\n} from \"@supernova-studio/client\"\nimport { sleep } from \"../utils/common.js\"\nimport { tmpdir } from \"node:os\"\n\nconst exec = promisify(execCallback)\n\nconst TemplateUploadConfig = z.object({})\n\ntype TemplateUploadConfig = z.infer<typeof TemplateUploadConfig>\ntype TemplatePreset = { name: string; description: string; thumbnail?: string; files?: string[] }\n\nasync function fileExists(p: string) {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\nconst dockerfileTemplate = `\nFROM node:22-slim\n\nRUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /home/user\n\nCOPY . .\nRUN {{ npmTokenSecretMount }} npm i && truncate -s 0 .npmrc\nRUN node docker-scripts/extract-private-packages.js\n`\nexport default class TemplateUpload extends SentryCommand<TemplateUploadConfig> {\n static override args = {}\n static override description = \"Upload component container template to Supernova\"\n static override examples = [\"<%= config.bin %> <%= command.id %> TemplateUpload \"]\n static override hidden: boolean = false\n static override flags = {\n ...commonFlags,\n workspaceId: Flags.string({ char: \"w\", description: \"Workspace ID to upload the template to\", required: true }),\n designSystemId: Flags.string({\n char: \"d\",\n description: \"Design system ID to upload the template to\",\n required: true,\n }),\n force: Flags.boolean({\n char: \"f\",\n description:\n \"Allows overwriting already published version of this template if it exists. This flag has no effect on new versions.\",\n required: false,\n }),\n npmToken: Flags.string({\n description:\n \"Allows passing NPM token as a Docker secret. The token will be available as a NPM_TOKEN env variable\",\n required: false,\n }),\n }\n\n get commandId(): string {\n return TemplateUpload.id\n }\n\n get configSchema(): ZodType<TemplateUploadConfig> {\n return TemplateUploadConfig\n }\n\n @SentryTraced()\n public async run(): Promise<void> {\n const apiClient = await this.apiClient()\n const { flags } = await this.parse()\n\n // Read package json\n let pkg\n try {\n pkg = await readPackageJson()\n } catch (error) {\n if (error instanceof Error) this.error(`Failed to read or parse package.json: ${error.message}`)\n else throw error\n }\n\n if (pkg.supernova?.privateDependencies) {\n this.log(`Following packages will be linked as private dependencies: ${pkg.supernova.privateDependencies}`)\n\n if (!(await fileExists(path.join(process.cwd(), \".npmrc\")))) {\n this.error(\n `CLI needs private NPM registry access to be able to bundle private dependencies.\\n` +\n `Please provide .npmrc file in the root directory and include neccessary access tokens.`,\n )\n }\n } else {\n this.warn(`package.json doesn't contain 'supernova.privateDependencies' declaration.`)\n this.warn(`Dependencies coming from private registries will fail`)\n }\n\n const templatesWithThumbnailUrls = pkg.supernova?.templates\n ? await this.uploadThumbnailsAndBuildTemplates(apiClient, flags.workspaceId, pkg.supernova.templates)\n : undefined\n\n // Request build\n const buildData = await apiClient.sandboxes.builds.start({\n workspaceId: flags.workspaceId,\n designSystemId: flags.designSystemId,\n name: pkg.name,\n version: pkg.version,\n isExistingVersionUpdateAllowed: flags.force ?? false,\n templates: templatesWithThumbnailUrls,\n })\n\n // Build image\n const url = imageUrl(buildData)\n\n await this.validateDockerDaemon()\n const buildDir = await this.createBuildDir()\n\n try {\n await this.prepareBuildFolder(buildDir)\n await this.buildDockerImage(buildDir, url, flags.npmToken)\n await this.pushDockerImage(buildDir, buildData.dockerRegistryDomain, url)\n await this.remoteTemplateBuild(apiClient, buildData.build.id)\n\n this.log(`✅ Template has been successfully uploaded`)\n } finally {\n await this.deleteBuildDir(buildDir)\n }\n }\n\n private async validateDockerDaemon() {\n await exec(\"docker info\").catch(() => {\n this.error(`Docker is not available, please start docker daemon and try again`)\n })\n }\n\n private createBuildDir(): Promise<string> {\n return fs.mkdtemp(path.join(tmpdir(), \"supernova-template-bundle-\"))\n }\n\n private async deleteBuildDir(buildDir: string) {\n await fs.rm(buildDir, { recursive: true, force: true })\n }\n\n private async prepareBuildFolder(buildDir: string) {\n // Move working directory to temp folder from where it will be built\n await fsx.copy(process.cwd(), buildDir, {\n filter(src) {\n return !src.includes(\"node_modules/\") && !src.includes(\".git/\") && !src.includes(\".out/\")\n },\n })\n\n // Inject Supernova scripts\n const cliSrcPath = path.resolve(path.dirname(new URL(import.meta.url).pathname), \"..\")\n\n await fsx.copy(path.join(cliSrcPath, \"docker-scripts\"), path.join(buildDir, \"docker-scripts\"))\n }\n\n private async buildDockerImage(buildDir: string, imageUrl: string, npmToken: string | undefined) {\n action.start(\"🔨 Building docker image\")\n\n let cmd = `docker build -t ${imageUrl} --pull --platform linux/amd64`\n if (npmToken) cmd += ` --secret id=NPM_TOKEN`\n cmd += \" -f - .\"\n\n const dockerfile = dockerfileTemplate.replace(\n \"{{ npmTokenSecretMount }}\",\n npmToken ? `--mount=type=secret,id=NPM_TOKEN NPM_TOKEN=\"$(cat /run/secrets/NPM_TOKEN)\"` : \"\",\n )\n\n const subprocess = exec(cmd, {\n env: npmToken ? { ...process.env, NPM_TOKEN: npmToken } : process.env,\n cwd: buildDir,\n })\n\n subprocess.child.stdin!.write(dockerfile)\n subprocess.child.stdin!.end()\n\n await subprocess\n\n action.stop(\"done\")\n }\n\n private async pushDockerImage(buildDir: string, dockerHost: string, imageUrl: string) {\n const response = await fetch(`https://${dockerHost}/v2/`)\n if (response.status === 401) {\n // Requires auth\n const { accessToken } = (await this.apiClient()).config\n const loginProcess = exec(`docker login ${dockerHost} -u cli --password-stdin`)\n loginProcess.child.stdin!.write(accessToken)\n loginProcess.child.stdin!.end()\n await loginProcess\n }\n\n action.start(\"⬆️ Uploading docker image to Supernova\")\n await exec(`docker push ${imageUrl}`, {\n cwd: buildDir,\n })\n action.stop(\"done\")\n }\n\n private async remoteTemplateBuild(client: SupernovaApiClient, buildId: string) {\n action.start(\"📦 Creating template with the image\")\n\n // Trigger remote build phase\n await client.sandboxes.builds.finalize(buildId)\n\n // Poll every 2 seconds for roughly 5 minutes\n const pollIntervalMs = 2000\n const timeoutMs = 5 * 60 * 1000\n\n const startTime = Date.now()\n\n let build\n do {\n await sleep(pollIntervalMs)\n build = (await client.sandboxes.builds.get(buildId)).build\n } while (build.state === \"Building\" && Date.now() - startTime < timeoutMs)\n\n // Verify build state\n if (build.state !== \"Success\") {\n this.error(`Template creation failed`)\n }\n\n action.stop(\"done\")\n }\n\n private async uploadThumbnailsAndBuildTemplates(\n apiClient: SupernovaApiClient,\n workspaceId: string,\n templates: { [key: string]: TemplatePreset },\n ): Promise<DTOSandboxTemplateBuildCreateInput[\"templates\"]> {\n // Validate template names are unique\n const templateNames = Object.values(templates).map(t => t.name)\n const duplicateNames = templateNames.filter((name, index) => templateNames.indexOf(name) !== index)\n if (duplicateNames.length > 0) {\n throw new Error(\n `Duplicate template names found: ${[...new Set(duplicateNames)].join(\", \")}. Each template must have a unique name.`,\n )\n }\n\n const templateCount = Object.keys(templates).length\n action.start(`📸 Processing ${templateCount} template(s)`)\n\n const thumbnailFiles: Array<{\n name: string\n size: number\n checksum: string\n originalPath: string\n templateId: string\n }> = []\n\n // Validate thumbnail files\n for (const [templateId, template] of Object.entries(templates)) {\n if (!template.thumbnail) continue\n\n const validation = await validateThumbnailFile(templateId, template.thumbnail, this)\n if (!validation) continue\n\n try {\n const checksum = await calculateFileChecksum(validation.fullPath)\n thumbnailFiles.push({\n name: validation.name,\n size: validation.size,\n checksum,\n originalPath: validation.fullPath,\n templateId,\n })\n } catch (error) {\n this.warn(\n `Failed to calculate checksum for ${validation.fullPath}: ${error instanceof Error ? error.message : String(error)}`,\n )\n continue\n }\n }\n\n let thumbnailUrlMap: { [templateId: string]: string } = {}\n\n if (thumbnailFiles.length > 0) {\n try {\n // Request upload URLs from API\n const uploadResponse = await apiClient.files.upload({\n ownerType: \"Workspace\",\n workspaceId,\n files: thumbnailFiles.map(({ name, size, checksum }) => ({ name, size, checksum })),\n })\n\n // Upload files to signed URLs\n await uploadFilesToUrls(uploadResponse.uploadUrls, uploadResponse.files, thumbnailFiles)\n\n await apiClient.files.finalizeUpload({\n ownerType: \"Workspace\",\n workspaceId,\n fileIds: uploadResponse.uploadUrls.map(f => f.fileId),\n })\n\n // Map template IDs to their uploaded thumbnail URLs\n thumbnailUrlMap = buildTemplateUrlMap(thumbnailFiles, uploadResponse.files)\n } catch (error) {\n this.warn(`Failed to upload thumbnails: ${error instanceof Error ? error.message : String(error)}`)\n this.warn(\"Continuing without uploaded thumbnails...\")\n // Don't error out completely, just continue without uploaded thumbnails\n }\n }\n\n const message =\n thumbnailFiles.length > 0 ? `uploaded ${thumbnailFiles.length} thumbnail(s)` : \"no thumbnails to upload\"\n action.stop(message)\n\n const templatesWithUrls = Object.entries(templates).map(([id, template]) => {\n return {\n id,\n name: template.name,\n description: template.description,\n thumbnailUrl: thumbnailUrlMap[id],\n files: template.files,\n }\n })\n\n return templatesWithUrls\n }\n}\n\ntype PackageJson = {\n name: string\n version: string\n dependencies: Record<string, string>\n supernova:\n | {\n privateDependencies: string[] | undefined\n templates?: {\n [key: string]: TemplatePreset\n }\n }\n | undefined\n}\n\nasync function readPackageJson(): Promise<PackageJson> {\n const pkgPath = path.join(process.cwd(), \"package.json\")\n\n if (!(await fileExists(pkgPath))) throw new Error(`package.json file was not found in the current directory`)\n\n const raw = await fs.readFile(pkgPath, \"utf8\")\n const pkg = JSON.parse(raw)\n\n if (typeof pkg !== \"object\" || pkg === null) throw new Error(`Error parsing package.json: not a json`)\n\n if (typeof pkg.name !== \"string\") throw new Error(`Error parsing package.json: 'name' must be defined`)\n if (typeof pkg.version !== \"string\") throw new Error(`Error parsing package.json: 'version' must be defined`)\n if (typeof pkg.dependencies !== \"object\" || pkg.dependencies === null)\n throw new Error(`Error parsing package.json: 'dependencies' must be defined`)\n\n if (pkg.supernova?.privateDependencies) {\n const privateDependencies = pkg.supernova?.privateDependencies\n if (!Array.isArray(privateDependencies)) throw new TypeError(`supernova.privateDependencies must be an array`)\n\n for (const [i, d] of privateDependencies.entries()) {\n if (typeof d !== \"string\") {\n throw new TypeError(`supernova.privateDependencies[${i}] must be a string`)\n }\n\n if (!pkg.dependencies[d]) {\n throw new Error(`Private dependency ${d} is not listed in 'dependencies'`)\n }\n }\n }\n\n return pkg\n}\n\nfunction imageUrl(build: DTOSandboxTemplateBuildCreateResponse) {\n return `${build.dockerRegistryDomain}${build.build.dockerImagePath}`\n}\n\nasync function validateThumbnailFile(\n templateId: string,\n thumbnailPath: string,\n logger: { warn: (msg: string) => void },\n): Promise<{ name: string; size: number; fullPath: string } | undefined> {\n const allowedExtensions = [\".png\", \".jpg\", \".jpeg\", \".svg\", \".webp\"]\n const maxFileSize = 10 * 1024 * 1024 // 10 MB in bytes\n\n const fullPath = path.resolve(thumbnailPath)\n const name = path.basename(thumbnailPath)\n\n if (!(await fileExists(fullPath))) {\n logger.warn(`Thumbnail file not found for template ${templateId}: ${thumbnailPath}`)\n return undefined\n }\n\n const extension = path.extname(thumbnailPath).toLowerCase()\n if (!allowedExtensions.includes(extension)) {\n logger.warn(\n `Thumbnail file ${name} for template ${templateId} has unsupported format. Allowed formats: ${allowedExtensions.join(\", \")}`,\n )\n return undefined\n }\n\n const size = await getFileSize(fullPath)\n if (size > maxFileSize) {\n logger.warn(\n `Thumbnail file ${name} for template ${templateId} is too large (${(size / 1024 / 1024).toFixed(2)}MB). Maximum size is 10MB.`,\n )\n return undefined\n }\n\n return { name, size, fullPath }\n}\n\nasync function uploadFilesToUrls(\n uploadUrls: Array<{ fileId: string; uploadUrl: string }>,\n fileResponses: Array<{ id: string; name: string; size: number }>,\n thumbnailFiles: Array<{ name: string; size: number; originalPath: string; templateId: string }>,\n): Promise<void> {\n const uploadTasks = uploadUrls.map(async uploadUrl => {\n const fileResponse = fileResponses.find(f => f.id === uploadUrl.fileId)\n const thumbnailFile = thumbnailFiles.find(f => f.name === fileResponse?.name && f.size === fileResponse?.size)\n\n if (thumbnailFile) {\n const fileBuffer = await fs.readFile(thumbnailFile.originalPath)\n await fetch(uploadUrl.uploadUrl, {\n method: \"PUT\",\n body: fileBuffer,\n headers: {\n \"Content-Type\": \"application/octet-stream\",\n },\n })\n }\n })\n\n await Promise.all(uploadTasks)\n}\n\nfunction buildTemplateUrlMap(\n thumbnailFiles: Array<{ templateId: string; name: string; size: number }>,\n fileResponses: Array<{ name: string; size: number; url: string }>,\n): { [templateId: string]: string } {\n const thumbnailUrlMap: { [templateId: string]: string } = {}\n\n for (const thumbnailFile of thumbnailFiles) {\n const fileResponse = fileResponses.find(f => f.name === thumbnailFile.name && f.size === thumbnailFile.size)\n if (fileResponse) {\n thumbnailUrlMap[thumbnailFile.templateId] = fileResponse.url\n }\n }\n\n return thumbnailUrlMap\n}\n\nasync function calculateFileChecksum(filePath: string): Promise<string> {\n const fileBuffer = await fs.readFile(filePath)\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", fileBuffer)\n return Buffer.from(hashBuffer).toString(\"hex\")\n}\n\nasync function getFileSize(filePath: string): Promise<number> {\n const stats = await fs.stat(filePath)\n return stats.size\n}\n"],"names":[],"mappings":"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","debug_id":"3a01607f-c974-5086-8482-944a26462fb3"}
|
|
1
|
+
{"version":3,"file":"template-upload.js","sources":["../../src/commands/template-upload.ts"],"sourceRoot":"","sourcesContent":["import fetch from \"node-fetch\"\nimport { Flags } from \"@oclif/core\"\nimport { action } from \"@oclif/core/ux\"\nimport { SentryTraced } from \"@sentry/nestjs\"\nimport { exec as execCallback } from \"node:child_process\"\nimport * as fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { promisify } from \"node:util\"\nimport { z, ZodType } from \"zod\"\nimport fsx from \"fs-extra\"\nimport crypto from \"node:crypto\"\n\nimport { commonFlags, SentryCommand } from \"../types/index.js\"\n\nimport {\n DTOSandboxTemplateBuildCreateResponse,\n DTOSandboxTemplateBuildCreateInput,\n SupernovaApiClient,\n} from \"@supernova-studio/client\"\nimport { sleep } from \"../utils/common.js\"\nimport { tmpdir } from \"node:os\"\nimport { discoverAndUpdatePackageJson, discoverFilesForTemplates } from \"../utils/discover.js\"\nimport { validateTemplates, fileExists, TemplatePreset } from \"../utils/validate-templates.js\"\n\nconst exec = promisify(execCallback)\n\nconst TemplateUploadConfig = z.object({})\n\ntype TemplateUploadConfig = z.infer<typeof TemplateUploadConfig>\n\nconst dockerfileTemplate = `\nFROM node:22-slim\n\nRUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /home/user\n\nCOPY . .\nRUN {{ npmTokenSecretMount }} npm i && truncate -s 0 .npmrc\nRUN node docker-scripts/extract-private-packages.js\n`\nexport default class TemplateUpload extends SentryCommand<TemplateUploadConfig> {\n static override args = {}\n static override description = \"Upload component container template to Supernova\"\n static override examples = [\"<%= config.bin %> <%= command.id %> TemplateUpload \"]\n static override hidden: boolean = false\n static override flags = {\n ...commonFlags,\n workspaceId: Flags.string({ char: \"w\", description: \"Workspace ID to upload the template to\", required: false }),\n designSystemId: Flags.string({\n char: \"d\",\n description: \"Design system ID to upload the template to\",\n required: false,\n }),\n force: Flags.boolean({\n char: \"f\",\n description:\n \"Allows overwriting already published version of this template if it exists. This flag has no effect on new versions.\",\n required: false,\n }),\n npmToken: Flags.string({\n description:\n \"Allows passing NPM token as a Docker secret. The token will be available as a NPM_TOKEN env variable\",\n required: false,\n }),\n discover: Flags.boolean({\n description: \"Run template and pattern discovery before upload to update package.json\",\n required: false,\n }),\n debug: Flags.boolean({\n description: \"Preserve shell directory and App.tsx on template build failures for debugging\",\n required: false,\n hidden: true,\n }),\n }\n\n get commandId(): string {\n return TemplateUpload.id\n }\n\n get configSchema(): ZodType<TemplateUploadConfig> {\n return TemplateUploadConfig\n }\n\n @SentryTraced()\n public async run(): Promise<void> {\n const apiClient = await this.apiClient()\n const { flags } = await this.parse()\n\n // Update package.json with discovered names/descriptions if requested\n if (flags.discover) {\n action.start(\"🔍 Running template and pattern discovery\")\n try {\n const { templates, patterns } = await discoverAndUpdatePackageJson(process.cwd())\n action.stop(`found ${Object.keys(templates).length} templates, ${Object.keys(patterns).length} patterns`)\n } catch (error) {\n action.stop(\"failed\")\n if (error instanceof Error) this.error(`Discovery failed: ${error.message}`)\n else throw error\n }\n }\n\n // Check if this is discover-only mode\n const isDiscoverOnly = flags.discover && !flags.workspaceId && !flags.designSystemId\n\n if (isDiscoverOnly) {\n this.log(\"✅ Discovery completed. Use --workspaceId and --designSystemId to upload templates.\")\n return\n }\n\n // Validate required flags for upload\n if (!flags.workspaceId) {\n this.error(\"Missing required flag workspaceId\")\n }\n if (!flags.designSystemId) {\n this.error(\"Missing required flag designSystemId\")\n }\n\n // Read package json\n let pkg\n try {\n pkg = await readPackageJson()\n } catch (error) {\n if (error instanceof Error) this.error(`Failed to read or parse package.json: ${error.message}`)\n else throw error\n }\n\n if (pkg.supernova?.privateDependencies) {\n this.log(`Following packages will be linked as private dependencies: ${pkg.supernova.privateDependencies}`)\n\n if (!(await fileExists(path.join(process.cwd(), \".npmrc\")))) {\n this.error(\n `CLI needs private NPM registry access to be able to bundle private dependencies.\\n` +\n `Please provide .npmrc file in the root directory and include neccessary access tokens.`,\n )\n }\n } else {\n this.warn(`package.json doesn't contain 'supernova.privateDependencies' declaration.`)\n this.warn(`Dependencies coming from private registries will fail`)\n }\n\n let templatesWithThumbnailUrls: DTOSandboxTemplateBuildCreateInput[\"templates\"] | undefined\n\n if (pkg.supernova?.templates) {\n // Always enrich templates from package.json with discovered files/thumbnails info on the fly\n const templates = await discoverFilesForTemplates(pkg.supernova.templates, process.cwd())\n\n await validateTemplates(templates, this, flags.debug)\n templatesWithThumbnailUrls = await this.uploadThumbnailsAndBuildTemplates(apiClient, flags.workspaceId, templates)\n }\n\n // Request build\n const buildData = await apiClient.sandboxes.builds.start({\n workspaceId: flags.workspaceId,\n designSystemId: flags.designSystemId,\n name: pkg.name,\n version: pkg.version,\n isExistingVersionUpdateAllowed: flags.force ?? false,\n templates: templatesWithThumbnailUrls,\n })\n\n // Build image\n const url = imageUrl(buildData)\n\n await this.validateDockerDaemon()\n const buildDir = await this.createBuildDir()\n\n try {\n await this.prepareBuildFolder(buildDir)\n await this.buildDockerImage(buildDir, url, flags.npmToken)\n await this.pushDockerImage(buildDir, buildData.dockerRegistryDomain, url)\n await this.remoteTemplateBuild(apiClient, buildData.build.id)\n\n this.log(`✅ Template has been successfully uploaded`)\n } finally {\n await this.deleteBuildDir(buildDir)\n }\n }\n\n private async validateDockerDaemon() {\n await exec(\"docker info\").catch(() => {\n this.error(`Docker is not available, please start docker daemon and try again`)\n })\n }\n\n private createBuildDir(): Promise<string> {\n return fs.mkdtemp(path.join(tmpdir(), \"supernova-template-bundle-\"))\n }\n\n private async deleteBuildDir(buildDir: string) {\n await fs.rm(buildDir, { recursive: true, force: true })\n }\n\n private async prepareBuildFolder(buildDir: string) {\n // Move working directory to temp folder from where it will be built\n await fsx.copy(process.cwd(), buildDir, {\n filter(src) {\n return !src.includes(\"node_modules/\") && !src.includes(\".git/\") && !src.includes(\".out/\")\n },\n })\n\n // Inject Supernova scripts\n const cliSrcPath = path.resolve(path.dirname(new URL(import.meta.url).pathname), \"..\")\n\n await fsx.copy(path.join(cliSrcPath, \"docker-scripts\"), path.join(buildDir, \"docker-scripts\"))\n }\n\n private async buildDockerImage(buildDir: string, imageUrl: string, npmToken: string | undefined) {\n action.start(\"🔨 Building docker image\")\n\n let cmd = `docker build -t ${imageUrl} --pull --platform linux/amd64`\n if (npmToken) cmd += ` --secret id=NPM_TOKEN`\n cmd += \" -f - .\"\n\n const dockerfile = dockerfileTemplate.replace(\n \"{{ npmTokenSecretMount }}\",\n npmToken ? `--mount=type=secret,id=NPM_TOKEN NPM_TOKEN=\"$(cat /run/secrets/NPM_TOKEN)\"` : \"\",\n )\n\n const subprocess = exec(cmd, {\n env: npmToken ? { ...process.env, NPM_TOKEN: npmToken } : process.env,\n cwd: buildDir,\n })\n\n subprocess.child.stdin!.write(dockerfile)\n subprocess.child.stdin!.end()\n\n await subprocess\n\n action.stop(\"done\")\n }\n\n private async pushDockerImage(buildDir: string, dockerHost: string, imageUrl: string) {\n const response = await fetch(`https://${dockerHost}/v2/`)\n if (response.status === 401) {\n // Requires auth\n const { accessToken } = (await this.apiClient()).config\n const loginProcess = exec(`docker login ${dockerHost} -u cli --password-stdin`)\n loginProcess.child.stdin!.write(accessToken)\n loginProcess.child.stdin!.end()\n await loginProcess\n }\n\n action.start(\"⬆️ Uploading docker image to Supernova\")\n await exec(`docker push ${imageUrl}`, {\n cwd: buildDir,\n })\n action.stop(\"done\")\n }\n\n private async remoteTemplateBuild(client: SupernovaApiClient, buildId: string) {\n action.start(\"📦 Creating template with the image\")\n\n // Trigger remote build phase\n await client.sandboxes.builds.finalize(buildId)\n\n // Poll every 2 seconds for roughly 5 minutes\n const pollIntervalMs = 2000\n const timeoutMs = 5 * 60 * 1000\n\n const startTime = Date.now()\n\n let build\n do {\n await sleep(pollIntervalMs)\n build = (await client.sandboxes.builds.get(buildId)).build\n } while (build.state === \"Building\" && Date.now() - startTime < timeoutMs)\n\n // Verify build state\n if (build.state !== \"Success\") {\n this.error(`Template creation failed`)\n }\n\n action.stop(\"done\")\n }\n\n private async uploadThumbnailsAndBuildTemplates(\n apiClient: SupernovaApiClient,\n workspaceId: string,\n templates: { [key: string]: TemplatePreset },\n ): Promise<DTOSandboxTemplateBuildCreateInput[\"templates\"]> {\n // Validate template names are unique\n const templateNames = Object.values(templates).map(t => t.name)\n const duplicateNames = templateNames.filter((name, index) => templateNames.indexOf(name) !== index)\n if (duplicateNames.length > 0) {\n throw new Error(\n `Duplicate template names found: ${[...new Set(duplicateNames)].join(\", \")}. Each template must have a unique name.`,\n )\n }\n\n const templateCount = Object.keys(templates).length\n action.start(`📸 Processing ${templateCount} template(s)`)\n\n const thumbnailFiles: Array<{\n name: string\n size: number\n checksum: string\n originalPath: string\n templateId: string\n }> = []\n\n // Validate thumbnail files\n for (const [templateId, template] of Object.entries(templates)) {\n if (!template.thumbnail) continue\n\n const validation = await validateThumbnailFile(templateId, template.thumbnail, this)\n if (!validation) continue\n\n try {\n const checksum = await calculateFileChecksum(validation.fullPath)\n thumbnailFiles.push({\n name: validation.name,\n size: validation.size,\n checksum,\n originalPath: validation.fullPath,\n templateId,\n })\n } catch (error) {\n this.warn(\n `Failed to calculate checksum for ${validation.fullPath}: ${error instanceof Error ? error.message : String(error)}`,\n )\n continue\n }\n }\n\n let thumbnailUrlMap: { [templateId: string]: string } = {}\n\n if (thumbnailFiles.length > 0) {\n try {\n // Request upload URLs from API\n const uploadResponse = await apiClient.files.upload({\n ownerType: \"Workspace\",\n workspaceId,\n files: thumbnailFiles.map(({ name, size, checksum }) => ({ name, size, checksum })),\n })\n\n // Upload files to signed URLs\n await uploadFilesToUrls(uploadResponse.uploadUrls, uploadResponse.files, thumbnailFiles)\n\n await apiClient.files.finalizeUpload({\n ownerType: \"Workspace\",\n workspaceId,\n fileIds: uploadResponse.uploadUrls.map(f => f.fileId),\n })\n\n // Map template IDs to their uploaded thumbnail URLs\n thumbnailUrlMap = buildTemplateUrlMap(thumbnailFiles, uploadResponse.files)\n } catch (error) {\n this.warn(`Failed to upload thumbnails: ${error instanceof Error ? error.message : String(error)}`)\n this.warn(\"Continuing without uploaded thumbnails...\")\n // Don't error out completely, just continue without uploaded thumbnails\n }\n }\n\n const message =\n thumbnailFiles.length > 0 ? `uploaded ${thumbnailFiles.length} thumbnail(s)` : \"no thumbnails to upload\"\n action.stop(message)\n\n const templatesWithUrls = Object.entries(templates).map(([id, template]) => {\n return {\n id,\n name: template.name,\n description: template.description,\n thumbnailUrl: thumbnailUrlMap[id],\n files: template.files,\n }\n })\n\n return templatesWithUrls\n }\n}\n\ntype PackageJson = {\n name: string\n version: string\n dependencies: Record<string, string>\n supernova:\n | {\n privateDependencies: string[] | undefined\n templates?: {\n [key: string]: TemplatePreset\n }\n }\n | undefined\n}\n\nasync function readPackageJson(): Promise<PackageJson> {\n const pkgPath = path.join(process.cwd(), \"package.json\")\n\n if (!(await fileExists(pkgPath))) throw new Error(`package.json file was not found in the current directory`)\n\n const raw = await fs.readFile(pkgPath, \"utf8\")\n const pkg = JSON.parse(raw)\n\n if (typeof pkg !== \"object\" || pkg === null) throw new Error(`Error parsing package.json: not a json`)\n\n if (typeof pkg.name !== \"string\") throw new Error(`Error parsing package.json: 'name' must be defined`)\n if (typeof pkg.version !== \"string\") throw new Error(`Error parsing package.json: 'version' must be defined`)\n if (typeof pkg.dependencies !== \"object\" || pkg.dependencies === null)\n throw new Error(`Error parsing package.json: 'dependencies' must be defined`)\n\n if (pkg.supernova?.privateDependencies) {\n const privateDependencies = pkg.supernova?.privateDependencies\n if (!Array.isArray(privateDependencies)) throw new TypeError(`supernova.privateDependencies must be an array`)\n\n for (const [i, d] of privateDependencies.entries()) {\n if (typeof d !== \"string\") {\n throw new TypeError(`supernova.privateDependencies[${i}] must be a string`)\n }\n\n if (!pkg.dependencies[d]) {\n throw new Error(`Private dependency ${d} is not listed in 'dependencies'`)\n }\n }\n }\n\n return pkg\n}\n\nfunction imageUrl(build: DTOSandboxTemplateBuildCreateResponse) {\n return `${build.dockerRegistryDomain}${build.build.dockerImagePath}`\n}\n\nasync function validateThumbnailFile(\n templateId: string,\n thumbnailPath: string,\n logger: { warn: (msg: string) => void },\n): Promise<{ name: string; size: number; fullPath: string } | undefined> {\n const allowedExtensions = [\".png\", \".jpg\", \".jpeg\", \".svg\", \".webp\"]\n const maxFileSize = 10 * 1024 * 1024 // 10 MB in bytes\n\n const fullPath = path.resolve(thumbnailPath)\n const name = path.basename(thumbnailPath)\n\n if (!(await fileExists(fullPath))) {\n logger.warn(`Thumbnail file not found for template ${templateId}: ${thumbnailPath}`)\n return undefined\n }\n\n const extension = path.extname(thumbnailPath).toLowerCase()\n if (!allowedExtensions.includes(extension)) {\n logger.warn(\n `Thumbnail file ${name} for template ${templateId} has unsupported format. Allowed formats: ${allowedExtensions.join(\", \")}`,\n )\n return undefined\n }\n\n const size = await getFileSize(fullPath)\n if (size > maxFileSize) {\n logger.warn(\n `Thumbnail file ${name} for template ${templateId} is too large (${(size / 1024 / 1024).toFixed(2)}MB). Maximum size is 10MB.`,\n )\n return undefined\n }\n\n return { name, size, fullPath }\n}\n\nasync function uploadFilesToUrls(\n uploadUrls: Array<{ fileId: string; uploadUrl: string }>,\n fileResponses: Array<{ id: string; name: string; size: number }>,\n thumbnailFiles: Array<{ name: string; size: number; originalPath: string; templateId: string }>,\n): Promise<void> {\n const uploadTasks = uploadUrls.map(async uploadUrl => {\n const fileResponse = fileResponses.find(f => f.id === uploadUrl.fileId)\n const thumbnailFile = thumbnailFiles.find(f => f.name === fileResponse?.name && f.size === fileResponse?.size)\n\n if (thumbnailFile) {\n const fileBuffer = await fs.readFile(thumbnailFile.originalPath)\n await fetch(uploadUrl.uploadUrl, {\n method: \"PUT\",\n body: fileBuffer,\n headers: {\n \"Content-Type\": \"application/octet-stream\",\n },\n })\n }\n })\n\n await Promise.all(uploadTasks)\n}\n\nfunction buildTemplateUrlMap(\n thumbnailFiles: Array<{ templateId: string; checksum: string }>,\n fileResponses: Array<{ url: string; deduplicationKey: string }>,\n): { [templateId: string]: string } {\n const thumbnailUrlMap: { [templateId: string]: string } = {}\n\n for (const thumbnailFile of thumbnailFiles) {\n const fileResponse = fileResponses.find(f => f.deduplicationKey === thumbnailFile.checksum)\n if (fileResponse) {\n thumbnailUrlMap[thumbnailFile.templateId] = fileResponse.url\n }\n }\n\n return thumbnailUrlMap\n}\n\nasync function calculateFileChecksum(filePath: string): Promise<string> {\n const fileBuffer = await fs.readFile(filePath)\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", fileBuffer)\n return Buffer.from(hashBuffer).toString(\"hex\")\n}\n\nasync function getFileSize(filePath: string): Promise<number> {\n const stats = await fs.stat(filePath)\n return stats.size\n}\n"],"names":[],"mappings":"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","debug_id":"b80a82ae-3a40-5488-a3cf-4d8210ab28a6"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface TemplateInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
thumbnail?: string;
|
|
5
|
+
files: string[];
|
|
6
|
+
}
|
|
7
|
+
interface ItemsObject {
|
|
8
|
+
[itemKey: string]: TemplateInfo;
|
|
9
|
+
}
|
|
10
|
+
export declare function folderNameToDisplayName(folderName: string): string;
|
|
11
|
+
export declare function discoverTemplatesAndPatterns(basePath?: string): Promise<{
|
|
12
|
+
templates: ItemsObject;
|
|
13
|
+
patterns: ItemsObject;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function discoverFilesForTemplates(pkgTemplates: Record<string, Pick<TemplateInfo, "name" | "description">>, basePath?: string): Promise<ItemsObject>;
|
|
16
|
+
export declare function discoverAndUpdatePackageJson(basePath?: string): Promise<{
|
|
17
|
+
templates: ItemsObject;
|
|
18
|
+
patterns: ItemsObject;
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/utils/discover.ts"],"names":[],"mappings":"AAGA,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,UAAU,WAAW;IACnB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAAA;CAChC;AAMD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAOlE;AAscD,wBAAsB,4BAA4B,CAChD,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,SAAS,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,CAAC,CAc5D;AAED,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,EACxE,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAKtB;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,SAAS,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,CAAC,CAqB5D"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7d906731-5fc8-5c9e-b336-a051b5efcb88")}catch(e){}}();
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
export function folderNameToDisplayName(folderName) {
|
|
6
|
+
return folderName
|
|
7
|
+
.replace(/[-_]/g, " ")
|
|
8
|
+
.replace(/([A-Z])/g, " $1")
|
|
9
|
+
.trim()
|
|
10
|
+
.replace(/\s+/g, " ")
|
|
11
|
+
.replace(/\b\w/g, c => c.toUpperCase());
|
|
12
|
+
}
|
|
13
|
+
function getAllFilesInDirectory(dirPath, relativeTo) {
|
|
14
|
+
return fs
|
|
15
|
+
.readdirSync(dirPath, { recursive: true, withFileTypes: true })
|
|
16
|
+
.filter(entry => entry.isFile() && entry.name !== "README.md")
|
|
17
|
+
.map(entry => path.relative(relativeTo, path.join(entry.parentPath || dirPath, entry.name)))
|
|
18
|
+
.sort();
|
|
19
|
+
}
|
|
20
|
+
function findThumbnail(templateDir) {
|
|
21
|
+
return [".png", ".svg", ".jpg", ".jpeg"]
|
|
22
|
+
.map(ext => `thumbnail${ext}`)
|
|
23
|
+
.find(filename => fs.existsSync(path.join(templateDir, filename)));
|
|
24
|
+
}
|
|
25
|
+
function parseDescriptionFromReadme(readmeFilePath) {
|
|
26
|
+
if (!fs.existsSync(readmeFilePath))
|
|
27
|
+
return "";
|
|
28
|
+
try {
|
|
29
|
+
const content = fs.readFileSync(readmeFilePath, "utf8");
|
|
30
|
+
const match = content.match(/^#[^\n]*\n+([^\n#]+)/m);
|
|
31
|
+
if (!match)
|
|
32
|
+
return "";
|
|
33
|
+
let description = match[1].trim();
|
|
34
|
+
description = description.replace(/\*\*/g, "").replace(/\*/g, "");
|
|
35
|
+
description = description.charAt(0).toUpperCase() + description.slice(1);
|
|
36
|
+
if (!description.endsWith(".") && !description.endsWith("!") && !description.endsWith("?")) {
|
|
37
|
+
description += ".";
|
|
38
|
+
}
|
|
39
|
+
return description;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseImportsFromTSFile(filePath, baseDir) {
|
|
46
|
+
if (!fs.existsSync(filePath))
|
|
47
|
+
return [];
|
|
48
|
+
try {
|
|
49
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
50
|
+
const dependencies = [];
|
|
51
|
+
const importRegex = /import\s+(?:[\w*{}\s,]+\s+from\s+)?['"`]([^'"`]+)['"`]/g;
|
|
52
|
+
let match;
|
|
53
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
54
|
+
const importPath = match[1];
|
|
55
|
+
if (importPath.startsWith("./") || importPath.startsWith("../")) {
|
|
56
|
+
try {
|
|
57
|
+
const fileDir = path.dirname(filePath);
|
|
58
|
+
const resolvedPath = path.resolve(fileDir, importPath);
|
|
59
|
+
const possiblePaths = [
|
|
60
|
+
resolvedPath,
|
|
61
|
+
resolvedPath + ".tsx",
|
|
62
|
+
resolvedPath + ".ts",
|
|
63
|
+
resolvedPath + ".json",
|
|
64
|
+
resolvedPath + ".js",
|
|
65
|
+
];
|
|
66
|
+
const actualPath = possiblePaths.find(p => fs.existsSync(p));
|
|
67
|
+
if (actualPath) {
|
|
68
|
+
const containerRoot = path.resolve(baseDir, "../../..");
|
|
69
|
+
const relativePath = path.relative(containerRoot, actualPath).replace(/\\/g, "/");
|
|
70
|
+
if (relativePath.startsWith("supernova/")) {
|
|
71
|
+
dependencies.push(relativePath);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return dependencies;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function parseImportsFromDirectory(itemDir) {
|
|
86
|
+
const dependencies = new Set();
|
|
87
|
+
try {
|
|
88
|
+
const entries = fs.readdirSync(itemDir, { recursive: true, withFileTypes: true });
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
if (entry.isFile()) {
|
|
91
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
92
|
+
if (ext === ".ts" || ext === ".tsx") {
|
|
93
|
+
const fullPath = path.join(entry.parentPath || itemDir, entry.name);
|
|
94
|
+
const fileDeps = parseImportsFromTSFile(fullPath, itemDir);
|
|
95
|
+
fileDeps.forEach(dep => dependencies.add(dep));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
}
|
|
102
|
+
return Array.from(dependencies).sort();
|
|
103
|
+
}
|
|
104
|
+
function parseMainReadmeTable(mainReadmePath, itemKey) {
|
|
105
|
+
if (!fs.existsSync(mainReadmePath))
|
|
106
|
+
return null;
|
|
107
|
+
try {
|
|
108
|
+
const content = fs.readFileSync(mainReadmePath, "utf8");
|
|
109
|
+
const tableMatch = content.match(/(\|\s*(?:Pattern|Template)\s*\|[^\n]*)\n\|[-\s|]*\n((?:\|[^\n]*\n)*)/i);
|
|
110
|
+
if (!tableMatch)
|
|
111
|
+
return null;
|
|
112
|
+
const headerCells = tableMatch[1]
|
|
113
|
+
.split("|")
|
|
114
|
+
.map(cell => cell.trim())
|
|
115
|
+
.filter(cell => cell);
|
|
116
|
+
const nameIndex = headerCells.findIndex(cell => /^(Pattern|Template)$/i.test(cell));
|
|
117
|
+
const descIndex = headerCells.findIndex(cell => /^Description$/i.test(cell));
|
|
118
|
+
if (nameIndex === -1 || descIndex === -1)
|
|
119
|
+
return null;
|
|
120
|
+
const rows = tableMatch[2].split("\n").filter(row => row.trim());
|
|
121
|
+
for (const row of rows) {
|
|
122
|
+
const cells = row
|
|
123
|
+
.split("|")
|
|
124
|
+
.map(cell => cell.trim())
|
|
125
|
+
.filter(cell => cell);
|
|
126
|
+
if (cells.length > Math.max(nameIndex, descIndex)) {
|
|
127
|
+
const name = cells[nameIndex]?.replace(/\[([^\]]+)\].*/, "$1");
|
|
128
|
+
const description = cells[descIndex];
|
|
129
|
+
if (name === itemKey) {
|
|
130
|
+
return description.endsWith(".") ? description : description + ".";
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
function extractDescriptionFromReadme(itemDir, fallbackName, itemKey, subdirectory) {
|
|
140
|
+
const itemReadmePath = path.join(itemDir, "README.md");
|
|
141
|
+
const individualDescription = parseDescriptionFromReadme(itemReadmePath);
|
|
142
|
+
if (individualDescription) {
|
|
143
|
+
return individualDescription;
|
|
144
|
+
}
|
|
145
|
+
const containerRoot = path.resolve(itemDir, "../../..");
|
|
146
|
+
const mainReadmePath = path.join(containerRoot, "supernova", subdirectory, "README.md");
|
|
147
|
+
const tableDescription = parseMainReadmeTable(mainReadmePath, itemKey);
|
|
148
|
+
if (tableDescription) {
|
|
149
|
+
return tableDescription;
|
|
150
|
+
}
|
|
151
|
+
return `Use this to prototype similar to ${fallbackName}`;
|
|
152
|
+
}
|
|
153
|
+
function readPackageJson(basePath) {
|
|
154
|
+
const packageJsonPath = path.join(basePath, "package.json");
|
|
155
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
156
|
+
throw new Error(`package.json not found at ${packageJsonPath}`);
|
|
157
|
+
}
|
|
158
|
+
const content = fs.readFileSync(packageJsonPath, "utf8");
|
|
159
|
+
return JSON.parse(content);
|
|
160
|
+
}
|
|
161
|
+
function writePackageJson(basePath, packageData) {
|
|
162
|
+
const packageJsonPath = path.join(basePath, "package.json");
|
|
163
|
+
const content = JSON.stringify(packageData, null, 2) + "\n";
|
|
164
|
+
fs.writeFileSync(packageJsonPath, content, "utf8");
|
|
165
|
+
}
|
|
166
|
+
function discoverItems(basePath, subdirectory) {
|
|
167
|
+
const resolvedBasePath = basePath || process.cwd();
|
|
168
|
+
const itemsDir = path.join(resolvedBasePath, "supernova", subdirectory);
|
|
169
|
+
if (!fs.existsSync(itemsDir)) {
|
|
170
|
+
throw new Error(`${subdirectory} directory not found at ${itemsDir}`);
|
|
171
|
+
}
|
|
172
|
+
const items = {};
|
|
173
|
+
const entries = fs.readdirSync(itemsDir, { withFileTypes: true });
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
if (!entry.isDirectory() || entry.name === "README.md") {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const itemKey = entry.name;
|
|
179
|
+
const itemDir = path.join(itemsDir, itemKey);
|
|
180
|
+
const displayName = folderNameToDisplayName(itemKey);
|
|
181
|
+
const description = extractDescriptionFromReadme(itemDir, displayName, itemKey, subdirectory);
|
|
182
|
+
const thumbnail = findThumbnail(itemDir);
|
|
183
|
+
const files = getAllFilesInDirectory(itemDir, itemDir);
|
|
184
|
+
const containerRoot = path.resolve(itemDir, "../../..");
|
|
185
|
+
const itemRelativePath = path.relative(containerRoot, itemDir).replace(/\\/g, "/");
|
|
186
|
+
const fullPathFiles = files.map(file => `${itemRelativePath}/${file}`);
|
|
187
|
+
const importDependencies = parseImportsFromDirectory(itemDir);
|
|
188
|
+
const allDependencies = [...new Set([...importDependencies])];
|
|
189
|
+
const itemBasePath = itemRelativePath;
|
|
190
|
+
const externalDependencies = allDependencies.filter(dep => !dep.startsWith(itemBasePath + "/"));
|
|
191
|
+
const validExternalDependencies = externalDependencies.filter(dep => {
|
|
192
|
+
const fullPath = path.join(containerRoot, dep);
|
|
193
|
+
const exists = fs.existsSync(fullPath);
|
|
194
|
+
if (!exists) {
|
|
195
|
+
console.warn(`Warning: Dependency not found: ${dep} (expected at ${fullPath})`);
|
|
196
|
+
}
|
|
197
|
+
return exists;
|
|
198
|
+
});
|
|
199
|
+
const allFiles = new Set([...fullPathFiles, ...validExternalDependencies]);
|
|
200
|
+
const filteredFiles = Array.from(allFiles).filter(file => !file.endsWith("README.md") &&
|
|
201
|
+
!["/thumbnail.png", "/thumbnail.svg", "/thumbnail.jpg", "/thumbnail.jpeg"].some(ext => file.endsWith(ext)));
|
|
202
|
+
const existingFiles = filteredFiles
|
|
203
|
+
.filter(file => {
|
|
204
|
+
const fullPath = path.join(containerRoot, file);
|
|
205
|
+
const exists = fs.existsSync(fullPath);
|
|
206
|
+
if (!exists) {
|
|
207
|
+
console.warn(`Warning: File not found: ${file} (expected at ${fullPath})`);
|
|
208
|
+
}
|
|
209
|
+
return exists;
|
|
210
|
+
})
|
|
211
|
+
.sort();
|
|
212
|
+
const itemInfo = {
|
|
213
|
+
name: displayName,
|
|
214
|
+
description,
|
|
215
|
+
files: existingFiles,
|
|
216
|
+
};
|
|
217
|
+
if (thumbnail) {
|
|
218
|
+
itemInfo.thumbnail = `${itemRelativePath}/${thumbnail}`;
|
|
219
|
+
}
|
|
220
|
+
items[itemKey] = itemInfo;
|
|
221
|
+
}
|
|
222
|
+
return items;
|
|
223
|
+
}
|
|
224
|
+
function discoverTemplates(basePath) {
|
|
225
|
+
const resolvedBasePath = basePath || process.cwd();
|
|
226
|
+
return discoverItems(resolvedBasePath, "templates");
|
|
227
|
+
}
|
|
228
|
+
function discoverPatterns(basePath) {
|
|
229
|
+
const resolvedBasePath = basePath || process.cwd();
|
|
230
|
+
return discoverItems(resolvedBasePath, "patterns");
|
|
231
|
+
}
|
|
232
|
+
function resolveTransitiveDependencies(items, patterns, basePath) {
|
|
233
|
+
const resolvedItems = {};
|
|
234
|
+
for (const [itemKey, itemInfo] of Object.entries(items)) {
|
|
235
|
+
const resolvedFiles = new Set([...itemInfo.files]);
|
|
236
|
+
const dependentPatterns = new Set();
|
|
237
|
+
for (const file of itemInfo.files) {
|
|
238
|
+
const pathMatch = file.match(/^supernova\/patterns\/([^\/]+)\//);
|
|
239
|
+
if (pathMatch) {
|
|
240
|
+
dependentPatterns.add(pathMatch[1]);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function addTransitiveDependencies(patternKey, visited = new Set()) {
|
|
244
|
+
if (visited.has(patternKey)) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
visited.add(patternKey);
|
|
248
|
+
const pattern = patterns[patternKey];
|
|
249
|
+
if (!pattern) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
pattern.files.forEach(file => resolvedFiles.add(file));
|
|
253
|
+
for (const file of pattern.files) {
|
|
254
|
+
const pathMatch = file.match(/^supernova\/patterns\/([^\/]+)\//);
|
|
255
|
+
if (pathMatch && pathMatch[1] !== patternKey) {
|
|
256
|
+
addTransitiveDependencies(pathMatch[1], new Set(visited));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
for (const patternKey of dependentPatterns) {
|
|
261
|
+
addTransitiveDependencies(patternKey);
|
|
262
|
+
}
|
|
263
|
+
const containerRoot = path.resolve(basePath);
|
|
264
|
+
const validFiles = Array.from(resolvedFiles)
|
|
265
|
+
.filter(file => {
|
|
266
|
+
const fullPath = path.join(containerRoot, file);
|
|
267
|
+
const exists = fs.existsSync(fullPath);
|
|
268
|
+
if (!exists) {
|
|
269
|
+
console.warn(`Warning: Transitive dependency not found: ${file} (expected at ${fullPath})`);
|
|
270
|
+
}
|
|
271
|
+
return exists;
|
|
272
|
+
})
|
|
273
|
+
.sort();
|
|
274
|
+
resolvedItems[itemKey] = {
|
|
275
|
+
...itemInfo,
|
|
276
|
+
files: validFiles,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
return resolvedItems;
|
|
280
|
+
}
|
|
281
|
+
export async function discoverTemplatesAndPatterns(basePath) {
|
|
282
|
+
const resolvedBasePath = basePath || process.cwd();
|
|
283
|
+
const rawTemplates = discoverTemplates(resolvedBasePath);
|
|
284
|
+
const rawPatterns = discoverPatterns(resolvedBasePath);
|
|
285
|
+
const templates = resolveTransitiveDependencies(rawTemplates, rawPatterns, resolvedBasePath);
|
|
286
|
+
const patterns = resolveTransitiveDependencies(rawPatterns, rawPatterns, resolvedBasePath);
|
|
287
|
+
return { templates, patterns };
|
|
288
|
+
}
|
|
289
|
+
export async function discoverFilesForTemplates(pkgTemplates, basePath) {
|
|
290
|
+
const { templates } = await discoverTemplatesAndPatterns(basePath);
|
|
291
|
+
return Object.fromEntries(Object.entries(pkgTemplates).map(([key, pkgTemplate]) => [key, { ...templates[key], ...pkgTemplate }]));
|
|
292
|
+
}
|
|
293
|
+
export async function discoverAndUpdatePackageJson(basePath) {
|
|
294
|
+
const result = await discoverTemplatesAndPatterns(basePath);
|
|
295
|
+
const resolvedBasePath = basePath || process.cwd();
|
|
296
|
+
const packageData = readPackageJson(resolvedBasePath);
|
|
297
|
+
if (!packageData.supernova) {
|
|
298
|
+
packageData.supernova = {};
|
|
299
|
+
}
|
|
300
|
+
packageData.supernova.templates = Object.fromEntries(Object.entries(result.templates).map(([key, { name, description }]) => [key, { name, description }]));
|
|
301
|
+
writePackageJson(resolvedBasePath, packageData);
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=discover.js.map
|
|
305
|
+
//# debugId=7d906731-5fc8-5c9e-b336-a051b5efcb88
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sources":["../../src/utils/discover.ts"],"sourceRoot":"","sourcesContent":["import fs from \"node:fs\"\nimport path from \"node:path\"\n\ninterface TemplateInfo {\n name: string\n description: string\n thumbnail?: string\n files: string[]\n}\n\ninterface ItemsObject {\n [itemKey: string]: TemplateInfo\n}\n\n/**\n * Converts folder name to spaced title case\n * e.g., \"AppShell\" -> \"App Shell\", \"PortalFeatureDetail\" -> \"Portal Feature Detail\"\n */\nexport function folderNameToDisplayName(folderName: string): string {\n return folderName\n .replace(/[-_]/g, \" \") // kebab-case and snake_case → spaces\n .replace(/([A-Z])/g, \" $1\") // PascalCase/camelCase → spaces before uppercase\n .trim()\n .replace(/\\s+/g, \" \") // normalize multiple spaces\n .replace(/\\b\\w/g, c => c.toUpperCase()) // capitalize each word\n}\n\n/**\n * Recursively get all files in a directory relative to that directory\n */\nfunction getAllFilesInDirectory(dirPath: string, relativeTo: string): string[] {\n return fs\n .readdirSync(dirPath, { recursive: true, withFileTypes: true })\n .filter(entry => entry.isFile() && entry.name !== \"README.md\")\n .map(entry => path.relative(relativeTo, path.join(entry.parentPath || dirPath, entry.name)))\n .sort()\n}\n\n/**\n * Check for thumbnail files in a directory\n */\nfunction findThumbnail(templateDir: string): string | undefined {\n return [\".png\", \".svg\", \".jpg\", \".jpeg\"]\n .map(ext => `thumbnail${ext}`)\n .find(filename => fs.existsSync(path.join(templateDir, filename)))\n}\n\n/**\n * Parse description from a README.md file in any directory\n * Takes the first sentence after the first # heading\n *\n * @param readmeFilePath - Full path to README.md file\n * @returns string - The description or empty string if not found\n */\nfunction parseDescriptionFromReadme(readmeFilePath: string): string {\n if (!fs.existsSync(readmeFilePath)) return \"\"\n\n try {\n const content = fs.readFileSync(readmeFilePath, \"utf8\")\n\n // Find first paragraph after first # heading\n const match = content.match(/^#[^\\n]*\\n+([^\\n#]+)/m)\n if (!match) return \"\"\n\n let description = match[1].trim()\n\n // Clean up the description\n description = description.replace(/\\*\\*/g, \"\").replace(/\\*/g, \"\") // Remove markdown formatting\n description = description.charAt(0).toUpperCase() + description.slice(1) // Ensure capital letter\n\n // Ensure it ends with period if it doesn't already\n if (!description.endsWith(\".\") && !description.endsWith(\"!\") && !description.endsWith(\"?\")) {\n description += \".\"\n }\n\n return description\n } catch (error) {\n return \"\"\n }\n}\n\n/**\n * Parse TypeScript/TSX files for import statements and extract file dependencies\n * @param filePath - Path to .ts/.tsx file\n * @param baseDir - Base directory for resolving relative imports\n * @returns string[] - Array of imported file paths (resolved to project root)\n */\nfunction parseImportsFromTSFile(filePath: string, baseDir: string): string[] {\n if (!fs.existsSync(filePath)) return []\n\n try {\n const content = fs.readFileSync(filePath, \"utf8\")\n const dependencies: string[] = []\n\n // Regex to match import statements\n const importRegex = /import\\s+(?:[\\w*{}\\s,]+\\s+from\\s+)?['\"`]([^'\"`]+)['\"`]/g\n\n let match\n while ((match = importRegex.exec(content)) !== null) {\n const importPath = match[1]\n\n // Only process relative imports (starting with ./ or ../)\n if (importPath.startsWith(\"./\") || importPath.startsWith(\"../\")) {\n try {\n // Resolve relative to the file's directory\n const fileDir = path.dirname(filePath)\n const resolvedPath = path.resolve(fileDir, importPath)\n\n // Try common extensions if no extension provided\n const possiblePaths = [\n resolvedPath,\n resolvedPath + \".tsx\",\n resolvedPath + \".ts\",\n resolvedPath + \".json\",\n resolvedPath + \".js\",\n ]\n\n const actualPath = possiblePaths.find(p => fs.existsSync(p))\n\n if (actualPath) {\n // Convert to path relative to container root\n const containerRoot = path.resolve(baseDir, \"../../..\")\n const relativePath = path.relative(containerRoot, actualPath).replace(/\\\\/g, \"/\")\n\n // Only include files within the supernova directory\n if (relativePath.startsWith(\"supernova/\")) {\n dependencies.push(relativePath)\n }\n }\n } catch (error) {\n // Skip invalid import paths\n }\n }\n }\n\n return dependencies\n } catch (error) {\n return []\n }\n}\n\n/**\n * Parse all TypeScript/TSX files in a directory for import dependencies\n * @param itemDir - Directory containing the template/pattern\n * @returns string[] - Array of all imported file paths from all TS/TSX files\n */\nfunction parseImportsFromDirectory(itemDir: string): string[] {\n const dependencies = new Set<string>()\n\n try {\n const entries = fs.readdirSync(itemDir, { recursive: true, withFileTypes: true })\n\n for (const entry of entries) {\n if (entry.isFile()) {\n const ext = path.extname(entry.name).toLowerCase()\n if (ext === \".ts\" || ext === \".tsx\") {\n const fullPath = path.join(entry.parentPath || itemDir, entry.name)\n const fileDeps = parseImportsFromTSFile(fullPath, itemDir)\n fileDeps.forEach(dep => dependencies.add(dep))\n }\n }\n }\n } catch (error) {\n // Skip directories that can't be read\n }\n\n return Array.from(dependencies).sort()\n}\n\n/**\n * Parse main directory README.md for table-based descriptions\n * Extracts description from markdown table like:\n * | Pattern | Description |\n * | PromptEditor | Tiptap rich text editor |\n */\nfunction parseMainReadmeTable(mainReadmePath: string, itemKey: string): string | null {\n if (!fs.existsSync(mainReadmePath)) return null\n\n try {\n const content = fs.readFileSync(mainReadmePath, \"utf8\")\n\n // Find table that contains Pattern or Template header\n const tableMatch = content.match(/(\\|\\s*(?:Pattern|Template)\\s*\\|[^\\n]*)\\n\\|[-\\s|]*\\n((?:\\|[^\\n]*\\n)*)/i)\n if (!tableMatch) return null\n\n // Parse header to get column indices\n const headerCells = tableMatch[1]\n .split(\"|\")\n .map(cell => cell.trim())\n .filter(cell => cell)\n const nameIndex = headerCells.findIndex(cell => /^(Pattern|Template)$/i.test(cell))\n const descIndex = headerCells.findIndex(cell => /^Description$/i.test(cell))\n\n if (nameIndex === -1 || descIndex === -1) return null\n\n // Parse table rows\n const rows = tableMatch[2].split(\"\\n\").filter(row => row.trim())\n\n for (const row of rows) {\n const cells = row\n .split(\"|\")\n .map(cell => cell.trim())\n .filter(cell => cell)\n\n if (cells.length > Math.max(nameIndex, descIndex)) {\n const name = cells[nameIndex]?.replace(/\\[([^\\]]+)\\].*/, \"$1\") // Remove markdown link syntax\n const description = cells[descIndex]\n\n if (name === itemKey) {\n return description.endsWith(\".\") ? description : description + \".\"\n }\n }\n }\n } catch (error) {\n // If error reading file, return null\n }\n\n return null\n}\n\n/**\n * Extract description from README.md file\n * Priority: 1) Individual README, 2) Main directory table, 3) Fallback\n */\nfunction extractDescriptionFromReadme(\n itemDir: string,\n fallbackName: string,\n itemKey: string,\n subdirectory: \"templates\" | \"patterns\",\n): string {\n // Try individual README first (highest priority)\n const itemReadmePath = path.join(itemDir, \"README.md\")\n const individualDescription = parseDescriptionFromReadme(itemReadmePath)\n if (individualDescription) {\n return individualDescription\n }\n\n // Try main directory table second\n const containerRoot = path.resolve(itemDir, \"../../..\")\n const mainReadmePath = path.join(containerRoot, \"supernova\", subdirectory, \"README.md\")\n const tableDescription = parseMainReadmeTable(mainReadmePath, itemKey)\n if (tableDescription) {\n return tableDescription\n }\n\n // Fall back to default\n return `Use this to prototype similar to ${fallbackName}`\n}\n\n/**\n * Read package.json and return parsed content\n */\nfunction readPackageJson(basePath: string): any {\n const packageJsonPath = path.join(basePath, \"package.json\")\n\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`package.json not found at ${packageJsonPath}`)\n }\n\n const content = fs.readFileSync(packageJsonPath, \"utf8\")\n return JSON.parse(content)\n}\n\n/**\n * Write package.json with proper formatting\n */\nfunction writePackageJson(basePath: string, packageData: any): void {\n const packageJsonPath = path.join(basePath, \"package.json\")\n const content = JSON.stringify(packageData, null, 2) + \"\\n\"\n fs.writeFileSync(packageJsonPath, content, \"utf8\")\n}\n\n/**\n * Discovers items in a supernova subdirectory and returns metadata object\n *\n * @param basePath - Base directory path (defaults to current working directory)\n * @param subdirectory - Subdirectory name ('templates' or 'patterns')\n * @returns ItemsObject - Object with item metadata\n */\nfunction discoverItems(basePath: string, subdirectory: \"templates\" | \"patterns\"): ItemsObject {\n const resolvedBasePath = basePath || process.cwd()\n const itemsDir = path.join(resolvedBasePath, \"supernova\", subdirectory)\n\n // Check if directory exists\n if (!fs.existsSync(itemsDir)) {\n throw new Error(`${subdirectory} directory not found at ${itemsDir}`)\n }\n\n const items: ItemsObject = {}\n\n // Read all entries in directory\n const entries = fs.readdirSync(itemsDir, { withFileTypes: true })\n\n for (const entry of entries) {\n // Skip non-directories and README files\n if (!entry.isDirectory() || entry.name === \"README.md\") {\n continue\n }\n\n const itemKey = entry.name\n const itemDir = path.join(itemsDir, itemKey)\n\n // Generate display name\n const displayName = folderNameToDisplayName(itemKey)\n\n // Extract description from README.md\n const description = extractDescriptionFromReadme(itemDir, displayName, itemKey, subdirectory)\n\n // Find thumbnail\n const thumbnail = findThumbnail(itemDir)\n\n // Get all files in item directory with full paths\n const files = getAllFilesInDirectory(itemDir, itemDir)\n const containerRoot = path.resolve(itemDir, \"../../..\") // This goes from supernova/templates/X to container root\n const itemRelativePath = path.relative(containerRoot, itemDir).replace(/\\\\/g, \"/\")\n const fullPathFiles = files.map(file => `${itemRelativePath}/${file}`)\n\n // Parse dependencies from TypeScript/TSX import statements\n const importDependencies = parseImportsFromDirectory(itemDir)\n\n // Combine both sources of dependencies\n const allDependencies = [...new Set([...importDependencies])]\n\n // Filter out dependencies that are within the same item directory\n const itemBasePath = itemRelativePath\n const externalDependencies = allDependencies.filter(dep => !dep.startsWith(itemBasePath + \"/\"))\n\n // Validate that external dependencies exist in the filesystem\n const validExternalDependencies = externalDependencies.filter(dep => {\n const fullPath = path.join(containerRoot, dep)\n const exists = fs.existsSync(fullPath)\n if (!exists) {\n console.warn(`Warning: Dependency not found: ${dep} (expected at ${fullPath})`)\n }\n return exists\n })\n\n // Combine files and valid dependencies, remove duplicates\n const allFiles = new Set([...fullPathFiles, ...validExternalDependencies])\n // Remove README.md files and thumbnail files from the combined list\n const filteredFiles = Array.from(allFiles).filter(\n file =>\n !file.endsWith(\"README.md\") &&\n ![\"/thumbnail.png\", \"/thumbnail.svg\", \"/thumbnail.jpg\", \"/thumbnail.jpeg\"].some(ext => file.endsWith(ext)),\n )\n\n // Validate that all files exist in the filesystem\n const existingFiles = filteredFiles\n .filter(file => {\n const fullPath = path.join(containerRoot, file)\n const exists = fs.existsSync(fullPath)\n if (!exists) {\n console.warn(`Warning: File not found: ${file} (expected at ${fullPath})`)\n }\n return exists\n })\n .sort()\n\n // Build item info object\n const itemInfo: TemplateInfo = {\n name: displayName,\n description,\n files: existingFiles,\n }\n\n // Only add thumbnail property if it exists (with full path)\n if (thumbnail) {\n itemInfo.thumbnail = `${itemRelativePath}/${thumbnail}`\n }\n\n items[itemKey] = itemInfo\n }\n\n return items\n}\n\n/**\n * Discovers templates in supernova/templates directory and returns metadata object\n *\n * @param basePath - Base directory path (defaults to current working directory)\n * @returns ItemsObject - Object with template metadata\n */\nfunction discoverTemplates(basePath?: string): ItemsObject {\n const resolvedBasePath = basePath || process.cwd()\n return discoverItems(resolvedBasePath, \"templates\")\n}\n\n/**\n * Discovers patterns in supernova/patterns directory and returns metadata object\n *\n * @param basePath - Base directory path (defaults to current working directory)\n * @returns ItemsObject - Object with pattern metadata\n */\nfunction discoverPatterns(basePath?: string): ItemsObject {\n const resolvedBasePath = basePath || process.cwd()\n return discoverItems(resolvedBasePath, \"patterns\")\n}\n\n/**\n * Resolve transitive dependencies for templates/patterns\n * If Template A imports Pattern B, and Pattern B imports Pattern C,\n * then Template A should include files from both Pattern B and Pattern C\n */\nfunction resolveTransitiveDependencies(items: ItemsObject, patterns: ItemsObject, basePath: string): ItemsObject {\n const resolvedItems: ItemsObject = {}\n\n for (const [itemKey, itemInfo] of Object.entries(items)) {\n const resolvedFiles = new Set([...itemInfo.files])\n\n // Find which patterns this item depends on\n const dependentPatterns = new Set<string>()\n\n // Check direct dependencies by looking at file paths\n for (const file of itemInfo.files) {\n const pathMatch = file.match(/^supernova\\/patterns\\/([^\\/]+)\\//)\n if (pathMatch) {\n dependentPatterns.add(pathMatch[1])\n }\n }\n\n // Recursively resolve transitive dependencies\n function addTransitiveDependencies(patternKey: string, visited = new Set<string>()) {\n if (visited.has(patternKey)) {\n return // Avoid circular dependencies\n }\n visited.add(patternKey)\n\n const pattern = patterns[patternKey]\n if (!pattern) {\n return\n }\n\n // Add all files from this pattern\n pattern.files.forEach(file => resolvedFiles.add(file))\n\n // Find what patterns this pattern depends on\n for (const file of pattern.files) {\n const pathMatch = file.match(/^supernova\\/patterns\\/([^\\/]+)\\//)\n if (pathMatch && pathMatch[1] !== patternKey) {\n // Recursively add transitive dependencies\n addTransitiveDependencies(pathMatch[1], new Set(visited))\n }\n }\n }\n\n // Resolve transitive dependencies for each direct dependency\n for (const patternKey of dependentPatterns) {\n addTransitiveDependencies(patternKey)\n }\n\n // Validate all resolved files exist\n const containerRoot = path.resolve(basePath)\n const validFiles = Array.from(resolvedFiles)\n .filter(file => {\n const fullPath = path.join(containerRoot, file)\n const exists = fs.existsSync(fullPath)\n if (!exists) {\n console.warn(`Warning: Transitive dependency not found: ${file} (expected at ${fullPath})`)\n }\n return exists\n })\n .sort()\n\n resolvedItems[itemKey] = {\n ...itemInfo,\n files: validFiles,\n }\n }\n\n return resolvedItems\n}\n\n/**\n * Discovers templates and patterns, then updates package.json with the results\n *\n * @param basePath - Base directory path (defaults to current working directory)\n * @returns Promise<{templates: ItemsObject, patterns: ItemsObject}> - Object with template and pattern metadata\n */\n\nexport async function discoverTemplatesAndPatterns(\n basePath?: string,\n): Promise<{ templates: ItemsObject; patterns: ItemsObject }> {\n const resolvedBasePath = basePath || process.cwd()\n\n // First discover templates and patterns independently\n const rawTemplates = discoverTemplates(resolvedBasePath)\n const rawPatterns = discoverPatterns(resolvedBasePath)\n\n // Resolve transitive dependencies for templates\n const templates = resolveTransitiveDependencies(rawTemplates, rawPatterns, resolvedBasePath)\n\n // Resolve transitive dependencies for patterns (in case patterns depend on other patterns)\n const patterns = resolveTransitiveDependencies(rawPatterns, rawPatterns, resolvedBasePath)\n\n return { templates, patterns }\n}\n\nexport async function discoverFilesForTemplates(\n pkgTemplates: Record<string, Pick<TemplateInfo, \"name\" | \"description\">>,\n basePath?: string,\n): Promise<ItemsObject> {\n const { templates } = await discoverTemplatesAndPatterns(basePath)\n return Object.fromEntries(\n Object.entries(pkgTemplates).map(([key, pkgTemplate]) => [key, { ...templates[key], ...pkgTemplate }]),\n )\n}\n\nexport async function discoverAndUpdatePackageJson(\n basePath?: string,\n): Promise<{ templates: ItemsObject; patterns: ItemsObject }> {\n const result = await discoverTemplatesAndPatterns(basePath)\n const resolvedBasePath = basePath || process.cwd()\n\n // Read current package.json\n const packageData = readPackageJson(resolvedBasePath)\n\n // Ensure supernova object exists\n if (!packageData.supernova) {\n packageData.supernova = {}\n }\n\n // Only persist name and description — files and thumbnail are always re-discovered at upload time\n packageData.supernova.templates = Object.fromEntries(\n Object.entries(result.templates).map(([key, { name, description }]) => [key, { name, description }]),\n )\n\n // Write back to package.json\n writePackageJson(resolvedBasePath, packageData)\n\n return result\n}\n"],"names":[],"mappings":"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","debug_id":"7d906731-5fc8-5c9e-b336-a051b5efcb88"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type TemplatePreset = {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
thumbnail?: string;
|
|
5
|
+
files?: string[];
|
|
6
|
+
};
|
|
7
|
+
export interface Logger {
|
|
8
|
+
warn: (msg: string) => void;
|
|
9
|
+
error: (msg: string) => never;
|
|
10
|
+
log: (msg: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function fileExists(p: string): Promise<boolean>;
|
|
13
|
+
export declare function validateTemplates(templates: {
|
|
14
|
+
[key: string]: TemplatePreset;
|
|
15
|
+
}, logger: Logger, debug?: boolean): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=validate-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-templates.d.ts","sourceRoot":"","sources":["../../src/utils/validate-templates.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAExG,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,KAAK,CAAA;IAC7B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3B;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,MAAM,oBAOzC;AAED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAA;CAAE,EAC5C,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8648ca5c-4a11-592c-b7d6-b6ccc9afb0f6")}catch(e){}}();
|
|
3
|
+
import { action } from "@oclif/core/ux";
|
|
4
|
+
import { exec as execCallback } from "node:child_process";
|
|
5
|
+
import * as fs from "node:fs/promises";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
const exec = promisify(execCallback);
|
|
9
|
+
export async function fileExists(p) {
|
|
10
|
+
try {
|
|
11
|
+
await fs.access(p);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function validateTemplates(templates, logger, debug) {
|
|
19
|
+
action.start(`🔍 Validating ${Object.keys(templates).length} template(s)`);
|
|
20
|
+
for (const [templateKey, template] of Object.entries(templates)) {
|
|
21
|
+
action.start(`Validating template '${templateKey}'`);
|
|
22
|
+
if (!template.files || template.files.length === 0) {
|
|
23
|
+
action.stop("no files specified");
|
|
24
|
+
logger.error(`Template '${templateKey}': No files specified`);
|
|
25
|
+
}
|
|
26
|
+
const expectedMainFile = `supernova/templates/${templateKey}/${templateKey}.tsx`;
|
|
27
|
+
if (!template.files.includes(expectedMainFile)) {
|
|
28
|
+
action.stop("main file missing");
|
|
29
|
+
logger.error(`Template '${templateKey}': Expected main file '${expectedMainFile}' not found in files array`);
|
|
30
|
+
}
|
|
31
|
+
for (const filePath of template.files) {
|
|
32
|
+
if (!(await fileExists(path.resolve(filePath)))) {
|
|
33
|
+
action.stop("files missing");
|
|
34
|
+
logger.error(`Template '${templateKey}': File does not exist: ${filePath}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await testTemplateBuild(templateKey, template.files, logger, debug);
|
|
39
|
+
action.stop("build successful");
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
action.stop("build failed");
|
|
43
|
+
logger.error(`Template '${templateKey}': Build test failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
action.stop("validation complete");
|
|
47
|
+
}
|
|
48
|
+
async function testTemplateBuild(templateKey, files, logger, debug) {
|
|
49
|
+
const appTsxPath = path.resolve("src/App.tsx");
|
|
50
|
+
const componentsDir = path.resolve("src/components");
|
|
51
|
+
const toDestPath = (filePath) => path.join(componentsDir, filePath.replace(/^supernova\/(patterns|templates)\//, ""));
|
|
52
|
+
let originalAppContent = "";
|
|
53
|
+
let copiedFiles = [];
|
|
54
|
+
let failed = false;
|
|
55
|
+
try {
|
|
56
|
+
await checkNoDirsExist(files.map(f => path.dirname(toDestPath(f))));
|
|
57
|
+
copiedFiles = await copyFiles(files, toDestPath);
|
|
58
|
+
originalAppContent = await patchAppTsx(appTsxPath, templateKey);
|
|
59
|
+
await runBuild(logger);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
failed = true;
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
const keepFilesForDebugging = debug && failed;
|
|
67
|
+
if (!keepFilesForDebugging) {
|
|
68
|
+
await cleanup(copiedFiles, appTsxPath, originalAppContent);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function checkNoDirsExist(dirs) {
|
|
73
|
+
for (const dir of [...new Set(dirs)]) {
|
|
74
|
+
if (await fileExists(dir)) {
|
|
75
|
+
throw new Error(`Component directory already exists: ${path.relative(process.cwd(), dir)}. Please remove or rename this directory before testing the template.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function copyFiles(files, toDestPath) {
|
|
80
|
+
const copiedFiles = [];
|
|
81
|
+
for (const filePath of files) {
|
|
82
|
+
const destPath = toDestPath(filePath);
|
|
83
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
84
|
+
await fs.copyFile(path.resolve(filePath), destPath);
|
|
85
|
+
copiedFiles.push(destPath);
|
|
86
|
+
if (destPath.endsWith(".tsx") || destPath.endsWith(".ts")) {
|
|
87
|
+
await updateImportsInFile(destPath);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return copiedFiles;
|
|
91
|
+
}
|
|
92
|
+
async function patchAppTsx(appTsxPath, templateKey) {
|
|
93
|
+
if (!(await fileExists(appTsxPath)))
|
|
94
|
+
return "";
|
|
95
|
+
const originalContent = await fs.readFile(appTsxPath, "utf8");
|
|
96
|
+
await fs.writeFile(appTsxPath, `import { ${templateKey} } from "./components/${templateKey}/${templateKey}"\n\nexport default function App() {\n return <${templateKey} />\n}`);
|
|
97
|
+
return originalContent;
|
|
98
|
+
}
|
|
99
|
+
async function runBuild(logger) {
|
|
100
|
+
try {
|
|
101
|
+
const result = await exec("npm run build", { cwd: process.cwd() });
|
|
102
|
+
if (result.stderr)
|
|
103
|
+
logger.log(`Build stderr: ${result.stderr}`);
|
|
104
|
+
}
|
|
105
|
+
catch (buildError) {
|
|
106
|
+
logger.log(`Build failed with error: ${buildError.message}`);
|
|
107
|
+
if (buildError.stdout)
|
|
108
|
+
logger.log(`Build stdout: ${buildError.stdout}`);
|
|
109
|
+
if (buildError.stderr)
|
|
110
|
+
logger.log(`Build stderr: ${buildError.stderr}`);
|
|
111
|
+
throw buildError;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function cleanup(copiedFiles, appTsxPath, originalAppContent) {
|
|
115
|
+
for (const filePath of copiedFiles) {
|
|
116
|
+
if (await fileExists(filePath)) {
|
|
117
|
+
await fs.rm(filePath, { force: true });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const sortedDirs = [...new Set(copiedFiles.map(f => path.dirname(f)))].sort((a, b) => b.length - a.length);
|
|
121
|
+
for (const dir of sortedDirs) {
|
|
122
|
+
try {
|
|
123
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (originalAppContent && (await fileExists(appTsxPath))) {
|
|
129
|
+
await fs.writeFile(appTsxPath, originalAppContent);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function updateImportsInFile(filePath) {
|
|
133
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
134
|
+
const updatedContent = content.replace(/from\s+["']\.\.\/\.\.\/(patterns|templates)\/([^/"']+\/[^"']+)["']/g, 'from "../$2"');
|
|
135
|
+
if (content !== updatedContent) {
|
|
136
|
+
await fs.writeFile(filePath, updatedContent);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=validate-templates.js.map
|
|
140
|
+
//# debugId=8648ca5c-4a11-592c-b7d6-b6ccc9afb0f6
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-templates.js","sources":["../../src/utils/validate-templates.ts"],"sourceRoot":"","sourcesContent":["import { action } from \"@oclif/core/ux\"\nimport { exec as execCallback } from \"node:child_process\"\nimport * as fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { promisify } from \"node:util\"\n\nconst exec = promisify(execCallback)\n\nexport type TemplatePreset = { name: string; description: string; thumbnail?: string; files?: string[] }\n\nexport interface Logger {\n warn: (msg: string) => void\n error: (msg: string) => never\n log: (msg: string) => void\n}\n\nexport async function fileExists(p: string) {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\nexport async function validateTemplates(\n templates: { [key: string]: TemplatePreset },\n logger: Logger,\n debug?: boolean,\n): Promise<void> {\n action.start(`🔍 Validating ${Object.keys(templates).length} template(s)`)\n\n for (const [templateKey, template] of Object.entries(templates)) {\n action.start(`Validating template '${templateKey}'`)\n\n // Check if template has files\n if (!template.files || template.files.length === 0) {\n action.stop(\"no files specified\")\n logger.error(`Template '${templateKey}': No files specified`)\n }\n\n // Validate main file exists\n const expectedMainFile = `supernova/templates/${templateKey}/${templateKey}.tsx`\n if (!template.files.includes(expectedMainFile)) {\n action.stop(\"main file missing\")\n logger.error(`Template '${templateKey}': Expected main file '${expectedMainFile}' not found in files array`)\n }\n\n // Validate all files exist on disk\n for (const filePath of template.files) {\n if (!(await fileExists(path.resolve(filePath)))) {\n action.stop(\"files missing\")\n logger.error(`Template '${templateKey}': File does not exist: ${filePath}`)\n }\n }\n\n // Actually test the template by copying and building\n try {\n await testTemplateBuild(templateKey, template.files, logger, debug)\n action.stop(\"build successful\")\n } catch (error) {\n action.stop(\"build failed\")\n logger.error(\n `Template '${templateKey}': Build test failed: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n action.stop(\"validation complete\")\n}\n\nasync function testTemplateBuild(templateKey: string, files: string[], logger: Logger, debug?: boolean): Promise<void> {\n const appTsxPath = path.resolve(\"src/App.tsx\")\n const componentsDir = path.resolve(\"src/components\")\n const toDestPath = (filePath: string) =>\n path.join(componentsDir, filePath.replace(/^supernova\\/(patterns|templates)\\//, \"\"))\n\n let originalAppContent = \"\"\n let copiedFiles: string[] = []\n let failed = false\n\n try {\n await checkNoDirsExist(files.map(f => path.dirname(toDestPath(f))))\n copiedFiles = await copyFiles(files, toDestPath)\n originalAppContent = await patchAppTsx(appTsxPath, templateKey)\n await runBuild(logger)\n } catch (error) {\n failed = true\n throw error\n } finally {\n const keepFilesForDebugging = debug && failed\n if (!keepFilesForDebugging) {\n await cleanup(copiedFiles, appTsxPath, originalAppContent)\n }\n }\n}\n\nasync function checkNoDirsExist(dirs: string[]): Promise<void> {\n for (const dir of [...new Set(dirs)]) {\n if (await fileExists(dir)) {\n throw new Error(\n `Component directory already exists: ${path.relative(process.cwd(), dir)}. Please remove or rename this directory before testing the template.`,\n )\n }\n }\n}\n\nasync function copyFiles(files: string[], toDestPath: (f: string) => string): Promise<string[]> {\n const copiedFiles: string[] = []\n for (const filePath of files) {\n const destPath = toDestPath(filePath)\n await fs.mkdir(path.dirname(destPath), { recursive: true })\n await fs.copyFile(path.resolve(filePath), destPath)\n copiedFiles.push(destPath)\n if (destPath.endsWith(\".tsx\") || destPath.endsWith(\".ts\")) {\n await updateImportsInFile(destPath)\n }\n }\n return copiedFiles\n}\n\nasync function patchAppTsx(appTsxPath: string, templateKey: string): Promise<string> {\n if (!(await fileExists(appTsxPath))) return \"\"\n const originalContent = await fs.readFile(appTsxPath, \"utf8\")\n await fs.writeFile(\n appTsxPath,\n `import { ${templateKey} } from \"./components/${templateKey}/${templateKey}\"\\n\\nexport default function App() {\\n return <${templateKey} />\\n}`,\n )\n return originalContent\n}\n\nasync function runBuild(logger: Logger): Promise<void> {\n try {\n const result = await exec(\"npm run build\", { cwd: process.cwd() })\n if (result.stderr) logger.log(`Build stderr: ${result.stderr}`)\n } catch (buildError: any) {\n logger.log(`Build failed with error: ${buildError.message}`)\n if (buildError.stdout) logger.log(`Build stdout: ${buildError.stdout}`)\n if (buildError.stderr) logger.log(`Build stderr: ${buildError.stderr}`)\n throw buildError\n }\n}\n\nasync function cleanup(copiedFiles: string[], appTsxPath: string, originalAppContent: string): Promise<void> {\n for (const filePath of copiedFiles) {\n if (await fileExists(filePath)) {\n await fs.rm(filePath, { force: true })\n }\n }\n\n const sortedDirs = [...new Set(copiedFiles.map(f => path.dirname(f)))].sort((a, b) => b.length - a.length)\n for (const dir of sortedDirs) {\n try {\n await fs.rm(dir, { recursive: true, force: true })\n } catch {\n // ignore\n }\n }\n\n if (originalAppContent && (await fileExists(appTsxPath))) {\n await fs.writeFile(appTsxPath, originalAppContent)\n }\n}\n\nasync function updateImportsInFile(filePath: string): Promise<void> {\n const content = await fs.readFile(filePath, \"utf8\")\n const updatedContent = content.replace(\n /from\\s+[\"']\\.\\.\\/\\.\\.\\/(patterns|templates)\\/([^/\"']+\\/[^\"']+)[\"']/g,\n 'from \"../$2\"',\n )\n if (content !== updatedContent) {\n await fs.writeFile(filePath, updatedContent)\n }\n}\n"],"names":[],"mappings":"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","debug_id":"8648ca5c-4a11-592c-b7d6-b6ccc9afb0f6"}
|
package/oclif.manifest.json
CHANGED
|
@@ -520,7 +520,7 @@
|
|
|
520
520
|
"char": "w",
|
|
521
521
|
"description": "Workspace ID to upload the template to",
|
|
522
522
|
"name": "workspaceId",
|
|
523
|
-
"required":
|
|
523
|
+
"required": false,
|
|
524
524
|
"hasDynamicHelp": false,
|
|
525
525
|
"multiple": false,
|
|
526
526
|
"type": "option"
|
|
@@ -529,7 +529,7 @@
|
|
|
529
529
|
"char": "d",
|
|
530
530
|
"description": "Design system ID to upload the template to",
|
|
531
531
|
"name": "designSystemId",
|
|
532
|
-
"required":
|
|
532
|
+
"required": false,
|
|
533
533
|
"hasDynamicHelp": false,
|
|
534
534
|
"multiple": false,
|
|
535
535
|
"type": "option"
|
|
@@ -549,6 +549,21 @@
|
|
|
549
549
|
"hasDynamicHelp": false,
|
|
550
550
|
"multiple": false,
|
|
551
551
|
"type": "option"
|
|
552
|
+
},
|
|
553
|
+
"discover": {
|
|
554
|
+
"description": "Run template and pattern discovery before upload to update package.json",
|
|
555
|
+
"name": "discover",
|
|
556
|
+
"required": false,
|
|
557
|
+
"allowNo": false,
|
|
558
|
+
"type": "boolean"
|
|
559
|
+
},
|
|
560
|
+
"debug": {
|
|
561
|
+
"description": "Preserve shell directory and App.tsx on template build failures for debugging",
|
|
562
|
+
"hidden": true,
|
|
563
|
+
"name": "debug",
|
|
564
|
+
"required": false,
|
|
565
|
+
"allowNo": false,
|
|
566
|
+
"type": "boolean"
|
|
552
567
|
}
|
|
553
568
|
},
|
|
554
569
|
"hasDynamicHelp": false,
|
|
@@ -589,5 +604,5 @@
|
|
|
589
604
|
]
|
|
590
605
|
}
|
|
591
606
|
},
|
|
592
|
-
"version": "2.0.
|
|
607
|
+
"version": "2.0.38"
|
|
593
608
|
}
|