strapi2front 0.2.1 → 0.2.3
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 +75 -75
- package/dist/bin/strapi2front.js.map +1 -1
- package/dist/index.js +75 -75
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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");
|
|
@@ -377,8 +400,8 @@ export default defineConfig({
|
|
|
377
400
|
url: process.env.STRAPI_URL || "${answers.strapiUrl}",
|
|
378
401
|
token: process.env.STRAPI_TOKEN,
|
|
379
402
|
|
|
380
|
-
// API prefix (default: "/api"
|
|
381
|
-
|
|
403
|
+
// API prefix (default: "/api")
|
|
404
|
+
apiPrefix: "${answers.apiPrefix}",
|
|
382
405
|
|
|
383
406
|
// Output configuration
|
|
384
407
|
output: {
|
|
@@ -516,35 +539,12 @@ function cleanOrphanedFiles(outputPath, orphanedItems) {
|
|
|
516
539
|
}
|
|
517
540
|
async function syncCommand(options) {
|
|
518
541
|
const cwd = process.cwd();
|
|
519
|
-
|
|
520
|
-
const s =
|
|
542
|
+
p.intro(pc4.cyan("strapi2front sync"));
|
|
543
|
+
const s = p.spinner();
|
|
521
544
|
try {
|
|
522
545
|
s.start("Loading configuration...");
|
|
523
546
|
let config = await loadConfig(cwd);
|
|
524
547
|
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
548
|
s.start("Detecting Strapi version...");
|
|
549
549
|
const versionResult = await detectStrapiVersion(config.url, config.token, config.apiPrefix);
|
|
550
550
|
s.stop("Version detection complete");
|
|
@@ -552,21 +552,21 @@ async function syncCommand(options) {
|
|
|
552
552
|
if (versionResult.detected) {
|
|
553
553
|
if (versionResult.detected !== config.strapiVersion) {
|
|
554
554
|
if (versionResult.detected === "v5" && config.strapiVersion === "v4") {
|
|
555
|
-
|
|
555
|
+
p.log.warn(
|
|
556
556
|
pc4.yellow(`Detected Strapi ${pc4.bold("v5")} but config has ${pc4.bold("v4")}. Using v5.`)
|
|
557
557
|
);
|
|
558
558
|
effectiveVersion = "v5";
|
|
559
559
|
} else if (versionResult.detected === "v4" && config.strapiVersion === "v5") {
|
|
560
|
-
|
|
560
|
+
p.log.warn(
|
|
561
561
|
pc4.yellow(`Detected Strapi ${pc4.bold("v4")} but config has ${pc4.bold("v5")}. Using v4.`)
|
|
562
562
|
);
|
|
563
563
|
effectiveVersion = "v4";
|
|
564
564
|
}
|
|
565
565
|
} else {
|
|
566
|
-
|
|
566
|
+
p.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
|
|
567
567
|
}
|
|
568
568
|
} else {
|
|
569
|
-
|
|
569
|
+
p.log.warn(pc4.yellow(`Could not detect Strapi version. Using ${pc4.bold(config.strapiVersion)}`));
|
|
570
570
|
}
|
|
571
571
|
config = { ...config, strapiVersion: effectiveVersion };
|
|
572
572
|
s.start("Fetching schema from Strapi...");
|
|
@@ -576,13 +576,13 @@ async function syncCommand(options) {
|
|
|
576
576
|
let blocksRendererInstalled = isPackageInstalled(BLOCKS_RENDERER_PACKAGE, cwd);
|
|
577
577
|
const { hasBlocks: hasBlocksFields, fieldsFound: blocksFieldsFound } = schemaHasBlocks(schema);
|
|
578
578
|
if (hasBlocksFields && !blocksRendererInstalled) {
|
|
579
|
-
|
|
580
|
-
const installBlocks = await
|
|
579
|
+
p.log.info(`Blocks fields detected: ${pc4.cyan(blocksFieldsFound.join(", "))}`);
|
|
580
|
+
const installBlocks = await p.confirm({
|
|
581
581
|
message: `Install ${pc4.cyan(BLOCKS_RENDERER_PACKAGE)} for proper type support and rendering?`,
|
|
582
582
|
initialValue: true
|
|
583
583
|
});
|
|
584
|
-
if (
|
|
585
|
-
|
|
584
|
+
if (p.isCancel(installBlocks)) {
|
|
585
|
+
p.cancel("Sync cancelled");
|
|
586
586
|
process.exit(0);
|
|
587
587
|
}
|
|
588
588
|
if (installBlocks) {
|
|
@@ -596,7 +596,7 @@ async function syncCommand(options) {
|
|
|
596
596
|
logger.warn("You can install it manually later and re-run sync");
|
|
597
597
|
}
|
|
598
598
|
} else {
|
|
599
|
-
|
|
599
|
+
p.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
|
|
600
600
|
}
|
|
601
601
|
}
|
|
602
602
|
const outputPath = path5.join(cwd, config.output.path);
|
|
@@ -608,18 +608,18 @@ async function syncCommand(options) {
|
|
|
608
608
|
const orphanedFolders = getOrphanedFolders(outputPath, currentStructure);
|
|
609
609
|
if (orphanedFolders.length > 0) {
|
|
610
610
|
const otherStructure = isByFeature ? "by-layer" : "by-feature";
|
|
611
|
-
|
|
611
|
+
p.log.warn(
|
|
612
612
|
pc4.yellow(`Found files from previous ${pc4.bold(otherStructure)} structure:`)
|
|
613
613
|
);
|
|
614
|
-
|
|
614
|
+
p.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
|
|
615
615
|
let shouldClean = options.clean;
|
|
616
616
|
if (!shouldClean) {
|
|
617
|
-
const cleanResponse = await
|
|
617
|
+
const cleanResponse = await p.confirm({
|
|
618
618
|
message: `Remove orphaned ${otherStructure} files?`,
|
|
619
619
|
initialValue: true
|
|
620
620
|
});
|
|
621
|
-
if (
|
|
622
|
-
|
|
621
|
+
if (p.isCancel(cleanResponse)) {
|
|
622
|
+
p.cancel("Sync cancelled");
|
|
623
623
|
process.exit(0);
|
|
624
624
|
}
|
|
625
625
|
shouldClean = cleanResponse;
|
|
@@ -629,7 +629,7 @@ async function syncCommand(options) {
|
|
|
629
629
|
cleanOrphanedFiles(outputPath, orphanedFolders);
|
|
630
630
|
s.stop(`Removed: ${orphanedFolders.join(", ")}`);
|
|
631
631
|
} else {
|
|
632
|
-
|
|
632
|
+
p.log.info(pc4.dim("Keeping orphaned files. You can clean them manually or use --clean flag."));
|
|
633
633
|
}
|
|
634
634
|
}
|
|
635
635
|
}
|
|
@@ -708,7 +708,7 @@ async function syncCommand(options) {
|
|
|
708
708
|
}
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
|
-
|
|
711
|
+
p.note(
|
|
712
712
|
[
|
|
713
713
|
`Generated ${generatedFiles.length} files in ${pc4.cyan(config.output.path)}`,
|
|
714
714
|
"",
|
|
@@ -718,7 +718,7 @@ async function syncCommand(options) {
|
|
|
718
718
|
].filter(Boolean).join("\n"),
|
|
719
719
|
"Sync complete!"
|
|
720
720
|
);
|
|
721
|
-
|
|
721
|
+
p.outro(pc4.green("Types and services are ready to use!"));
|
|
722
722
|
} catch (error) {
|
|
723
723
|
s.stop("Sync failed");
|
|
724
724
|
if (error instanceof Error) {
|