swallowkit 1.0.0-beta.21 → 1.0.0-beta.23

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.
Files changed (36) hide show
  1. package/README.ja.md +4 -4
  2. package/README.md +4 -4
  3. package/dist/cli/commands/dev.d.ts +11 -0
  4. package/dist/cli/commands/dev.d.ts.map +1 -1
  5. package/dist/cli/commands/dev.js +80 -7
  6. package/dist/cli/commands/dev.js.map +1 -1
  7. package/dist/cli/commands/init.d.ts.map +1 -1
  8. package/dist/cli/commands/init.js +17 -18
  9. package/dist/cli/commands/init.js.map +1 -1
  10. package/dist/cli/commands/scaffold.d.ts +0 -3
  11. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  12. package/dist/cli/commands/scaffold.js +3 -172
  13. package/dist/cli/commands/scaffold.js.map +1 -1
  14. package/dist/cli/index.d.ts.map +1 -1
  15. package/dist/cli/index.js +37 -1
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/core/project/validation.js +2 -2
  18. package/dist/core/project/validation.js.map +1 -1
  19. package/dist/core/scaffold/model-parser.d.ts.map +1 -1
  20. package/dist/core/scaffold/model-parser.js +5 -6
  21. package/dist/core/scaffold/model-parser.js.map +1 -1
  22. package/dist/core/scaffold/native-schema-generator.d.ts +13 -0
  23. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -0
  24. package/dist/core/scaffold/native-schema-generator.js +667 -0
  25. package/dist/core/scaffold/native-schema-generator.js.map +1 -0
  26. package/package.json +1 -1
  27. package/src/__tests__/dev.test.ts +53 -1
  28. package/src/__tests__/model-parser.test.ts +44 -64
  29. package/src/__tests__/scaffold.test.ts +54 -26
  30. package/src/cli/commands/dev.ts +101 -8
  31. package/src/cli/commands/init.ts +26 -19
  32. package/src/cli/commands/scaffold.ts +3 -213
  33. package/src/cli/index.ts +4 -1
  34. package/src/core/project/validation.ts +2 -2
  35. package/src/core/scaffold/model-parser.ts +7 -7
  36. package/src/core/scaffold/native-schema-generator.ts +769 -0
@@ -5,7 +5,7 @@
5
5
 
6
6
  import * as fs from "fs";
7
7
  import * as path from "path";
8
- import { spawn, spawnSync } from "child_process";
8
+ import { spawnSync } from "child_process";
9
9
  import { getBackendLanguage, getConnectorDefinition, getAuthConfig, ensureSwallowKitProject } from "../../core/config";
10
10
  import { ModelInfo, parseModelFile, toKebabCase, toPascalCase, toCamelCase } from "../../core/scaffold/model-parser";
