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.
@@ -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 p3 from '@clack/prompts';
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
- p3.intro(pc4.cyan("strapi2front setup"));
145
- p3.note(
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
- p3.cancel("Could not detect a supported framework. Currently only Astro is supported.");
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
- p3.cancel(`${detection.framework.name} is not yet supported. Currently only Astro is supported.`);
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 p3.text({
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 (p3.isCancel(strapiUrlInput)) {
177
- p3.cancel("Setup cancelled");
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 p3.text({
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 (p3.isCancel(strapiToken)) {
186
- p3.cancel("Setup cancelled");
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
- p3.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
191
+ p.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
192
192
  }
193
- const strapiVersion = await p3.select({
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 (p3.isCancel(strapiVersion)) {
202
- p3.cancel("Setup cancelled");
201
+ if (p.isCancel(strapiVersion)) {
202
+ p.cancel("Setup cancelled");
203
203
  return null;
204
204
  }
205
- p3.log.info(pc4.dim(`Using Strapi ${strapiVersion}. This can be changed later in strapi.config.ts`));
206
- const outputDir = await p3.text({
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 (p3.isCancel(outputDir)) {
212
- p3.cancel("Setup cancelled");
232
+ if (p.isCancel(outputDir)) {
233
+ p.cancel("Setup cancelled");
213
234
  return null;
214
235
  }
215
- const features = await p3.multiselect({
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 (p3.isCancel(features)) {
226
- p3.cancel("Setup cancelled");
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 = p3.spinner();
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 p3.confirm({
343
+ const installDeps = await p.confirm({
321
344
  message: "Install required dependencies (strapi2front, strapi-sdk-js)?",
322
345
  initialValue: true
323
346
  });
324
- if (p3.isCancel(installDeps)) {
325
- p3.cancel("Setup cancelled");
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
- p3.log.info(pc4.dim("Remember to install dependencies manually:"));
349
- p3.log.info(pc4.dim(` ${getInstallDevCommand(packageManager.name, "strapi2front")}`));
350
- p3.log.info(pc4.dim(` ${getInstallCommand(packageManager.name, "strapi-sdk-js")}`));
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
- p3.note(
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
- p3.outro(pc4.green("Happy coding!"));
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", change if you customized it in Strapi)
381
- // apiPrefix: "/api",
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
- p3.intro(pc4.cyan("strapi2front sync"));
520
- const s = p3.spinner();
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
- p3.log.warn(
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
- p3.log.warn(
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
- p3.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
566
+ p.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
567
567
  }
568
568
  } else {
569
- p3.log.warn(pc4.yellow(`Could not detect Strapi version. Using ${pc4.bold(config.strapiVersion)}`));
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
- p3.log.info(`Blocks fields detected: ${pc4.cyan(blocksFieldsFound.join(", "))}`);
580
- const installBlocks = await p3.confirm({
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 (p3.isCancel(installBlocks)) {
585
- p3.cancel("Sync cancelled");
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
- p3.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
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
- p3.log.warn(
611
+ p.log.warn(
612
612
  pc4.yellow(`Found files from previous ${pc4.bold(otherStructure)} structure:`)
613
613
  );
614
- p3.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
614
+ p.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
615
615
  let shouldClean = options.clean;
616
616
  if (!shouldClean) {
617
- const cleanResponse = await p3.confirm({
617
+ const cleanResponse = await p.confirm({
618
618
  message: `Remove orphaned ${otherStructure} files?`,
619
619
  initialValue: true
620
620
  });
621
- if (p3.isCancel(cleanResponse)) {
622
- p3.cancel("Sync cancelled");
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
- p3.log.info(pc4.dim("Keeping orphaned files. You can clean them manually or use --clean flag."));
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
- p3.note(
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
- p3.outro(pc4.green("Types and services are ready to use!"));
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) {