strapi2front 0.3.2 → 0.4.1

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.
@@ -2,10 +2,10 @@
2
2
  import { Command } from 'commander';
3
3
  import pc4 from 'picocolors';
4
4
  import * as p from '@clack/prompts';
5
- import fs4 from 'fs/promises';
6
- import path5 from 'path';
5
+ import fs5 from 'fs/promises';
6
+ import path6 from 'path';
7
7
  import { spawn, execSync } from 'child_process';
8
- import fs5 from 'fs';
8
+ import fs6 from 'fs';
9
9
  import { loadConfig, detectStrapiVersion, fetchSchema, parseSchema } from '@strapi2front/core';
10
10
  import { generateByFeature, generateTypes, generateClient, generateLocales, generateServices, generateActions } from '@strapi2front/generators';
11
11
 
@@ -24,17 +24,17 @@ var FRAMEWORK_DETECTORS = {
24
24
  }
25
25
  };
26
26
  async function detectFramework(cwd = process.cwd()) {
27
- const pkgPath = path5.join(cwd, "package.json");
27
+ const pkgPath = path6.join(cwd, "package.json");
28
28
  try {
29
- const pkgContent = await fs4.readFile(pkgPath, "utf-8");
29
+ const pkgContent = await fs5.readFile(pkgPath, "utf-8");
30
30
  const pkg = JSON.parse(pkgContent);
31
31
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
32
32
  for (const [pkgName, detector] of Object.entries(FRAMEWORK_DETECTORS)) {
33
33
  if (deps[pkgName]) {
34
34
  for (const configFile of detector.configFiles) {
35
- const configPath = path5.join(cwd, configFile);
35
+ const configPath = path6.join(cwd, configFile);
36
36
  try {
37
- await fs4.access(configPath);
37
+ await fs5.access(configPath);
38
38
  return {
39
39
  name: detector.name,
40
40
  version: deps[pkgName],
@@ -70,12 +70,12 @@ function getFrameworkDisplayName(framework) {
70
70
  var TS_CONFIG_FILES = ["tsconfig.json", "tsconfig.app.json"];
71
71
  async function detectTypeScript(cwd = process.cwd()) {
72
72
  for (const configFile of TS_CONFIG_FILES) {
73
- const configPath = path5.join(cwd, configFile);
73
+ const configPath = path6.join(cwd, configFile);
74
74
  try {
75
- await fs4.access(configPath);
76
- const pkgPath = path5.join(cwd, "package.json");
75
+ await fs5.access(configPath);
76
+ const pkgPath = path6.join(cwd, "package.json");
77
77
  try {
78
- const pkgContent = await fs4.readFile(pkgPath, "utf-8");
78
+ const pkgContent = await fs5.readFile(pkgPath, "utf-8");
79
79
  const pkg = JSON.parse(pkgContent);
80
80
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
81
81
  return {
@@ -107,9 +107,9 @@ var LOCK_FILES = {
107
107
  };
108
108
  async function detectPackageManager(cwd = process.cwd()) {
109
109
  for (const [lockFile, pm] of Object.entries(LOCK_FILES)) {
110
- const lockPath = path5.join(cwd, lockFile);
110
+ const lockPath = path6.join(cwd, lockFile);
111
111
  try {
112
- await fs4.access(lockPath);
112
+ await fs5.access(lockPath);
113
113
  return {
114
114
  name: pm,
115
115
  lockFile
@@ -140,6 +140,34 @@ function getInstallDevCommand(pm, pkg) {
140
140
  };
141
141
  return commands2[pm];
142
142
  }
143
+ async function detectModuleType(cwd = process.cwd()) {
144
+ try {
145
+ const packageJsonPath = path6.join(cwd, "package.json");
146
+ const content = await fs5.readFile(packageJsonPath, "utf-8");
147
+ const packageJson = JSON.parse(content);
148
+ if (packageJson.type === "module") {
149
+ return { type: "esm", reason: 'package.json has "type": "module"' };
150
+ }
151
+ if (packageJson.type === "commonjs") {
152
+ return { type: "commonjs", reason: 'package.json has "type": "commonjs"' };
153
+ }
154
+ } catch {
155
+ }
156
+ const esmIndicators = [
157
+ "next.config.mjs",
158
+ "nuxt.config.mjs",
159
+ "vite.config.mjs",
160
+ "astro.config.mjs"
161
+ ];
162
+ for (const file of esmIndicators) {
163
+ try {
164
+ await fs5.access(path6.join(cwd, file));
165
+ return { type: "esm", reason: `Found ${file} (ESM config file)` };
166
+ } catch {
167
+ }
168
+ }
169
+ return { type: "commonjs", reason: "Default (no ESM indicators found)" };
170
+ }
143
171
  function getMajorVersion(version) {
144
172
  if (!version) return null;
145
173
  const match = version.replace(/^[\^~]/, "").match(/^(\d+)/);
@@ -350,6 +378,11 @@ async function initCommand(_options) {
350
378
  }
351
379
  s.start("Creating configuration files...");
352
380
  try {
381
+ let moduleType = "commonjs";
382
+ if (answers.outputFormat === "jsdoc") {
383
+ const detected = await detectModuleType(cwd);
384
+ moduleType = detected.type;
385
+ }
353
386
  const configExtension = answers.outputFormat === "jsdoc" ? "js" : "ts";
354
387
  const configContent = generateConfigFile({
355
388
  strapiUrl: answers.strapiUrl,
@@ -358,17 +391,18 @@ async function initCommand(_options) {
358
391
  outputFormat: answers.outputFormat,
359
392
  outputDir: answers.outputDir,
360
393
  generateActions: answers.generateActions,
361
- generateServices: answers.generateServices
394
+ generateServices: answers.generateServices,
395
+ moduleType
362
396
  });
363
- const configPath = path5.join(cwd, `strapi.config.${configExtension}`);
364
- await fs4.writeFile(configPath, configContent, "utf-8");
365
- const envPath = path5.join(cwd, ".env");
397
+ const configPath = path6.join(cwd, `strapi.config.${configExtension}`);
398
+ await fs5.writeFile(configPath, configContent, "utf-8");
399
+ const envPath = path6.join(cwd, ".env");
366
400
  await appendToEnvFile(envPath, {
367
401
  STRAPI_URL: answers.strapiUrl,
368
402
  STRAPI_TOKEN: answers.strapiToken
369
403
  });
370
- const outputPath = path5.join(cwd, answers.outputDir);
371
- await fs4.mkdir(outputPath, { recursive: true });
404
+ const outputPath = path6.join(cwd, answers.outputDir);
405
+ await fs5.mkdir(outputPath, { recursive: true });
372
406
  s.stop("Configuration files created");
373
407
  const installDeps = await p.confirm({
374
408
  message: "Install required dependencies (strapi2front, strapi-sdk-js)?",
@@ -428,6 +462,7 @@ async function initCommand(_options) {
428
462
  }
429
463
  function generateConfigFile(answers) {
430
464
  const isTypeScript = answers.outputFormat === "typescript";
465
+ const useESM = answers.moduleType === "esm";
431
466
  if (isTypeScript) {
432
467
  return `import { defineConfig } from "strapi2front";
433
468
 
@@ -461,6 +496,44 @@ export default defineConfig({
461
496
  // Strapi version
462
497
  strapiVersion: "${answers.strapiVersion}",
463
498
  });
499
+ `;
500
+ }
501
+ if (useESM) {
502
+ return `// @ts-check
503
+ import { defineConfig } from "strapi2front";
504
+
505
+ export default defineConfig({
506
+ // Strapi connection
507
+ url: process.env.STRAPI_URL || "${answers.strapiUrl}",
508
+ token: process.env.STRAPI_TOKEN,
509
+
510
+ // API prefix (default: "/api")
511
+ apiPrefix: "${answers.apiPrefix}",
512
+
513
+ // Output format: "typescript" (.ts) or "jsdoc" (.js with JSDoc)
514
+ outputFormat: "jsdoc",
515
+
516
+ // Module type: auto-detected as ESM
517
+ moduleType: "esm",
518
+
519
+ // Output configuration
520
+ output: {
521
+ path: "${answers.outputDir}",
522
+ types: "types",
523
+ services: "services",
524
+ structure: 'by-feature' // or 'by-layer'
525
+ },
526
+
527
+ // Features to generate
528
+ features: {
529
+ types: true,
530
+ services: ${answers.generateServices},
531
+ actions: false, // Actions require TypeScript
532
+ },
533
+
534
+ // Strapi version
535
+ strapiVersion: "${answers.strapiVersion}",
536
+ });
464
537
  `;
465
538
  }
466
539
  return `// @ts-check
@@ -500,7 +573,7 @@ module.exports = defineConfig({
500
573
  async function appendToEnvFile(envPath, variables) {
501
574
  let content = "";
502
575
  try {
503
- content = await fs4.readFile(envPath, "utf-8");
576
+ content = await fs5.readFile(envPath, "utf-8");
504
577
  } catch {
505
578
  }
506
579
  const lines = content.split("\n");
@@ -516,7 +589,7 @@ async function appendToEnvFile(envPath, variables) {
516
589
  if (newLines.length > 0) {
517
590
  const separator = content.endsWith("\n") || content === "" ? "" : "\n";
518
591
  const newContent = content + separator + newLines.join("\n") + "\n";
519
- await fs4.writeFile(envPath, newContent, "utf-8");
592
+ await fs5.writeFile(envPath, newContent, "utf-8");
520
593
  }
521
594
  }
522
595
  var BLOCKS_RENDERER_PACKAGE = "@strapi/blocks-react-renderer";
@@ -542,9 +615,9 @@ function schemaHasBlocks(schema) {
542
615
  }
543
616
  function isPackageInstalled(packageName, cwd) {
544
617
  try {
545
- const packageJsonPath = path5.join(cwd, "package.json");
546
- if (!fs5.existsSync(packageJsonPath)) return false;
547
- const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
618
+ const packageJsonPath = path6.join(cwd, "package.json");
619
+ if (!fs6.existsSync(packageJsonPath)) return false;
620
+ const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
548
621
  const deps = {
549
622
  ...packageJson.dependencies,
550
623
  ...packageJson.devDependencies
@@ -555,9 +628,9 @@ function isPackageInstalled(packageName, cwd) {
555
628
  }
556
629
  }
557
630
  function detectPackageManager2(cwd) {
558
- if (fs5.existsSync(path5.join(cwd, "bun.lockb"))) return "bun";
559
- if (fs5.existsSync(path5.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
560
- if (fs5.existsSync(path5.join(cwd, "yarn.lock"))) return "yarn";
631
+ if (fs6.existsSync(path6.join(cwd, "bun.lockb"))) return "bun";
632
+ if (fs6.existsSync(path6.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
633
+ if (fs6.existsSync(path6.join(cwd, "yarn.lock"))) return "yarn";
561
634
  return "npm";
562
635
  }
563
636
  function installPackage(packageName, cwd) {
@@ -575,22 +648,22 @@ function getOrphanedFolders(outputPath, currentStructure) {
575
648
  if (currentStructure === "by-feature") {
576
649
  const byLayerFolders = ["types", "services", "actions"];
577
650
  for (const folder of byLayerFolders) {
578
- const folderPath = path5.join(outputPath, folder);
579
- if (fs5.existsSync(folderPath)) {
651
+ const folderPath = path6.join(outputPath, folder);
652
+ if (fs6.existsSync(folderPath)) {
580
653
  orphanedFolders.push(folder);
581
654
  }
582
655
  }
583
- if (fs5.existsSync(path5.join(outputPath, "client.ts"))) {
656
+ if (fs6.existsSync(path6.join(outputPath, "client.ts"))) {
584
657
  orphanedFolders.push("client.ts");
585
658
  }
586
- if (fs5.existsSync(path5.join(outputPath, "locales.ts"))) {
659
+ if (fs6.existsSync(path6.join(outputPath, "locales.ts"))) {
587
660
  orphanedFolders.push("locales.ts");
588
661
  }
589
662
  } else {
590
663
  const byFeatureFolders = ["collections", "singles", "shared", "components"];
591
664
  for (const folder of byFeatureFolders) {
592
- const folderPath = path5.join(outputPath, folder);
593
- if (fs5.existsSync(folderPath)) {
665
+ const folderPath = path6.join(outputPath, folder);
666
+ if (fs6.existsSync(folderPath)) {
594
667
  orphanedFolders.push(folder);
595
668
  }
596
669
  }
@@ -599,13 +672,13 @@ function getOrphanedFolders(outputPath, currentStructure) {
599
672
  }
600
673
  function cleanOrphanedFiles(outputPath, orphanedItems) {
601
674
  for (const item of orphanedItems) {
602
- const itemPath = path5.join(outputPath, item);
603
- if (fs5.existsSync(itemPath)) {
604
- const stat = fs5.statSync(itemPath);
675
+ const itemPath = path6.join(outputPath, item);
676
+ if (fs6.existsSync(itemPath)) {
677
+ const stat = fs6.statSync(itemPath);
605
678
  if (stat.isDirectory()) {
606
- fs5.rmSync(itemPath, { recursive: true, force: true });
679
+ fs6.rmSync(itemPath, { recursive: true, force: true });
607
680
  } else {
608
- fs5.unlinkSync(itemPath);
681
+ fs6.unlinkSync(itemPath);
609
682
  }
610
683
  }
611
684
  }
@@ -672,12 +745,12 @@ async function syncCommand(options) {
672
745
  p.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
673
746
  }
674
747
  }
675
- const outputPath = path5.join(cwd, config.output.path);
748
+ const outputPath = path6.join(cwd, config.output.path);
676
749
  const generatedFiles = [];
677
750
  const generateAll = !options.typesOnly && !options.servicesOnly && !options.actionsOnly;
678
751
  const isByFeature = config.output.structure === "by-feature";
679
752
  const currentStructure = isByFeature ? "by-feature" : "by-layer";
680
- if (fs5.existsSync(outputPath)) {
753
+ if (fs6.existsSync(outputPath)) {
681
754
  const orphanedFolders = getOrphanedFolders(outputPath, currentStructure);
682
755
  if (orphanedFolders.length > 0) {
683
756
  const otherStructure = isByFeature ? "by-layer" : "by-feature";
@@ -707,6 +780,17 @@ async function syncCommand(options) {
707
780
  }
708
781
  }
709
782
  const outputFormat = config.outputFormat || "typescript";
783
+ let moduleType = "commonjs";
784
+ if (outputFormat === "jsdoc") {
785
+ if (config.moduleType) {
786
+ moduleType = config.moduleType;
787
+ p.log.info(`Module type: ${pc4.cyan(moduleType)} (from config)`);
788
+ } else {
789
+ const detected = await detectModuleType(cwd);
790
+ moduleType = detected.type;
791
+ p.log.info(`Module type: ${pc4.cyan(moduleType)} (${detected.reason})`);
792
+ }
793
+ }
710
794
  if (isByFeature) {
711
795
  s.start(`Generating files (by-feature, ${outputFormat})...`);
712
796
  const files = await generateByFeature(schema, rawSchema.locales, {
@@ -719,7 +803,8 @@ async function syncCommand(options) {
719
803
  blocksRendererInstalled,
720
804
  strapiVersion: config.strapiVersion,
721
805
  apiPrefix: config.apiPrefix,
722
- outputFormat
806
+ outputFormat,
807
+ moduleType
723
808
  });
724
809
  generatedFiles.push(...files);
725
810
  s.stop(`Generated ${files.length} files`);
@@ -727,7 +812,7 @@ async function syncCommand(options) {
727
812
  if (generateAll || options.typesOnly) {
728
813
  if (config.features.types) {
729
814
  s.start(`Generating types (${outputFormat})...`);
730
- const typesPath = path5.join(outputPath, config.output.types);
815
+ const typesPath = path6.join(outputPath, config.output.types);
731
816
  const files = await generateTypes(schema, {
732
817
  outputDir: typesPath,
733
818
  blocksRendererInstalled,
@@ -757,8 +842,8 @@ async function syncCommand(options) {
757
842
  if (generateAll || options.servicesOnly) {
758
843
  if (config.features.services) {
759
844
  s.start(`Generating services (${outputFormat})...`);
760
- const servicesPath = path5.join(outputPath, config.output.services);
761
- const typesImportPath = path5.relative(servicesPath, path5.join(outputPath, config.output.types)).replace(/\\/g, "/") || ".";
845
+ const servicesPath = path6.join(outputPath, config.output.services);
846
+ const typesImportPath = path6.relative(servicesPath, path6.join(outputPath, config.output.types)).replace(/\\/g, "/") || ".";
762
847
  const files = await generateServices(schema, {
763
848
  outputDir: servicesPath,
764
849
  typesImportPath: typesImportPath.startsWith(".") ? typesImportPath : "./" + typesImportPath,
@@ -772,9 +857,9 @@ async function syncCommand(options) {
772
857
  if ((generateAll || options.actionsOnly) && outputFormat === "typescript") {
773
858
  if (config.features.actions) {
774
859
  s.start("Generating Astro actions...");
775
- const actionsPath = path5.join(outputPath, config.output.actions);
776
- const servicesPath = path5.join(outputPath, config.output.services);
777
- const servicesImportPath = path5.relative(actionsPath, servicesPath).replace(/\\/g, "/") || ".";
860
+ const actionsPath = path6.join(outputPath, config.output.actions);
861
+ const servicesPath = path6.join(outputPath, config.output.services);
862
+ const servicesImportPath = path6.relative(actionsPath, servicesPath).replace(/\\/g, "/") || ".";
778
863
  const files = await generateActions(schema, {
779
864
  outputDir: actionsPath,
780
865
  servicesImportPath: servicesImportPath.startsWith(".") ? servicesImportPath : "./" + servicesImportPath,
@@ -790,7 +875,7 @@ async function syncCommand(options) {
790
875
  `Generated ${generatedFiles.length} files in ${pc4.cyan(config.output.path)}`,
791
876
  "",
792
877
  "Files generated:",
793
- ...generatedFiles.slice(0, 10).map((f) => ` ${pc4.dim(path5.relative(cwd, f))}`),
878
+ ...generatedFiles.slice(0, 10).map((f) => ` ${pc4.dim(path6.relative(cwd, f))}`),
794
879
  generatedFiles.length > 10 ? ` ${pc4.dim(`... and ${generatedFiles.length - 10} more`)}` : ""
795
880
  ].filter(Boolean).join("\n"),
796
881
  "Sync complete!"