11
11
  import {
@@ -22,7 +22,6 @@ import {
22
22
  generateApiConnectorFunctionPython,
23
23
  } from "../../core/scaffold/connector-functions-generator";
24
24
  import { generateCompactBFFRoutes, generateBFFCallFunction, generateConnectorBFFRoutes } from "../../core/scaffold/nextjs-generator";
25
- import { generateOpenApiDocument } from "../../core/scaffold/openapi-generator";
26
25
  import {
27
26
  generateListPage,
28
27
  generateDetailPage,
@@ -31,6 +30,7 @@ import {
31
30
  generateEditPage,
32
31
  UIAuthOptions,
33
32
  } from "../../core/scaffold/ui-generator";
33
+ import { generateLanguageSchemaArtifacts } from "../../core/scaffold/native-schema-generator";
34
34
  import { detectFromProject, getCommands } from "../../utils/package-manager";
35
35
  import {
36
36
  BackendLanguage,
@@ -171,7 +171,7 @@ export async function scaffoldCommand(options: ScaffoldOptions) {
171
171
  console.log(" 3. Navigate to the model from the homepage menu");
172
172
  }
173
173
  if (backendLanguage !== "typescript") {
174
- console.log(` ${options.apiOnly ? "2" : "4"}. Review generated OpenAPI assets in ${functionsDir}/openapi/ and ${functionsDir}/generated/`);
174
+ console.log(` ${options.apiOnly ? "2" : "4"}. Review generated OpenAPI export and native schema assets in ${functionsDir}/openapi/ and ${functionsDir}/generated/`);
175
175
  }
176
176
  console.log(
177
177
  ` ${options.apiOnly ? (backendLanguage === "typescript" ? "2" : "3") : (backendLanguage === "typescript" ? "4" : "5")}. Ensure BACKEND_FUNCTIONS_BASE_URL is set in your .env.local file`
@@ -636,216 +636,6 @@ function describeFunctionsOutputPath(functionsDir: string, backendLanguage: Back
636
636
  return `${functionsDir}/blueprints/`;
637
637
  }
638
638
 
639
- async function generateLanguageSchemaArtifacts(
640
- models: ModelInfo[],
641
- rootModel: ModelInfo,
642
- functionsDir: string,
643
- backendLanguage: Exclude<BackendLanguage, "typescript">
644
- ): Promise<void> {
645
- console.log("\n🧬 Generating OpenAPI-backed schema artifacts...");
646
-
647
- const openApiDir = path.join(process.cwd(), functionsDir, "openapi");
648
- fs.mkdirSync(openApiDir, { recursive: true });
649
-
650
- const specPath = path.join(openApiDir, `${toKebabCase(rootModel.name)}.openapi.json`);
651
- fs.writeFileSync(specPath, generateOpenApiDocument(models, rootModel), "utf-8");
652
- console.log(`✅ Created: ${specPath}`);
653
-
654
- const outputDir = path.join(
655
- process.cwd(),
656
- functionsDir,
657
- "generated",
658
- backendLanguage === "csharp" ? "csharp-models" : "python-models"
659
- );
660
-
661
- fs.mkdirSync(outputDir, { recursive: true });
662
- await runOpenApiGenerator(specPath, outputDir, backendLanguage);
663
- if (backendLanguage === "csharp") {
664
- pruneGeneratedCSharpArtifacts(outputDir);
665
- }
666
- console.log(`✅ Generated ${backendLanguage} schema assets: ${outputDir}`);
667
- }
668
-
669
- /**
670
- * OpenAPI Generator の実行前に Java バージョンを確認する。
671
- * Java 11 未満の場合は明確なエラーメッセージを表示して処理を中断する。
672
- */
673
- function checkJavaVersion(): void {
674
- try {
675
- const result = spawnSync("java", ["-version"], { encoding: "utf8" });
676
- // java -version は stderr に出力する
677
- const versionOutput = (result.stderr || "") + (result.stdout || "");
678
- const versionMatch = versionOutput.match(/version "(\d+)(?:\.(\d+))?/);
679
- if (!versionMatch) return;
680
-
681
- const major = parseInt(versionMatch[1]);
682
- // Java 8 以前は "1.8" 形式、Java 9 以降は "17" 形式
683
- const effectiveMajor = major === 1 ? parseInt(versionMatch[2] ?? "0") : major;
684
-
685
- if (effectiveMajor < 11) {
686
- const versionStr = versionOutput.match(/version "([^"]+)"/)?.[1] ?? "unknown";
687
- console.error(`\n❌ OpenAPI Generator requires Java 11 or later.`);
688
- console.error(` Detected: Java ${versionStr}`);
689
- if (process.env.JAVA_HOME) {
690
- console.error(` Current JAVA_HOME: ${process.env.JAVA_HOME}`);
691
- }
692
- console.error(` Please set JAVA_HOME to a Java 11+ installation and retry.`);
693
- console.error(` Example (Windows): $env:JAVA_HOME = "C:\\path\\to\\jdk-17"`);
694
- process.exit(1);
695
- }
696
- } catch {
697
- // java コマンドが見つからない場合は OpenAPI Generator 自身がエラーを出す
698
- }
699
- }
700
-
701
- async function runOpenApiGenerator(
702
- specPath: string,
703
- outputDir: string,
704
- backendLanguage: Exclude<BackendLanguage, "typescript">
705
- ): Promise<void> {
706
- checkJavaVersion();
707
- const pm = detectFromProject();
708
- const command = pm === "pnpm" ? "pnpm" : "npx";
709
- const args = pm === "pnpm"
710
- ? ["exec", "openapi-generator-cli", ...getOpenApiGeneratorArgs(specPath, outputDir, backendLanguage)]
711
- : ["openapi-generator-cli", ...getOpenApiGeneratorArgs(specPath, outputDir, backendLanguage)];
712
-
713
- await new Promise<void>((resolve, reject) => {
714
- const child = spawn(command, args, {
715
- cwd: process.cwd(),
716
- shell: true,
717
- stdio: getMachineAwareStdio(),
718
- });
719
-
720
- child.on("close", (code) => {
721
- if (code === 0) {
722
- resolve();
723
- return;
724
- }
725
-
726
- reject(new Error(`OpenAPI generator exited with code ${code}`));
727
- });
728
-
729
- child.on("error", reject);
730
- });
731
- }
732
-
733
- export function getOpenApiGeneratorArgs(
734
- specPath: string,
735
- outputDir: string,
736
- backendLanguage: Exclude<BackendLanguage, "typescript">
737
- ): string[] {
738
- const globalProperty = backendLanguage === "csharp"
739
- ? "models,apis=false,modelDocs=false,modelTests=false"
740
- : "models,apis=false,supportingFiles=false,modelDocs=false,modelTests=false";
741
-
742
- const baseArgs = [
743
- "generate",
744
- "-i",
745
- specPath,
746
- "-o",
747
- outputDir,
748
- "--global-property",
749
- globalProperty,
750
- ];
751
-
752
- if (backendLanguage === "csharp") {
753
- return [
754
- ...baseArgs,
755
- "-g",
756
- "csharp",
757
- "--additional-properties",
758
- "packageName=SwallowKitBackendModels,targetFramework=net8.0,nullableReferenceTypes=true",
759
- ];
760
- }
761
-
762
- return [
763
- ...baseArgs,
764
- "-g",
765
- "python",
766
- "--additional-properties",
767
- "packageName=backend_models,projectName=backend-models",
768
- ];
769
- }
770
-
771
- export function getCSharpSchemaArtifactPruneTargets(outputDir: string): string[] {
772
- return [
773
- path.join(outputDir, "src", "SwallowKitBackendModels.Test"),
774
- path.join(outputDir, "src", "SwallowKitBackendModels", "Api"),
775
- path.join(outputDir, "src", "SwallowKitBackendModels", "Extensions"),
776
- ];
777
- }
778
-
779
- function pruneGeneratedCSharpArtifacts(outputDir: string): void {
780
- for (const target of getCSharpSchemaArtifactPruneTargets(outputDir)) {
781
- if (fs.existsSync(target)) {
782
- fs.rmSync(target, { recursive: true, force: true });
783
- }
784
- }
785
-
786
- const clientDir = path.join(outputDir, "src", "SwallowKitBackendModels", "Client");
787
- if (!fs.existsSync(clientDir)) {
788
- // --global-property models ではClient/が生成されないため、
789
- // モデルが依存する最小限の Option<T> を自前で作成する
790
- fs.mkdirSync(clientDir, { recursive: true });
791
- fs.writeFileSync(
792
- path.join(clientDir, "Option.cs"),
793
- generateMinimalOptionCs(),
794
- "utf-8"
795
- );
796
- return;
797
- }
798
-
799
- for (const entry of fs.readdirSync(clientDir, { withFileTypes: true })) {
800
- if (!entry.isFile() || entry.name === "Option.cs") {
801
- continue;
802
- }
803
-
804
- fs.rmSync(path.join(clientDir, entry.name), { force: true });
805
- }
806
- }
807
-
808
- /**
809
- * OpenAPI Generator の csharp テンプレートが生成するモデルは Option<T> に依存するが、
810
- * supportingFiles を除外しているため Client/Option.cs が生成されない。
811
- * Polly 等の不要な依存を避けつつモデルをコンパイル可能にするため、最小限の Option<T> を提供する。
812
- */
813
- function generateMinimalOptionCs(): string {
814
- return `// <auto-generated>
815
- // Minimal Option<T> for OpenAPI Generator model compatibility.
816
- // Full client supporting files are excluded to avoid Polly version conflicts.
817
- // </auto-generated>
818
-
819
- #nullable enable
820
-
821
- namespace SwallowKitBackendModels.Client
822
- {
823
- /// <summary>
824
- /// A wrapper for nullable/optional properties generated by OpenAPI Generator.
825
- /// Tracks whether a value has been explicitly set (distinguishing null from absent).
826
- /// </summary>
827
- public readonly struct Option<TValue>
828
- {
829
- /// <summary>Whether this option has been explicitly set.</summary>
830
- public bool IsSet { get; }
831
-
832
- /// <summary>The contained value (may be default if not set).</summary>
833
- public TValue Value { get; }
834
-
835
- /// <summary>Create an Option with an explicit value.</summary>
836
- public Option(TValue value)
837
- {
838
- IsSet = true;
839
- Value = value;
840
- }
841
-
842
- /// <summary>Implicit conversion from Option to its inner value.</summary>
843
- public static implicit operator TValue(Option<TValue> option) => option.Value;
844
- }
845
- }
846
- `;
847
- }
848
-
849
639
  function updatePythonFunctionRegistrations(functionAppPath: string, registration: string): void {
850
640
  if (!fs.existsSync(functionAppPath)) {
851
641
  throw new Error(`Python Functions entrypoint not found: ${functionAppPath}`);
package/src/cli/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { execSync } from "child_process";
4
+ import { readFileSync } from "fs";
5
+ import * as path from "path";
4
6
  import { Command } from "commander";
5
7
  import { initCommand, devCommand, devSeedsCommand, scaffoldCommand, createModelCommand } from "./commands";
6
8
  import { provisionCommand } from "./commands/provision";
@@ -8,7 +10,8 @@ import { addConnectorCommand } from "./commands/add-connector";
8
10
  import { addAuthCommand } from "./commands/add-auth";
9
11
  import { isMachineCommand, runMachineCli } from "../machine";
10
12
 
11
- export const CLI_VERSION = require("../../package.json").version as string;
13
+ const packageJsonPath = path.resolve(__dirname, "../../package.json");
14
+ export const CLI_VERSION = JSON.parse(readFileSync(packageJsonPath, "utf8")).version as string;
12
15
 
13
16
  const DEV_OPTION_ARITY = new Map<string, 0 | 1>([
14
17
  ["-p", 1],
@@ -102,9 +102,9 @@ function validateGeneratedArtifacts(manifest: ProjectManifest, violations: Proje
102
102
  pushViolation(violations, {
103
103
  code: "missing-openapi-artifacts",
104
104
  severity: "warning",
105
- message: `No OpenAPI schema artifacts were found for ${manifest.backendLanguage} backend generation.`,
105
+ message: `No OpenAPI export or native schema artifacts were found for ${manifest.backendLanguage} backend generation.`,
106
106
  location: { path: "functions/openapi" },
107
- suggestedFix: "Run scaffold to regenerate the OpenAPI-backed backend schema artifacts.",
107
+ suggestedFix: "Run scaffold to regenerate the OpenAPI export and native backend schema artifacts.",
108
108
  });
109
109
  }
110
110
  }
@@ -3,11 +3,10 @@
3
3
  */
4
4
 
5
5
  import * as fs from "fs";
6
- import { execSync } from "child_process";
6
+ import { execFileSync } from "child_process";
7
7
  import * as path from "path";
8
8
 
9
9
  import { ModelConnectorConfig, ModelAuthPolicy } from "../../types";
10
- import { detectFromProject, getCommands } from "../../utils/package-manager";
11
10
 
12
11
  export interface ModelInfo {
13
12
  name: string; // モデル名(例: "Todo")
@@ -377,6 +376,10 @@ function inlineLocalDeps(
377
376
  return [...transitiveParts, content.trim()].filter(Boolean).join('\n\n');
378
377
  }
379
378
 
379
+ function resolveBundledTsxCliPath(): string {
380
+ return require.resolve("tsx/cli");
381
+ }
382
+
380
383
  /**
381
384
  * Zodスキーマから動的にフィールド情報を抽出
382
385
  */
@@ -543,11 +546,8 @@ if (isObject) {
543
546
  fs.writeFileSync(tempScript, scriptCode, 'utf8');
544
547
 
545
548
  try {
546
- // プロジェクトルートでtsxを実行 (npm/pnpm 両対応)
547
- // Detect package manager from project lockfile
548
- const pm = detectFromProject(projectRoot);
549
- const pmCmd = getCommands(pm);
550
- const result = execSync(`${pmCmd.exec} tsx "${tempScript}"`, {
549
+ const tsxCliPath = resolveBundledTsxCliPath();
550
+ const result = execFileSync(process.execPath, [tsxCliPath, tempScript], {
551
551
  encoding: 'utf8',
552
552
  cwd: projectRoot,
553
553
  });