swallowkit 1.0.0-beta.55 → 1.0.0-beta.57
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/cli/commands/add-auth.d.ts.map +1 -1
- package/dist/cli/commands/add-auth.js +154 -157
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +178 -25
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +7 -2
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +113 -123
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +127 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +8 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/operations/auth-operations.d.ts +57 -0
- package/dist/core/operations/auth-operations.d.ts.map +1 -0
- package/dist/core/operations/auth-operations.js +269 -0
- package/dist/core/operations/auth-operations.js.map +1 -0
- package/dist/core/operations/create-model.d.ts.map +1 -1
- package/dist/core/operations/create-model.js +23 -13
- package/dist/core/operations/create-model.js.map +1 -1
- package/dist/core/operations/file-session.d.ts +56 -0
- package/dist/core/operations/file-session.d.ts.map +1 -0
- package/dist/core/operations/file-session.js +203 -0
- package/dist/core/operations/file-session.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +52 -0
- package/dist/core/operations/provision-operations.d.ts.map +1 -0
- package/dist/core/operations/provision-operations.js +211 -0
- package/dist/core/operations/provision-operations.js.map +1 -0
- package/dist/core/operations/runtime.d.ts +5 -0
- package/dist/core/operations/runtime.d.ts.map +1 -1
- package/dist/core/operations/runtime.js +23 -0
- package/dist/core/operations/runtime.js.map +1 -1
- package/dist/core/operations/scaffold-apply.d.ts +21 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
- package/dist/core/operations/scaffold-apply.js +57 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
- package/dist/core/operations/scaffold-machine.js +1 -13
- package/dist/core/operations/scaffold-machine.js.map +1 -1
- package/dist/core/operations/scaffold-plan.d.ts +43 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
- package/dist/core/operations/scaffold-plan.js +187 -0
- package/dist/core/operations/scaffold-plan.js.map +1 -0
- package/dist/core/project/artifacts.d.ts +58 -0
- package/dist/core/project/artifacts.d.ts.map +1 -0
- package/dist/core/project/artifacts.js +179 -0
- package/dist/core/project/artifacts.js.map +1 -0
- package/dist/core/project/boundaries.d.ts +50 -0
- package/dist/core/project/boundaries.d.ts.map +1 -0
- package/dist/core/project/boundaries.js +117 -0
- package/dist/core/project/boundaries.js.map +1 -0
- package/dist/core/project/drift.d.ts +29 -0
- package/dist/core/project/drift.d.ts.map +1 -0
- package/dist/core/project/drift.js +188 -0
- package/dist/core/project/drift.js.map +1 -0
- package/dist/core/project/infra.d.ts +49 -0
- package/dist/core/project/infra.d.ts.map +1 -0
- package/dist/core/project/infra.js +167 -0
- package/dist/core/project/infra.js.map +1 -0
- package/dist/core/project/state.d.ts +15 -0
- package/dist/core/project/state.d.ts.map +1 -0
- package/dist/core/project/state.js +106 -0
- package/dist/core/project/state.js.map +1 -0
- package/dist/core/project/workflows.d.ts +43 -0
- package/dist/core/project/workflows.d.ts.map +1 -0
- package/dist/core/project/workflows.js +255 -0
- package/dist/core/project/workflows.js.map +1 -0
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +24 -27
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/functions-generator.js +9 -9
- package/dist/core/scaffold/native-schema-generator.d.ts +7 -1
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
- package/dist/core/scaffold/native-schema-generator.js +104 -47
- package/dist/core/scaffold/native-schema-generator.js.map +1 -1
- package/dist/core/scaffold/nextjs-generator.js +6 -6
- package/dist/core/scaffold/ui-generator.js +19 -19
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +62 -0
- package/dist/core/verify/index.d.ts.map +1 -0
- package/dist/core/verify/index.js +343 -0
- package/dist/core/verify/index.js.map +1 -0
- package/dist/machine/contracts.d.ts +8 -0
- package/dist/machine/contracts.d.ts.map +1 -1
- package/dist/machine/errors.d.ts +4 -1
- package/dist/machine/errors.d.ts.map +1 -1
- package/dist/machine/errors.js +9 -1
- package/dist/machine/errors.js.map +1 -1
- package/dist/machine/index.d.ts.map +1 -1
- package/dist/machine/index.js +350 -16
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +202 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +17 -17
- package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +6 -6
- package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +11 -11
- package/src/__tests__/agent-loop-phase34.test.ts +449 -0
- package/src/__tests__/file-session.test.ts +98 -0
- package/src/__tests__/init.test.ts +50 -0
- package/src/__tests__/mcp.test.ts +113 -5
- package/src/__tests__/plan-apply.test.ts +461 -0
- package/src/__tests__/scaffold.test.ts +2 -2
- package/src/cli/commands/add-auth.ts +164 -164
- package/src/cli/commands/init.ts +186 -24
- package/src/cli/commands/scaffold.ts +136 -130
- package/src/cli/index.ts +148 -2
- package/src/core/config.ts +5 -4
- package/src/core/operations/auth-operations.ts +353 -0
- package/src/core/operations/create-model.ts +25 -13
- package/src/core/operations/file-session.ts +222 -0
- package/src/core/operations/provision-operations.ts +297 -0
- package/src/core/operations/runtime.ts +23 -0
- package/src/core/operations/scaffold-apply.ts +106 -0
- package/src/core/operations/scaffold-machine.ts +2 -16
- package/src/core/operations/scaffold-plan.ts +215 -0
- package/src/core/project/artifacts.ts +205 -0
- package/src/core/project/boundaries.ts +170 -0
- package/src/core/project/drift.ts +202 -0
- package/src/core/project/infra.ts +196 -0
- package/src/core/project/state.ts +77 -0
- package/src/core/project/workflows.ts +249 -0
- package/src/core/scaffold/auth-generator.ts +24 -27
- package/src/core/scaffold/functions-generator.ts +9 -9
- package/src/core/scaffold/native-schema-generator.ts +152 -70
- package/src/core/scaffold/nextjs-generator.ts +6 -6
- package/src/core/scaffold/ui-generator.ts +19 -19
- package/src/core/verify/index.ts +392 -0
- package/src/machine/contracts.ts +16 -0
- package/src/machine/errors.ts +12 -1
- package/src/machine/index.ts +444 -15
- package/src/mcp/index.ts +198 -2
- package/src/types/index.ts +17 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
2
3
|
import * as path from "path";
|
|
3
4
|
import { spawn, spawnSync } from "child_process";
|
|
4
5
|
import { BackendLanguage } from "../../types";
|
|
6
|
+
import { FileOperationSession } from "../operations/file-session";
|
|
5
7
|
import { ModelInfo, toKebabCase } from "./model-parser";
|
|
6
8
|
import { generateOpenApiDocument } from "./openapi-generator";
|
|
7
9
|
import {
|
|
@@ -621,23 +623,47 @@ function mergePythonInitSource(existingSource: string | undefined, generatedSour
|
|
|
621
623
|
return `${normalizedExisting}${missingLines.join("\n")}\n`;
|
|
622
624
|
}
|
|
623
625
|
|
|
624
|
-
function writeMergedPythonInitFile(
|
|
625
|
-
|
|
626
|
-
|
|
626
|
+
function writeMergedPythonInitFile(
|
|
627
|
+
filePath: string,
|
|
628
|
+
generatedSource: string,
|
|
629
|
+
session: FileOperationSession,
|
|
630
|
+
sourceModel: string
|
|
631
|
+
): void {
|
|
632
|
+
const existingSource = session.fileExists(filePath) ? session.readFile(filePath) : undefined;
|
|
633
|
+
session.writeFile(filePath, mergePythonInitSource(existingSource, generatedSource), {
|
|
634
|
+
ownership: "extension-point",
|
|
635
|
+
generator: "native-schema",
|
|
636
|
+
sourceModel,
|
|
637
|
+
});
|
|
627
638
|
}
|
|
628
639
|
|
|
629
|
-
function ensureCSharpCodegenProjectFiles(
|
|
640
|
+
function ensureCSharpCodegenProjectFiles(
|
|
641
|
+
functionsRoot: string,
|
|
642
|
+
session: FileOperationSession,
|
|
643
|
+
sourceModel: string
|
|
644
|
+
): void {
|
|
630
645
|
const toolManifestPath = path.join(functionsRoot, ".config", "dotnet-tools.json");
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
646
|
+
if (!session.fileExists(toolManifestPath)) {
|
|
647
|
+
session.writeFile(toolManifestPath, buildCSharpCodegenToolManifestSource(), {
|
|
648
|
+
ownership: "generated-once",
|
|
649
|
+
generator: "native-schema",
|
|
650
|
+
sourceModel,
|
|
651
|
+
});
|
|
634
652
|
}
|
|
635
653
|
}
|
|
636
654
|
|
|
637
|
-
function ensurePythonCodegenProjectFiles(
|
|
655
|
+
function ensurePythonCodegenProjectFiles(
|
|
656
|
+
functionsRoot: string,
|
|
657
|
+
session: FileOperationSession,
|
|
658
|
+
sourceModel: string
|
|
659
|
+
): string {
|
|
638
660
|
const requirementsPath = path.join(functionsRoot, "requirements.codegen.txt");
|
|
639
|
-
if (!
|
|
640
|
-
|
|
661
|
+
if (!session.fileExists(requirementsPath)) {
|
|
662
|
+
session.writeFile(requirementsPath, buildPythonCodegenRequirementsSource(), {
|
|
663
|
+
ownership: "generated-once",
|
|
664
|
+
generator: "native-schema",
|
|
665
|
+
sourceModel,
|
|
666
|
+
});
|
|
641
667
|
}
|
|
642
668
|
return requirementsPath;
|
|
643
669
|
}
|
|
@@ -676,8 +702,7 @@ async function ensureProjectLocalUvCommand(projectRoot: string): Promise<{ comma
|
|
|
676
702
|
return { command: localUvExecutable, env: uvEnv };
|
|
677
703
|
}
|
|
678
704
|
|
|
679
|
-
async function ensurePythonCodegenEnvironment(functionsRoot: string): Promise<string> {
|
|
680
|
-
const requirementsPath = ensurePythonCodegenProjectFiles(functionsRoot);
|
|
705
|
+
async function ensurePythonCodegenEnvironment(functionsRoot: string, requirementsPath: string): Promise<string> {
|
|
681
706
|
const projectRoot = getPythonProjectRoot(functionsRoot);
|
|
682
707
|
const { command: uvCommand, env: uvEnv } = await ensureProjectLocalUvCommand(projectRoot);
|
|
683
708
|
const venvDir = path.join(functionsRoot, ".codegen-venv");
|
|
@@ -711,79 +736,125 @@ async function ensurePythonCodegenEnvironment(functionsRoot: string): Promise<st
|
|
|
711
736
|
return venvPython;
|
|
712
737
|
}
|
|
713
738
|
|
|
714
|
-
|
|
739
|
+
/**
|
|
740
|
+
* 外部 codegen toolchain の事前検証。プロジェクトには一切書き込まず、
|
|
741
|
+
* OS 一時ディレクトリ上で NSwag / datamodel-code-generator を実行して失敗を早期検出する。
|
|
742
|
+
*/
|
|
743
|
+
export async function validateNativeSchemaToolchain(
|
|
715
744
|
models: ModelInfo[],
|
|
716
|
-
|
|
717
|
-
|
|
745
|
+
rootModel: ModelInfo,
|
|
746
|
+
backendLanguage: Exclude<BackendLanguage, "typescript">,
|
|
718
747
|
functionsRoot: string
|
|
719
748
|
): Promise<void> {
|
|
720
|
-
|
|
749
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "swallowkit-native-codegen-"));
|
|
750
|
+
try {
|
|
751
|
+
const specPath = path.join(tempDir, `${toKebabCase(rootModel.name)}.openapi.json`);
|
|
752
|
+
fs.writeFileSync(specPath, generateOpenApiDocument(models, rootModel), "utf-8");
|
|
753
|
+
|
|
754
|
+
if (backendLanguage === "csharp") {
|
|
755
|
+
if (!canRun("dotnet", ["--version"], tempDir)) {
|
|
756
|
+
throw new Error(
|
|
757
|
+
"The .NET SDK is required to generate C# backend schema assets.\n" +
|
|
758
|
+
"Install the .NET 8 SDK and retry."
|
|
759
|
+
);
|
|
760
|
+
}
|
|
721
761
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
762
|
+
// プロジェクトの tool manifest(バージョン固定)があればそれを尊重し、なければ一時 manifest で検証する
|
|
763
|
+
const projectManifestPath = path.join(functionsRoot, ".config", "dotnet-tools.json");
|
|
764
|
+
let toolCwd = functionsRoot;
|
|
765
|
+
if (!fs.existsSync(projectManifestPath)) {
|
|
766
|
+
fs.mkdirSync(path.join(tempDir, ".config"), { recursive: true });
|
|
767
|
+
fs.writeFileSync(path.join(tempDir, ".config", "dotnet-tools.json"), buildCSharpCodegenToolManifestSource(), "utf-8");
|
|
768
|
+
toolCwd = tempDir;
|
|
769
|
+
}
|
|
728
770
|
|
|
729
|
-
|
|
730
|
-
|
|
771
|
+
await runCommand("dotnet", ["tool", "restore"], toolCwd, "Failed to restore the NSwag dotnet tool.");
|
|
772
|
+
await runCommand(
|
|
773
|
+
"dotnet",
|
|
774
|
+
getCSharpNativeGeneratorArgs(specPath, path.join(tempDir, "Contracts.cs")),
|
|
775
|
+
toolCwd,
|
|
776
|
+
"NSwag failed to generate C# backend schema assets."
|
|
777
|
+
);
|
|
778
|
+
} else {
|
|
779
|
+
const projectRequirementsPath = path.join(functionsRoot, "requirements.codegen.txt");
|
|
780
|
+
let requirementsPath = projectRequirementsPath;
|
|
781
|
+
if (!fs.existsSync(projectRequirementsPath)) {
|
|
782
|
+
requirementsPath = path.join(tempDir, "requirements.codegen.txt");
|
|
783
|
+
fs.writeFileSync(requirementsPath, buildPythonCodegenRequirementsSource(), "utf-8");
|
|
784
|
+
}
|
|
731
785
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
786
|
+
// .codegen-venv は environment cache であり managed artifact ではない(既存挙動どおり functionsRoot 配下)
|
|
787
|
+
fs.mkdirSync(functionsRoot, { recursive: true });
|
|
788
|
+
const pythonExecutable = await ensurePythonCodegenEnvironment(functionsRoot, requirementsPath);
|
|
789
|
+
await runCommand(
|
|
790
|
+
pythonExecutable,
|
|
791
|
+
getPythonNativeGeneratorArgs(specPath, path.join(tempDir, "models.py")),
|
|
792
|
+
functionsRoot,
|
|
793
|
+
"datamodel-code-generator failed to generate Python backend schema assets."
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
} finally {
|
|
797
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
798
|
+
}
|
|
799
|
+
}
|
|
744
800
|
|
|
745
|
-
|
|
801
|
+
async function generateCSharpSchemaArtifacts(
|
|
802
|
+
models: ModelInfo[],
|
|
803
|
+
outputDir: string,
|
|
804
|
+
functionsRoot: string,
|
|
805
|
+
session: FileOperationSession,
|
|
806
|
+
sourceModel: string
|
|
807
|
+
): Promise<void> {
|
|
808
|
+
ensureCSharpCodegenProjectFiles(functionsRoot, session, sourceModel);
|
|
746
809
|
|
|
747
810
|
const optionPath = getCSharpSchemaOptionPath(outputDir);
|
|
748
|
-
|
|
749
|
-
|
|
811
|
+
session.writeFile(optionPath, generateLegacyCompatibleOptionSource(), {
|
|
812
|
+
ownership: "managed",
|
|
813
|
+
generator: "native-schema",
|
|
814
|
+
sourceModel,
|
|
815
|
+
});
|
|
750
816
|
|
|
751
817
|
for (const model of models) {
|
|
752
818
|
const modelPath = getCSharpSchemaModelPath(outputDir, model.name);
|
|
753
|
-
|
|
754
|
-
|
|
819
|
+
session.writeFile(modelPath, generateLegacyCompatibleCSharpModelSource(model), {
|
|
820
|
+
ownership: "managed",
|
|
821
|
+
generator: "native-schema",
|
|
822
|
+
sourceModel,
|
|
823
|
+
});
|
|
755
824
|
}
|
|
756
825
|
}
|
|
757
826
|
|
|
758
827
|
async function generatePythonSchemaArtifacts(
|
|
759
828
|
models: ModelInfo[],
|
|
760
|
-
specPath: string,
|
|
761
829
|
outputDir: string,
|
|
762
|
-
functionsRoot: string
|
|
830
|
+
functionsRoot: string,
|
|
831
|
+
session: FileOperationSession,
|
|
832
|
+
sourceModel: string
|
|
763
833
|
): Promise<void> {
|
|
764
|
-
|
|
765
|
-
const tempModelsPath = path.join(outputDir, ".native-temp", "models.py");
|
|
766
|
-
fs.mkdirSync(path.dirname(tempModelsPath), { recursive: true });
|
|
767
|
-
|
|
768
|
-
await runCommand(
|
|
769
|
-
pythonExecutable,
|
|
770
|
-
getPythonNativeGeneratorArgs(specPath, tempModelsPath),
|
|
771
|
-
functionsRoot,
|
|
772
|
-
"datamodel-code-generator failed to generate Python backend schema assets."
|
|
773
|
-
);
|
|
774
|
-
|
|
775
|
-
fs.rmSync(path.dirname(tempModelsPath), { recursive: true, force: true });
|
|
834
|
+
ensurePythonCodegenProjectFiles(functionsRoot, session, sourceModel);
|
|
776
835
|
|
|
777
836
|
const packageRoot = path.join(outputDir, "backend_models");
|
|
778
837
|
const modelsRoot = path.join(packageRoot, "models");
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
838
|
+
writeMergedPythonInitFile(
|
|
839
|
+
path.join(packageRoot, "__init__.py"),
|
|
840
|
+
buildGeneratedPythonPackageInitSource(models),
|
|
841
|
+
session,
|
|
842
|
+
sourceModel
|
|
843
|
+
);
|
|
844
|
+
writeMergedPythonInitFile(
|
|
845
|
+
path.join(modelsRoot, "__init__.py"),
|
|
846
|
+
buildGeneratedPythonModelsInitSource(models),
|
|
847
|
+
session,
|
|
848
|
+
sourceModel
|
|
849
|
+
);
|
|
782
850
|
|
|
783
851
|
for (const model of models) {
|
|
784
852
|
const modelPath = getPythonSchemaModelPath(outputDir, model.name);
|
|
785
|
-
|
|
786
|
-
|
|
853
|
+
session.writeFile(modelPath, generateLegacyCompatiblePythonModelSource(model), {
|
|
854
|
+
ownership: "managed",
|
|
855
|
+
generator: "native-schema",
|
|
856
|
+
sourceModel,
|
|
857
|
+
});
|
|
787
858
|
}
|
|
788
859
|
}
|
|
789
860
|
|
|
@@ -791,18 +862,27 @@ export async function generateLanguageSchemaArtifacts(
|
|
|
791
862
|
models: ModelInfo[],
|
|
792
863
|
rootModel: ModelInfo,
|
|
793
864
|
functionsDir: string,
|
|
794
|
-
backendLanguage: Exclude<BackendLanguage, "typescript"
|
|
865
|
+
backendLanguage: Exclude<BackendLanguage, "typescript">,
|
|
866
|
+
session: FileOperationSession = new FileOperationSession("commit")
|
|
795
867
|
): Promise<void> {
|
|
796
|
-
|
|
868
|
+
const planning = session.mode === "collect";
|
|
869
|
+
console.log(
|
|
870
|
+
planning
|
|
871
|
+
? "\n\ud83e\uddec Planning OpenAPI export and native schema assets..."
|
|
872
|
+
: "\n\ud83e\uddec Generating OpenAPI export and native schema assets..."
|
|
873
|
+
);
|
|
797
874
|
|
|
798
875
|
const projectRoot = process.cwd();
|
|
799
876
|
const functionsRoot = path.join(projectRoot, functionsDir);
|
|
800
877
|
const openApiDir = path.join(functionsRoot, "openapi");
|
|
801
|
-
fs.mkdirSync(openApiDir, { recursive: true });
|
|
802
878
|
|
|
803
879
|
const specPath = path.join(openApiDir, `${toKebabCase(rootModel.name)}.openapi.json`);
|
|
804
|
-
|
|
805
|
-
|
|
880
|
+
session.writeFile(specPath, generateOpenApiDocument(models, rootModel), {
|
|
881
|
+
ownership: "managed",
|
|
882
|
+
generator: "native-schema",
|
|
883
|
+
sourceModel: rootModel.name,
|
|
884
|
+
});
|
|
885
|
+
console.log(planning ? `\ud83d\udccb Will create: ${specPath}` : `\u2705 Created: ${specPath}`);
|
|
806
886
|
|
|
807
887
|
const outputDir = path.join(
|
|
808
888
|
functionsRoot,
|
|
@@ -810,13 +890,15 @@ export async function generateLanguageSchemaArtifacts(
|
|
|
810
890
|
backendLanguage === "csharp" ? "csharp-models" : "python-models"
|
|
811
891
|
);
|
|
812
892
|
|
|
813
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
814
|
-
|
|
815
893
|
if (backendLanguage === "csharp") {
|
|
816
|
-
await generateCSharpSchemaArtifacts(models,
|
|
894
|
+
await generateCSharpSchemaArtifacts(models, outputDir, functionsRoot, session, rootModel.name);
|
|
817
895
|
} else {
|
|
818
|
-
await generatePythonSchemaArtifacts(models,
|
|
896
|
+
await generatePythonSchemaArtifacts(models, outputDir, functionsRoot, session, rootModel.name);
|
|
819
897
|
}
|
|
820
898
|
|
|
821
|
-
console.log(
|
|
899
|
+
console.log(
|
|
900
|
+
planning
|
|
901
|
+
? `\ud83d\udccb Will generate ${backendLanguage} schema assets: ${outputDir}`
|
|
902
|
+
: `\u2705 Generated ${backendLanguage} schema assets: ${outputDir}`
|
|
903
|
+
);
|
|
822
904
|
}
|
|
@@ -10,7 +10,7 @@ import { ModelInfo, toCamelCase } from "./model-parser";
|
|
|
10
10
|
* BFF callFunction ヘルパー (lib/api/call-function.ts) のコードを生成
|
|
11
11
|
*/
|
|
12
12
|
export function generateBFFCallFunction(): string {
|
|
13
|
-
return `import {
|
|
13
|
+
return `import { NextResponse } from 'next/server';
|
|
14
14
|
import { z } from 'zod/v4';
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -43,13 +43,13 @@ function getFunctionsKeyHeaders(functionsBaseUrl: string): Record<string, string
|
|
|
43
43
|
throw new Error('BACKEND_FUNCTIONS_KEY is required for non-local Functions calls');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
interface CallFunctionConfig<TInput =
|
|
46
|
+
interface CallFunctionConfig<TInput = unknown, TOutput = unknown> {
|
|
47
47
|
/** HTTP メソッド */
|
|
48
48
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
49
49
|
/** Azure Functions のパス (例: '/api/todo', '/api/todo/123') */
|
|
50
50
|
path: string;
|
|
51
51
|
/** リクエストボディ (POST/PUT 用) */
|
|
52
|
-
body?:
|
|
52
|
+
body?: unknown;
|
|
53
53
|
/** 入力バリデーション用 Zod スキーマ (省略時はバリデーションなし) */
|
|
54
54
|
inputSchema?: z.ZodSchema<TInput>;
|
|
55
55
|
/** 出力バリデーション用 Zod スキーマ (省略時はそのまま返す) */
|
|
@@ -58,7 +58,7 @@ interface CallFunctionConfig<TInput = any, TOutput = any> {
|
|
|
58
58
|
successStatus?: number;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export async function callFunction<TInput =
|
|
61
|
+
export async function callFunction<TInput = unknown, TOutput = unknown>(
|
|
62
62
|
config: CallFunctionConfig<TInput, TOutput>
|
|
63
63
|
): Promise<NextResponse> {
|
|
64
64
|
const { method, path, body, inputSchema, responseSchema, successStatus = 200 } = config;
|
|
@@ -121,10 +121,10 @@ export async function callFunction<TInput = any, TOutput = any>(
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
return NextResponse.json(data, { status: successStatus });
|
|
124
|
-
} catch (error
|
|
124
|
+
} catch (error) {
|
|
125
125
|
console.error(\`[BFF] Error:\`, error);
|
|
126
126
|
return NextResponse.json(
|
|
127
|
-
{ error: error.message
|
|
127
|
+
{ error: error instanceof Error ? error.message : 'Internal server error' },
|
|
128
128
|
{ status: 500 }
|
|
129
129
|
);
|
|
130
130
|
}
|
|
@@ -71,7 +71,7 @@ export function generateListPage(model: ModelInfo, sharedPackageName: string, au
|
|
|
71
71
|
const refModelCamel = toCamelCase(refModel);
|
|
72
72
|
return ` fetch('/api/${refModelCamel}')
|
|
73
73
|
.then(res => res.json())
|
|
74
|
-
.then((data:
|
|
74
|
+
.then((data: Array<{ id: string; name?: string; title?: string }>) => {
|
|
75
75
|
const map: Record<string, string> = {};
|
|
76
76
|
data.forEach(item => {
|
|
77
77
|
// name または title フィールドを表示用文字列として使用
|
|
@@ -138,8 +138,8 @@ ${hasForeignKeys ? foreignKeyFetches : ''}
|
|
|
138
138
|
if (!res.ok) throw new Error('Failed to delete ${modelCamel}');
|
|
139
139
|
|
|
140
140
|
set${modelName}s(${modelCamel}s.filter((item) => item.id !== id));
|
|
141
|
-
} catch (err
|
|
142
|
-
alert(\`Error: \${err.message}\`);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
alert(\`Error: \${err instanceof Error ? err.message : String(err)}\`);
|
|
143
143
|
}
|
|
144
144
|
};
|
|
145
145
|
|
|
@@ -216,7 +216,7 @@ ${displayFields.map(f => {
|
|
|
216
216
|
const displayField = f.nestedDisplayField || 'name';
|
|
217
217
|
if (f.isArray) {
|
|
218
218
|
return ` <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
219
|
-
{Array.isArray(item.${f.name}) ? item.${f.name}.map((ref:
|
|
219
|
+
{Array.isArray(item.${f.name}) ? item.${f.name}.map((ref: unknown) => (ref as { ${displayField}?: string } | null)?.${displayField} || '-').join(', ') : '-'}
|
|
220
220
|
</td>`;
|
|
221
221
|
} else {
|
|
222
222
|
return ` <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
@@ -317,7 +317,7 @@ export function generateDetailPage(model: ModelInfo, sharedPackageName: string,
|
|
|
317
317
|
const refModelCamel = toCamelCase(refModel);
|
|
318
318
|
return ` fetch('/api/${refModelCamel}')
|
|
319
319
|
.then(res => res.json())
|
|
320
|
-
.then((data:
|
|
320
|
+
.then((data: Array<{ id: string; name?: string; title?: string }>) => {
|
|
321
321
|
const map: Record<string, string> = {};
|
|
322
322
|
data.forEach(item => {
|
|
323
323
|
map[item.id] = item.name || item.title || item.id;
|
|
@@ -389,8 +389,8 @@ ${hasForeignKeys ? foreignKeyFetches : ''}
|
|
|
389
389
|
if (!res.ok) throw new Error('Failed to delete ${modelCamel}');
|
|
390
390
|
|
|
391
391
|
router.push('/${modelKebab}');
|
|
392
|
-
} catch (err
|
|
393
|
-
alert(\`Error: \${err.message}\`);
|
|
392
|
+
} catch (err) {
|
|
393
|
+
alert(\`Error: \${err instanceof Error ? err.message : String(err)}\`);
|
|
394
394
|
}
|
|
395
395
|
};
|
|
396
396
|
|
|
@@ -455,7 +455,7 @@ ${model.fields.map(f => {
|
|
|
455
455
|
if (f.isArray) {
|
|
456
456
|
return ` <div>
|
|
457
457
|
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">${label}</dt>
|
|
458
|
-
<dd className="mt-1 text-sm text-gray-900 dark:text-gray-100">{Array.isArray(${modelCamel}.${f.name}) ? ${modelCamel}.${f.name}.map((ref:
|
|
458
|
+
<dd className="mt-1 text-sm text-gray-900 dark:text-gray-100">{Array.isArray(${modelCamel}.${f.name}) ? ${modelCamel}.${f.name}.map((ref: unknown) => (ref as { ${displayField}?: string } | null)?.${displayField} || '-').join(', ') : '-'}</dd>
|
|
459
459
|
</div>`;
|
|
460
460
|
} else {
|
|
461
461
|
return ` <div>
|
|
@@ -547,7 +547,7 @@ export function generateFormComponent(model: ModelInfo, sharedPackageName: strin
|
|
|
547
547
|
return ` // ${refModelPascal} の一覧を取得
|
|
548
548
|
fetch('/api/${refModelCamel}')
|
|
549
549
|
.then(res => res.json())
|
|
550
|
-
.then(data => set${refModelPascal}Options(data.map((item:
|
|
550
|
+
.then(data => set${refModelPascal}Options(data.map((item: Record<string, string>) => ({ id: item.id, name: item.${displayField} || item.name || item.title || item.id }))))
|
|
551
551
|
.catch(err => console.error('Failed to load ${refModelPascal} options:', err));`;
|
|
552
552
|
}).join('\n');
|
|
553
553
|
|
|
@@ -581,7 +581,7 @@ ${formFields.map(f => {
|
|
|
581
581
|
// ネストスキーマの場合は参照ID(単一: string, 配列: string[])を管理
|
|
582
582
|
if (f.isNestedSchema) {
|
|
583
583
|
if (f.isArray) {
|
|
584
|
-
return ` ${f.name}Ids: initialData?.${f.name} ? (Array.isArray(initialData.${f.name}) ? initialData.${f.name}.map((item:
|
|
584
|
+
return ` ${f.name}Ids: initialData?.${f.name} ? (Array.isArray(initialData.${f.name}) ? initialData.${f.name}.map((item: { id: string }) => item.id) : []) : [] as string[],`;
|
|
585
585
|
} else {
|
|
586
586
|
return ` ${f.name}Id: initialData?.${f.name}?.id ?? '',`;
|
|
587
587
|
}
|
|
@@ -615,7 +615,7 @@ ${needsUseEffect ? `
|
|
|
615
615
|
${hasForignKeys ? foreignKeyFields.map(f => ` // ${f.referencedModel} の一覧を取得
|
|
616
616
|
fetch('/api/${toKebabCase(f.referencedModel!)}')
|
|
617
617
|
.then(res => res.json())
|
|
618
|
-
.then(data => set${f.referencedModel}Options(data.map((item:
|
|
618
|
+
.then(data => set${f.referencedModel}Options(data.map((item: Record<string, string>) => ({ id: item.id, name: item.name || item.title || item.id }))))
|
|
619
619
|
.catch(err => console.error('Failed to load ${f.referencedModel} options:', err));`).join('\n') : ''}
|
|
620
620
|
${hasNestedSchemas ? nestedSchemaFetches : ''}
|
|
621
621
|
}, []);
|
|
@@ -627,7 +627,7 @@ ${hasNestedSchemas ? nestedSchemaFetches : ''}
|
|
|
627
627
|
|
|
628
628
|
try {
|
|
629
629
|
// Array フィールドをカンマ区切りから配列に変換
|
|
630
|
-
const submitData:
|
|
630
|
+
const submitData: Record<string, unknown> = { ...formData };
|
|
631
631
|
${formFields.filter(f => f.isArray && !f.isNestedSchema).map(f => ` if (typeof submitData.${f.name} === 'string') {
|
|
632
632
|
submitData.${f.name} = submitData.${f.name}.split(',').map((s: string) => s.trim()).filter((s: string) => s.length > 0);
|
|
633
633
|
}`).join('\n')}
|
|
@@ -651,7 +651,7 @@ ${nestedSchemaFields.map(f => {
|
|
|
651
651
|
if (f.isArray) {
|
|
652
652
|
return ` // ${refModelPascal} 配列参照の変換
|
|
653
653
|
if (submitData.${f.name}Ids) {
|
|
654
|
-
submitData.${f.name} = submitData.${f.name}Ids
|
|
654
|
+
submitData.${f.name} = (submitData.${f.name}Ids as string[])
|
|
655
655
|
.map((refId: string) => ${refModelCamel}Options.find(opt => opt.id === refId))
|
|
656
656
|
.filter(Boolean);
|
|
657
657
|
delete submitData.${f.name}Ids;
|
|
@@ -688,17 +688,17 @@ ${nestedSchemaFields.map(f => {
|
|
|
688
688
|
}
|
|
689
689
|
|
|
690
690
|
router.push('/${toKebabCase(modelName)}');
|
|
691
|
-
} catch (err
|
|
692
|
-
if (err.
|
|
691
|
+
} catch (err) {
|
|
692
|
+
if (err instanceof z.ZodError) {
|
|
693
693
|
// Zod validation errors
|
|
694
694
|
const fieldErrors: Record<string, string> = {};
|
|
695
|
-
err.issues.forEach((
|
|
696
|
-
const field =
|
|
697
|
-
fieldErrors[field] =
|
|
695
|
+
err.issues.forEach((issue) => {
|
|
696
|
+
const field = String(issue.path[0]);
|
|
697
|
+
fieldErrors[field] = issue.message;
|
|
698
698
|
});
|
|
699
699
|
setErrors(fieldErrors);
|
|
700
700
|
} else {
|
|
701
|
-
alert(\`Error: \${err.message}\`);
|
|
701
|
+
alert(\`Error: \${err instanceof Error ? err.message : String(err)}\`);
|
|
702
702
|
}
|
|
703
703
|
setLoading(false);
|
|
704
704
|
}
|