strapi2front 0.2.1 → 0.2.2
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/bin/strapi2front.js +78 -77
- package/dist/bin/strapi2front.js.map +1 -1
- package/dist/index.js +78 -77
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/bin/strapi2front.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import pc4 from 'picocolors';
|
|
4
|
-
import * as
|
|
4
|
+
import * as p from '@clack/prompts';
|
|
5
5
|
import fs4 from 'fs/promises';
|
|
6
6
|
import path5 from 'path';
|
|
7
7
|
import { spawn, execSync } from 'child_process';
|
|
@@ -141,8 +141,8 @@ function getInstallDevCommand(pm, pkg) {
|
|
|
141
141
|
return commands2[pm];
|
|
142
142
|
}
|
|
143
143
|
async function runInitPrompts(detection) {
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
p.intro(pc4.cyan("strapi2front setup"));
|
|
145
|
+
p.note(
|
|
146
146
|
[
|
|
147
147
|
`Framework: ${pc4.green(getFrameworkDisplayName(detection.framework.name))} ${detection.framework.version ? pc4.dim(`v${detection.framework.version}`) : ""}`,
|
|
148
148
|
`TypeScript: ${detection.typescript.enabled ? pc4.green("enabled") : pc4.yellow("disabled")}`,
|
|
@@ -151,15 +151,15 @@ async function runInitPrompts(detection) {
|
|
|
151
151
|
"Detected Configuration"
|
|
152
152
|
);
|
|
153
153
|
if (detection.framework.name === "unknown") {
|
|
154
|
-
|
|
154
|
+
p.cancel("Could not detect a supported framework. Currently only Astro is supported.");
|
|
155
155
|
return null;
|
|
156
156
|
}
|
|
157
157
|
if (detection.framework.name !== "astro") {
|
|
158
|
-
|
|
158
|
+
p.cancel(`${detection.framework.name} is not yet supported. Currently only Astro is supported.`);
|
|
159
159
|
return null;
|
|
160
160
|
}
|
|
161
161
|
const defaultUrl = "http://localhost:1337";
|
|
162
|
-
const strapiUrlInput = await
|
|
162
|
+
const strapiUrlInput = await p.text({
|
|
163
163
|
message: "What is your Strapi URL?",
|
|
164
164
|
placeholder: `${defaultUrl} (press Enter for default)`,
|
|
165
165
|
validate: (value) => {
|
|
@@ -173,24 +173,24 @@ async function runInitPrompts(detection) {
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
|
-
if (
|
|
177
|
-
|
|
176
|
+
if (p.isCancel(strapiUrlInput)) {
|
|
177
|
+
p.cancel("Setup cancelled");
|
|
178
178
|
return null;
|
|
179
179
|
}
|
|
180
180
|
const strapiUrl = (strapiUrlInput || "").trim() || defaultUrl;
|
|
181
|
-
const strapiToken = await
|
|
181
|
+
const strapiToken = await p.text({
|
|
182
182
|
message: "What is your Strapi API token?",
|
|
183
183
|
placeholder: "Press Enter to skip (you can add it later in .env)"
|
|
184
184
|
});
|
|
185
|
-
if (
|
|
186
|
-
|
|
185
|
+
if (p.isCancel(strapiToken)) {
|
|
186
|
+
p.cancel("Setup cancelled");
|
|
187
187
|
return null;
|
|
188
188
|
}
|
|
189
189
|
const trimmedToken = (strapiToken || "").trim();
|
|
190
190
|
if (trimmedToken === "") {
|
|
191
|
-
|
|
191
|
+
p.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
|
|
192
192
|
}
|
|
193
|
-
const strapiVersion = await
|
|
193
|
+
const strapiVersion = await p.select({
|
|
194
194
|
message: "What version of Strapi are you using?",
|
|
195
195
|
options: [
|
|
196
196
|
{ value: "v5", label: "Strapi v5", hint: "Recommended - Latest version" },
|
|
@@ -198,21 +198,42 @@ async function runInitPrompts(detection) {
|
|
|
198
198
|
],
|
|
199
199
|
initialValue: "v5"
|
|
200
200
|
});
|
|
201
|
-
if (
|
|
202
|
-
|
|
201
|
+
if (p.isCancel(strapiVersion)) {
|
|
202
|
+
p.cancel("Setup cancelled");
|
|
203
203
|
return null;
|
|
204
204
|
}
|
|
205
|
-
|
|
206
|
-
const
|
|
205
|
+
p.log.info(pc4.dim(`Using Strapi ${strapiVersion}. This can be changed later in strapi.config.ts`));
|
|
206
|
+
const defaultPrefix = "/api";
|
|
207
|
+
const apiPrefixInput = await p.text({
|
|
208
|
+
message: "What is your Strapi API prefix?",
|
|
209
|
+
placeholder: `${defaultPrefix} (press Enter for default)`,
|
|
210
|
+
validate: (value) => {
|
|
211
|
+
const trimmed = (value || "").trim();
|
|
212
|
+
if (trimmed === "") return void 0;
|
|
213
|
+
if (!trimmed.startsWith("/")) {
|
|
214
|
+
return "API prefix must start with /";
|
|
215
|
+
}
|
|
216
|
+
return void 0;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
if (p.isCancel(apiPrefixInput)) {
|
|
220
|
+
p.cancel("Setup cancelled");
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const apiPrefix = (apiPrefixInput || "").trim() || defaultPrefix;
|
|
224
|
+
if (apiPrefix !== defaultPrefix) {
|
|
225
|
+
p.log.info(pc4.dim(`Using custom API prefix: ${apiPrefix}`));
|
|
226
|
+
}
|
|
227
|
+
const outputDir = await p.text({
|
|
207
228
|
message: "Where should we generate the Strapi files?",
|
|
208
229
|
placeholder: "src/strapi",
|
|
209
230
|
defaultValue: "src/strapi"
|
|
210
231
|
});
|
|
211
|
-
if (
|
|
212
|
-
|
|
232
|
+
if (p.isCancel(outputDir)) {
|
|
233
|
+
p.cancel("Setup cancelled");
|
|
213
234
|
return null;
|
|
214
235
|
}
|
|
215
|
-
const features = await
|
|
236
|
+
const features = await p.multiselect({
|
|
216
237
|
message: "What would you like to generate?",
|
|
217
238
|
options: [
|
|
218
239
|
{ value: "types", label: "Types", hint: "TypeScript interfaces for your content types" },
|
|
@@ -222,14 +243,15 @@ async function runInitPrompts(detection) {
|
|
|
222
243
|
initialValues: ["types", "services", "actions"],
|
|
223
244
|
required: true
|
|
224
245
|
});
|
|
225
|
-
if (
|
|
226
|
-
|
|
246
|
+
if (p.isCancel(features)) {
|
|
247
|
+
p.cancel("Setup cancelled");
|
|
227
248
|
return null;
|
|
228
249
|
}
|
|
229
250
|
return {
|
|
230
251
|
strapiUrl,
|
|
231
252
|
strapiToken: trimmedToken,
|
|
232
253
|
strapiVersion,
|
|
254
|
+
apiPrefix,
|
|
233
255
|
outputDir: (outputDir || "").trim() || "src/strapi",
|
|
234
256
|
generateActions: features.includes("actions"),
|
|
235
257
|
generateServices: features.includes("services")
|
|
@@ -282,7 +304,7 @@ function execAsync(command, cwd) {
|
|
|
282
304
|
}
|
|
283
305
|
async function initCommand(_options) {
|
|
284
306
|
const cwd = process.cwd();
|
|
285
|
-
const s =
|
|
307
|
+
const s = p.spinner();
|
|
286
308
|
s.start("Detecting project configuration...");
|
|
287
309
|
const [framework, typescript, packageManager] = await Promise.all([
|
|
288
310
|
detectFramework(cwd),
|
|
@@ -303,6 +325,7 @@ async function initCommand(_options) {
|
|
|
303
325
|
const configContent = generateConfigFile({
|
|
304
326
|
strapiUrl: answers.strapiUrl,
|
|
305
327
|
strapiVersion: answers.strapiVersion,
|
|
328
|
+
apiPrefix: answers.apiPrefix,
|
|
306
329
|
outputDir: answers.outputDir,
|
|
307
330
|
generateActions: answers.generateActions,
|
|
308
331
|
generateServices: answers.generateServices
|
|
@@ -317,12 +340,12 @@ async function initCommand(_options) {
|
|
|
317
340
|
const outputPath = path5.join(cwd, answers.outputDir);
|
|
318
341
|
await fs4.mkdir(outputPath, { recursive: true });
|
|
319
342
|
s.stop("Configuration files created");
|
|
320
|
-
const installDeps = await
|
|
343
|
+
const installDeps = await p.confirm({
|
|
321
344
|
message: "Install required dependencies (strapi2front, strapi-sdk-js)?",
|
|
322
345
|
initialValue: true
|
|
323
346
|
});
|
|
324
|
-
if (
|
|
325
|
-
|
|
347
|
+
if (p.isCancel(installDeps)) {
|
|
348
|
+
p.cancel("Setup cancelled");
|
|
326
349
|
process.exit(0);
|
|
327
350
|
}
|
|
328
351
|
if (installDeps) {
|
|
@@ -345,11 +368,11 @@ async function initCommand(_options) {
|
|
|
345
368
|
logger.warn(`Please install manually: ${installSdkCmd}`);
|
|
346
369
|
}
|
|
347
370
|
} else {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
371
|
+
p.log.info(pc4.dim("Remember to install dependencies manually:"));
|
|
372
|
+
p.log.info(pc4.dim(` ${getInstallDevCommand(packageManager.name, "strapi2front")}`));
|
|
373
|
+
p.log.info(pc4.dim(` ${getInstallCommand(packageManager.name, "strapi-sdk-js")}`));
|
|
351
374
|
}
|
|
352
|
-
|
|
375
|
+
p.note(
|
|
353
376
|
[
|
|
354
377
|
`${pc4.green("v")} Created ${pc4.cyan("strapi.config.ts")}`,
|
|
355
378
|
`${pc4.green("v")} Updated ${pc4.cyan(".env")} with Strapi credentials`,
|
|
@@ -362,7 +385,7 @@ async function initCommand(_options) {
|
|
|
362
385
|
].join("\n"),
|
|
363
386
|
"Setup complete!"
|
|
364
387
|
);
|
|
365
|
-
|
|
388
|
+
p.outro(pc4.green("Happy coding!"));
|
|
366
389
|
} catch (error) {
|
|
367
390
|
s.stop("Failed to create configuration files");
|
|
368
391
|
logger.error(error instanceof Error ? error.message : "Unknown error");
|
|
@@ -370,16 +393,17 @@ async function initCommand(_options) {
|
|
|
370
393
|
}
|
|
371
394
|
}
|
|
372
395
|
function generateConfigFile(answers) {
|
|
396
|
+
const apiPrefixLine = answers.apiPrefix !== "/api" ? `
|
|
397
|
+
// API prefix (customized from default "/api")
|
|
398
|
+
apiPrefix: "${answers.apiPrefix}",
|
|
399
|
+
` : "";
|
|
373
400
|
return `import { defineConfig } from "strapi2front";
|
|
374
401
|
|
|
375
402
|
export default defineConfig({
|
|
376
403
|
// Strapi connection
|
|
377
404
|
url: process.env.STRAPI_URL || "${answers.strapiUrl}",
|
|
378
405
|
token: process.env.STRAPI_TOKEN,
|
|
379
|
-
|
|
380
|
-
// API prefix (default: "/api", change if you customized it in Strapi)
|
|
381
|
-
// apiPrefix: "/api",
|
|
382
|
-
|
|
406
|
+
${apiPrefixLine}
|
|
383
407
|
// Output configuration
|
|
384
408
|
output: {
|
|
385
409
|
path: "${answers.outputDir}",
|
|
@@ -516,35 +540,12 @@ function cleanOrphanedFiles(outputPath, orphanedItems) {
|
|
|
516
540
|
}
|
|
517
541
|
async function syncCommand(options) {
|
|
518
542
|
const cwd = process.cwd();
|
|
519
|
-
|
|
520
|
-
const s =
|
|
543
|
+
p.intro(pc4.cyan("strapi2front sync"));
|
|
544
|
+
const s = p.spinner();
|
|
521
545
|
try {
|
|
522
546
|
s.start("Loading configuration...");
|
|
523
547
|
let config = await loadConfig(cwd);
|
|
524
548
|
s.stop("Configuration loaded");
|
|
525
|
-
const currentPrefix = config.apiPrefix || "/api";
|
|
526
|
-
const apiPrefixInput = await p3.text({
|
|
527
|
-
message: "What is your Strapi API prefix?",
|
|
528
|
-
placeholder: `${currentPrefix} (press Enter to use configured value)`,
|
|
529
|
-
initialValue: currentPrefix,
|
|
530
|
-
validate: (value) => {
|
|
531
|
-
const trimmed = (value || "").trim();
|
|
532
|
-
if (trimmed === "") return void 0;
|
|
533
|
-
if (!trimmed.startsWith("/")) {
|
|
534
|
-
return "API prefix must start with /";
|
|
535
|
-
}
|
|
536
|
-
return void 0;
|
|
537
|
-
}
|
|
538
|
-
});
|
|
539
|
-
if (p3.isCancel(apiPrefixInput)) {
|
|
540
|
-
p3.cancel("Sync cancelled");
|
|
541
|
-
process.exit(0);
|
|
542
|
-
}
|
|
543
|
-
const apiPrefix = (apiPrefixInput || "").trim() || currentPrefix;
|
|
544
|
-
if (apiPrefix !== currentPrefix) {
|
|
545
|
-
p3.log.info(pc4.dim(`Using API prefix: ${apiPrefix}`));
|
|
546
|
-
config = { ...config, apiPrefix };
|
|
547
|
-
}
|
|
548
549
|
s.start("Detecting Strapi version...");
|
|
549
550
|
const versionResult = await detectStrapiVersion(config.url, config.token, config.apiPrefix);
|
|
550
551
|
s.stop("Version detection complete");
|
|
@@ -552,21 +553,21 @@ async function syncCommand(options) {
|
|
|
552
553
|
if (versionResult.detected) {
|
|
553
554
|
if (versionResult.detected !== config.strapiVersion) {
|
|
554
555
|
if (versionResult.detected === "v5" && config.strapiVersion === "v4") {
|
|
555
|
-
|
|
556
|
+
p.log.warn(
|
|
556
557
|
pc4.yellow(`Detected Strapi ${pc4.bold("v5")} but config has ${pc4.bold("v4")}. Using v5.`)
|
|
557
558
|
);
|
|
558
559
|
effectiveVersion = "v5";
|
|
559
560
|
} else if (versionResult.detected === "v4" && config.strapiVersion === "v5") {
|
|
560
|
-
|
|
561
|
+
p.log.warn(
|
|
561
562
|
pc4.yellow(`Detected Strapi ${pc4.bold("v4")} but config has ${pc4.bold("v5")}. Using v4.`)
|
|
562
563
|
);
|
|
563
564
|
effectiveVersion = "v4";
|
|
564
565
|
}
|
|
565
566
|
} else {
|
|
566
|
-
|
|
567
|
+
p.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
|
|
567
568
|
}
|
|
568
569
|
} else {
|
|
569
|
-
|
|
570
|
+
p.log.warn(pc4.yellow(`Could not detect Strapi version. Using ${pc4.bold(config.strapiVersion)}`));
|
|
570
571
|
}
|
|
571
572
|
config = { ...config, strapiVersion: effectiveVersion };
|
|
572
573
|
s.start("Fetching schema from Strapi...");
|
|
@@ -576,13 +577,13 @@ async function syncCommand(options) {
|
|
|
576
577
|
let blocksRendererInstalled = isPackageInstalled(BLOCKS_RENDERER_PACKAGE, cwd);
|
|
577
578
|
const { hasBlocks: hasBlocksFields, fieldsFound: blocksFieldsFound } = schemaHasBlocks(schema);
|
|
578
579
|
if (hasBlocksFields && !blocksRendererInstalled) {
|
|
579
|
-
|
|
580
|
-
const installBlocks = await
|
|
580
|
+
p.log.info(`Blocks fields detected: ${pc4.cyan(blocksFieldsFound.join(", "))}`);
|
|
581
|
+
const installBlocks = await p.confirm({
|
|
581
582
|
message: `Install ${pc4.cyan(BLOCKS_RENDERER_PACKAGE)} for proper type support and rendering?`,
|
|
582
583
|
initialValue: true
|
|
583
584
|
});
|
|
584
|
-
if (
|
|
585
|
-
|
|
585
|
+
if (p.isCancel(installBlocks)) {
|
|
586
|
+
p.cancel("Sync cancelled");
|
|
586
587
|
process.exit(0);
|
|
587
588
|
}
|
|
588
589
|
if (installBlocks) {
|
|
@@ -596,7 +597,7 @@ async function syncCommand(options) {
|
|
|
596
597
|
logger.warn("You can install it manually later and re-run sync");
|
|
597
598
|
}
|
|
598
599
|
} else {
|
|
599
|
-
|
|
600
|
+
p.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
|
|
600
601
|
}
|
|
601
602
|
}
|
|
602
603
|
const outputPath = path5.join(cwd, config.output.path);
|
|
@@ -608,18 +609,18 @@ async function syncCommand(options) {
|
|
|
608
609
|
const orphanedFolders = getOrphanedFolders(outputPath, currentStructure);
|
|
609
610
|
if (orphanedFolders.length > 0) {
|
|
610
611
|
const otherStructure = isByFeature ? "by-layer" : "by-feature";
|
|
611
|
-
|
|
612
|
+
p.log.warn(
|
|
612
613
|
pc4.yellow(`Found files from previous ${pc4.bold(otherStructure)} structure:`)
|
|
613
614
|
);
|
|
614
|
-
|
|
615
|
+
p.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
|
|
615
616
|
let shouldClean = options.clean;
|
|
616
617
|
if (!shouldClean) {
|
|
617
|
-
const cleanResponse = await
|
|
618
|
+
const cleanResponse = await p.confirm({
|
|
618
619
|
message: `Remove orphaned ${otherStructure} files?`,
|
|
619
620
|
initialValue: true
|
|
620
621
|
});
|
|
621
|
-
if (
|
|
622
|
-
|
|
622
|
+
if (p.isCancel(cleanResponse)) {
|
|
623
|
+
p.cancel("Sync cancelled");
|
|
623
624
|
process.exit(0);
|
|
624
625
|
}
|
|
625
626
|
shouldClean = cleanResponse;
|
|
@@ -629,7 +630,7 @@ async function syncCommand(options) {
|
|
|
629
630
|
cleanOrphanedFiles(outputPath, orphanedFolders);
|
|
630
631
|
s.stop(`Removed: ${orphanedFolders.join(", ")}`);
|
|
631
632
|
} else {
|
|
632
|
-
|
|
633
|
+
p.log.info(pc4.dim("Keeping orphaned files. You can clean them manually or use --clean flag."));
|
|
633
634
|
}
|
|
634
635
|
}
|
|
635
636
|
}
|
|
@@ -708,7 +709,7 @@ async function syncCommand(options) {
|
|
|
708
709
|
}
|
|
709
710
|
}
|
|
710
711
|
}
|
|
711
|
-
|
|
712
|
+
p.note(
|
|
712
713
|
[
|
|
713
714
|
`Generated ${generatedFiles.length} files in ${pc4.cyan(config.output.path)}`,
|
|
714
715
|
"",
|
|
@@ -718,7 +719,7 @@ async function syncCommand(options) {
|
|
|
718
719
|
].filter(Boolean).join("\n"),
|
|
719
720
|
"Sync complete!"
|
|
720
721
|
);
|
|
721
|
-
|
|
722
|
+
p.outro(pc4.green("Types and services are ready to use!"));
|
|
722
723
|
} catch (error) {
|
|
723
724
|
s.stop("Sync failed");
|
|
724
725
|
if (error instanceof Error) {
|