@superblocksteam/sdk 2.0.96 → 2.0.97-next.0
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/.turbo/turbo-build.log +1 -1
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +125 -21
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/parse-sdk-registry.d.mts.map +1 -1
- package/dist/parse-sdk-registry.mjs +5 -130
- package/dist/parse-sdk-registry.mjs.map +1 -1
- package/dist/parse-sdk-registry.test.mjs +11 -1
- package/dist/parse-sdk-registry.test.mjs.map +1 -1
- package/package.json +6 -6
- package/src/cli-replacement/dev.mts +136 -37
- package/src/parse-sdk-registry.mts +8 -181
- package/src/parse-sdk-registry.test.mts +17 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.d.ts +0 -5
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.d.ts.map +0 -1
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.js +0 -61
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.js.map +0 -1
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.test.d.ts +0 -2
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.test.d.ts.map +0 -1
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.test.js +0 -32
- package/dist/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.test.js.map +0 -1
- package/src/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.test.ts +0 -60
- package/src/cli-replacement/assets/git-workflows/github-superblocks-sync-workflow.ts +0 -70
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-sdk-registry.test.mjs","sourceRoot":"","sources":["../src/parse-sdk-registry.test.mts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC;IACpB,MAAM,WAAW,GAAG,kBAAkB,CAAC;IACvC,MAAM,UAAU,GAAG,KAAK,EAAE,CAAS,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvD,OAAO,CACL,GAAG,KAAK,6BAA6B;YACrC,GAAG,KAAK,gCAAgC;YACxC,GAAG,KAAK,gCAAgC,
|
|
1
|
+
{"version":3,"file":"parse-sdk-registry.test.mjs","sourceRoot":"","sources":["../src/parse-sdk-registry.test.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superblocksteam/sdk",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.97-next.0",
|
|
4
4
|
"description": "Superblocks JS SDK",
|
|
5
5
|
"homepage": "https://www.superblocks.com",
|
|
6
6
|
"license": "Superblocks Community Software License",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"vite-tsconfig-paths": "^6.0.4",
|
|
49
49
|
"winston": "^3.17.0",
|
|
50
50
|
"yaml": "^2.7.1",
|
|
51
|
-
"@superblocksteam/library-shared": "2.0.
|
|
52
|
-
"@superblocksteam/shared": "0.
|
|
53
|
-
"@superblocksteam/telemetry": "2.0.
|
|
54
|
-
"@superblocksteam/util": "2.0.
|
|
55
|
-
"@superblocksteam/vite-plugin-file-sync": "2.0.
|
|
51
|
+
"@superblocksteam/library-shared": "2.0.97-next.0",
|
|
52
|
+
"@superblocksteam/shared": "0.9568.0",
|
|
53
|
+
"@superblocksteam/telemetry": "2.0.97-next.0",
|
|
54
|
+
"@superblocksteam/util": "2.0.97-next.0",
|
|
55
|
+
"@superblocksteam/vite-plugin-file-sync": "2.0.97-next.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@eslint/js": "^9.39.2",
|
|
@@ -5,7 +5,9 @@ import * as readline from "node:readline";
|
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { SpanStatusCode } from "@opentelemetry/api";
|
|
7
7
|
import {
|
|
8
|
+
buildGithubSuperblocksSyncWorkflow,
|
|
8
9
|
ConflictError,
|
|
10
|
+
isGitHubRemoteUrl,
|
|
9
11
|
NotFoundError,
|
|
10
12
|
SUPERBLOCKS_LIVE_GIT_BRANCH,
|
|
11
13
|
} from "@superblocksteam/shared";
|
|
@@ -33,7 +35,6 @@ import { createDevServer } from "../dev-utils/dev-server.mjs";
|
|
|
33
35
|
import { AUTO_UPGRADE_EXIT_CODE } from "../index.js";
|
|
34
36
|
import { getTracer } from "../telemetry/index.js";
|
|
35
37
|
import { getErrorMeta, getLogger, type Logger } from "../telemetry/logging.js";
|
|
36
|
-
import { buildGithubSuperblocksSyncWorkflow } from "./assets/git-workflows/github-superblocks-sync-workflow.js";
|
|
37
38
|
import { checkVersionsAndWritePackageJson } from "./automatic-upgrades.js";
|
|
38
39
|
import { getCurrentCliVersion } from "./version-detection.js";
|
|
39
40
|
import type {
|
|
@@ -51,6 +52,7 @@ import type { DraftInterface } from "@superblocksteam/vite-plugin-file-sync/draf
|
|
|
51
52
|
import type { GitService } from "@superblocksteam/vite-plugin-file-sync/git-service";
|
|
52
53
|
|
|
53
54
|
const exec = promisify(child_process.exec);
|
|
55
|
+
|
|
54
56
|
const passErrorToVSCode = (message: string | undefined, logger: Logger) => {
|
|
55
57
|
if (message && process.env.SUPERBLOCKS_VSCODE === "true") {
|
|
56
58
|
// Prefixing with `clierr:` will make the VS code extension capture this message and show it to the user.
|
|
@@ -479,18 +481,17 @@ export async function dev(options: {
|
|
|
479
481
|
process.env.SUPERBLOCKS_APP_TEMPLATE_NAME ??
|
|
480
482
|
options.prefetchedApplication?.application?.templateName;
|
|
481
483
|
const sdkApiEnabled = isSdkApiTemplate(templateName);
|
|
484
|
+
const isAppFullstackTemplate = templateName === "app-fullstack";
|
|
485
|
+
const rawFlagBootstrap = currentUser.flagBootstrap as
|
|
486
|
+
| Record<string, unknown>
|
|
487
|
+
| undefined;
|
|
482
488
|
const flagBootstrap = {
|
|
483
|
-
...
|
|
484
|
-
| Record<string, unknown>
|
|
485
|
-
| undefined),
|
|
489
|
+
...rawFlagBootstrap,
|
|
486
490
|
"clark.sdk-api.enabled": sdkApiEnabled,
|
|
487
491
|
"superblocks.native-git.enabled":
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
| Record<string, unknown>
|
|
492
|
-
| undefined
|
|
493
|
-
)?.["superblocks.native-git.enabled"],
|
|
492
|
+
(isAppFullstackTemplate &&
|
|
493
|
+
!!rawFlagBootstrap?.["superblocks.native-git.enabled"]) ||
|
|
494
|
+
!!rawFlagBootstrap?.["superblocks.native-git.forced"],
|
|
494
495
|
};
|
|
495
496
|
|
|
496
497
|
aiService = new AiService({
|
|
@@ -572,7 +573,14 @@ export async function dev(options: {
|
|
|
572
573
|
});
|
|
573
574
|
|
|
574
575
|
if (!bootstrappedGitService) {
|
|
575
|
-
logger.info("
|
|
576
|
+
logger.info("[git] startup git sync skipped", {
|
|
577
|
+
gitCategory: "setup",
|
|
578
|
+
gitOperation: "bootstrap",
|
|
579
|
+
gitOutcome: "skipped",
|
|
580
|
+
gitReason: "no_remote_configured",
|
|
581
|
+
applicationId: applicationConfig.id,
|
|
582
|
+
workDir: cwd,
|
|
583
|
+
});
|
|
576
584
|
gitSpan.end();
|
|
577
585
|
return;
|
|
578
586
|
}
|
|
@@ -607,14 +615,30 @@ export async function dev(options: {
|
|
|
607
615
|
);
|
|
608
616
|
} catch (syncError) {
|
|
609
617
|
logger.warn(
|
|
610
|
-
|
|
618
|
+
"[git] startup remote sync failed but local repo remains usable",
|
|
619
|
+
{
|
|
620
|
+
gitCategory: "setup",
|
|
621
|
+
gitOperation: "fetch-and-ensure-live-branch",
|
|
622
|
+
gitOutcome: "failed",
|
|
623
|
+
applicationId: applicationConfig.id,
|
|
624
|
+
workDir: cwd,
|
|
625
|
+
...getGitErrorFields(syncError),
|
|
626
|
+
},
|
|
611
627
|
);
|
|
612
628
|
}
|
|
613
629
|
} catch (gitError) {
|
|
614
630
|
// Init/configure/ensureGitRepo failed — repo is not usable
|
|
615
631
|
gitService = undefined;
|
|
616
632
|
logger.warn(
|
|
617
|
-
|
|
633
|
+
"[git] startup git setup failed, continuing without git",
|
|
634
|
+
{
|
|
635
|
+
gitCategory: "setup",
|
|
636
|
+
gitOperation: "bootstrap",
|
|
637
|
+
gitOutcome: "failed",
|
|
638
|
+
applicationId: applicationConfig.id,
|
|
639
|
+
workDir: cwd,
|
|
640
|
+
...getGitErrorFields(gitError),
|
|
641
|
+
},
|
|
618
642
|
);
|
|
619
643
|
gitSpan.setStatus({
|
|
620
644
|
code: SpanStatusCode.ERROR,
|
|
@@ -748,10 +772,22 @@ export async function dev(options: {
|
|
|
748
772
|
() => false,
|
|
749
773
|
);
|
|
750
774
|
if (!hasGit) {
|
|
751
|
-
logger.warn(
|
|
752
|
-
|
|
753
|
-
|
|
775
|
+
logger.warn("[git] runtime git service cache invalidated", {
|
|
776
|
+
gitCategory: "setup",
|
|
777
|
+
gitOperation: "activate-runtime-service",
|
|
778
|
+
gitOutcome: "failed",
|
|
779
|
+
gitReason: "missing_git_directory",
|
|
780
|
+
workDir: cwd,
|
|
781
|
+
});
|
|
754
782
|
gitService = undefined;
|
|
783
|
+
activeDbfsBranchName = await ensureRuntimeDbfsBranchConsistency({
|
|
784
|
+
sdk,
|
|
785
|
+
applicationConfig,
|
|
786
|
+
logger,
|
|
787
|
+
lockService,
|
|
788
|
+
syncService,
|
|
789
|
+
currentBranchName: activeDbfsBranchName,
|
|
790
|
+
});
|
|
755
791
|
return undefined;
|
|
756
792
|
}
|
|
757
793
|
|
|
@@ -776,6 +812,16 @@ export async function dev(options: {
|
|
|
776
812
|
userEmail: gitUserEmail,
|
|
777
813
|
});
|
|
778
814
|
if (!runtimeGitService) {
|
|
815
|
+
// Git may have been disconnected while this dev server is running.
|
|
816
|
+
// Reconcile lock/sync branch context back to non-git runtime state.
|
|
817
|
+
activeDbfsBranchName = await ensureRuntimeDbfsBranchConsistency({
|
|
818
|
+
sdk,
|
|
819
|
+
applicationConfig,
|
|
820
|
+
logger,
|
|
821
|
+
lockService,
|
|
822
|
+
syncService,
|
|
823
|
+
currentBranchName: activeDbfsBranchName,
|
|
824
|
+
});
|
|
779
825
|
return undefined;
|
|
780
826
|
}
|
|
781
827
|
|
|
@@ -800,9 +846,14 @@ export async function dev(options: {
|
|
|
800
846
|
gitService = runtimeGitService;
|
|
801
847
|
return gitService;
|
|
802
848
|
} catch (error) {
|
|
803
|
-
logger.warn(
|
|
804
|
-
|
|
805
|
-
|
|
849
|
+
logger.warn("[git] runtime bootstrap failed", {
|
|
850
|
+
gitCategory: "setup",
|
|
851
|
+
gitOperation: "runtime-bootstrap",
|
|
852
|
+
gitOutcome: "failed",
|
|
853
|
+
applicationId: applicationConfig.id,
|
|
854
|
+
workDir: cwd,
|
|
855
|
+
...getGitErrorFields(error),
|
|
856
|
+
});
|
|
806
857
|
return undefined;
|
|
807
858
|
}
|
|
808
859
|
};
|
|
@@ -818,6 +869,7 @@ export async function dev(options: {
|
|
|
818
869
|
syncService: syncService,
|
|
819
870
|
lockService: lockService,
|
|
820
871
|
aiService: aiService,
|
|
872
|
+
gitService: gitService,
|
|
821
873
|
activateGitService: activateRuntimeGitService,
|
|
822
874
|
snapshotManager: snapshotManager,
|
|
823
875
|
logger: options.logger,
|
|
@@ -864,6 +916,17 @@ export async function dev(options: {
|
|
|
864
916
|
// Git sync helpers
|
|
865
917
|
// ---------------------------------------------------------------------------
|
|
866
918
|
|
|
919
|
+
function getGitErrorFields(error: unknown): {
|
|
920
|
+
gitErrorKind: string;
|
|
921
|
+
gitErrorMessage: string;
|
|
922
|
+
} {
|
|
923
|
+
const meta = getErrorMeta(error);
|
|
924
|
+
return {
|
|
925
|
+
gitErrorKind: meta.error.kind,
|
|
926
|
+
gitErrorMessage: meta.error.message,
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
|
|
867
930
|
async function bootstrapGitService({
|
|
868
931
|
sdk,
|
|
869
932
|
applicationId,
|
|
@@ -897,10 +960,12 @@ async function bootstrapGitService({
|
|
|
897
960
|
|
|
898
961
|
const service = createGitService(cwd);
|
|
899
962
|
let credentials: { username: string; token: string } | undefined;
|
|
963
|
+
let gitRemoteHost: string | undefined;
|
|
900
964
|
|
|
901
965
|
if (gitConfig.hasCredential) {
|
|
902
966
|
try {
|
|
903
967
|
const host = new URL(gitConfig.gitRemoteUrl).hostname;
|
|
968
|
+
gitRemoteHost = host;
|
|
904
969
|
const freshToken = await gitConfigSdk.getGitFreshToken(
|
|
905
970
|
host,
|
|
906
971
|
applicationId,
|
|
@@ -908,8 +973,16 @@ async function bootstrapGitService({
|
|
|
908
973
|
if (freshToken) {
|
|
909
974
|
credentials = freshToken;
|
|
910
975
|
}
|
|
911
|
-
} catch {
|
|
912
|
-
logger.warn("
|
|
976
|
+
} catch (error) {
|
|
977
|
+
logger.warn("[git] credential fetch failed, continuing without auth", {
|
|
978
|
+
gitCategory: "setup",
|
|
979
|
+
gitOperation: "fetch-credentials",
|
|
980
|
+
gitOutcome: "failed",
|
|
981
|
+
applicationId,
|
|
982
|
+
gitRemoteHost,
|
|
983
|
+
gitRemoteUrl: gitConfig.gitRemoteUrl,
|
|
984
|
+
...getGitErrorFields(error),
|
|
985
|
+
});
|
|
913
986
|
}
|
|
914
987
|
}
|
|
915
988
|
|
|
@@ -928,9 +1001,14 @@ async function fetchAndEnsureLiveBranch(
|
|
|
928
1001
|
await git.fetch();
|
|
929
1002
|
} catch (error) {
|
|
930
1003
|
fetchError = error;
|
|
931
|
-
getLogger().warn(
|
|
932
|
-
|
|
933
|
-
|
|
1004
|
+
getLogger().warn("[git] fetch and ensure live branch failed", {
|
|
1005
|
+
gitCategory: "setup",
|
|
1006
|
+
gitOperation: "fetch-and-ensure-live-branch",
|
|
1007
|
+
gitOutcome: "failed",
|
|
1008
|
+
gitReason: errorPrefix,
|
|
1009
|
+
workDir: git.workDir,
|
|
1010
|
+
...getGitErrorFields(error),
|
|
1011
|
+
});
|
|
934
1012
|
}
|
|
935
1013
|
// Always ensure the local superblocks/live branch exists,
|
|
936
1014
|
// even if fetch failed (remote may not be reachable yet).
|
|
@@ -961,9 +1039,15 @@ async function ensureGitRepo(
|
|
|
961
1039
|
`refs/heads/${SUPERBLOCKS_LIVE_GIT_BRANCH}`,
|
|
962
1040
|
])
|
|
963
1041
|
.catch((err) => {
|
|
964
|
-
getLogger().warn(
|
|
965
|
-
|
|
966
|
-
|
|
1042
|
+
getLogger().warn("[git] ensure repo ls-remote failed", {
|
|
1043
|
+
gitCategory: "setup",
|
|
1044
|
+
gitOperation: "ensure-repo",
|
|
1045
|
+
gitOutcome: "failed",
|
|
1046
|
+
gitRemote: "origin",
|
|
1047
|
+
gitBranch: SUPERBLOCKS_LIVE_GIT_BRANCH,
|
|
1048
|
+
gitRemoteUrl: remoteUrl,
|
|
1049
|
+
...getGitErrorFields(err),
|
|
1050
|
+
});
|
|
967
1051
|
return "";
|
|
968
1052
|
});
|
|
969
1053
|
|
|
@@ -1003,17 +1087,36 @@ async function ensureGitRepo(
|
|
|
1003
1087
|
const remotes = await git.getRemotes(true);
|
|
1004
1088
|
const origin = remotes.find((r) => r.name === "origin");
|
|
1005
1089
|
if (origin && origin.refs.fetch !== remoteUrl) {
|
|
1006
|
-
getLogger().warn(
|
|
1007
|
-
|
|
1008
|
-
|
|
1090
|
+
getLogger().warn("[git] ensure repo remote url changed", {
|
|
1091
|
+
gitCategory: "setup",
|
|
1092
|
+
gitOperation: "ensure-repo",
|
|
1093
|
+
gitOutcome: "fallback",
|
|
1094
|
+
gitRemote: "origin",
|
|
1095
|
+
gitPreviousRemoteUrl: origin.refs.fetch,
|
|
1096
|
+
gitRemoteUrl: remoteUrl,
|
|
1097
|
+
});
|
|
1009
1098
|
await git.remote(["set-url", "origin", remoteUrl]);
|
|
1010
1099
|
} else if (!origin) {
|
|
1011
|
-
getLogger().warn("[git]
|
|
1100
|
+
getLogger().warn("[git] ensure repo origin remote missing, adding", {
|
|
1101
|
+
gitCategory: "setup",
|
|
1102
|
+
gitOperation: "ensure-repo",
|
|
1103
|
+
gitOutcome: "fallback",
|
|
1104
|
+
gitRemote: "origin",
|
|
1105
|
+
gitRemoteUrl: remoteUrl,
|
|
1106
|
+
});
|
|
1012
1107
|
await git.addRemote("origin", remoteUrl);
|
|
1013
1108
|
}
|
|
1014
1109
|
} catch (remoteErr) {
|
|
1015
1110
|
getLogger().warn(
|
|
1016
|
-
|
|
1111
|
+
"[git] ensure repo remote inspection failed, attempting fallback",
|
|
1112
|
+
{
|
|
1113
|
+
gitCategory: "setup",
|
|
1114
|
+
gitOperation: "ensure-repo",
|
|
1115
|
+
gitOutcome: "failed",
|
|
1116
|
+
gitRemote: "origin",
|
|
1117
|
+
gitRemoteUrl: remoteUrl,
|
|
1118
|
+
...getGitErrorFields(remoteErr),
|
|
1119
|
+
},
|
|
1017
1120
|
);
|
|
1018
1121
|
try {
|
|
1019
1122
|
await git.addRemote("origin", remoteUrl);
|
|
@@ -1028,15 +1131,11 @@ async function ensureGitRepo(
|
|
|
1028
1131
|
await seedGithubWorkflowIfNeeded(git.workDir, remoteUrl);
|
|
1029
1132
|
}
|
|
1030
1133
|
|
|
1031
|
-
function isGithubRemote(remoteUrl: string): boolean {
|
|
1032
|
-
return remoteUrl.includes("github.com");
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
1134
|
async function seedGithubWorkflowIfNeeded(
|
|
1036
1135
|
workDir: string,
|
|
1037
1136
|
remoteUrl: string,
|
|
1038
1137
|
): Promise<void> {
|
|
1039
|
-
if (!
|
|
1138
|
+
if (!isGitHubRemoteUrl(remoteUrl)) {
|
|
1040
1139
|
return;
|
|
1041
1140
|
}
|
|
1042
1141
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { parseSdkRegistryFromContent } from "@superblocksteam/vite-plugin-file-sync/parsing";
|
|
3
3
|
|
|
4
4
|
export type RegistryKeyToPath = Map<string, string>;
|
|
5
5
|
|
|
6
6
|
type PathExists = (p: string) => Promise<boolean>;
|
|
7
|
+
const RESOLUTION_EXTENSIONS = [".ts", ".tsx", ".js"] as const;
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Parse server/apis/index.ts to extract the mapping from registry key (used in
|
|
@@ -26,84 +27,9 @@ export async function parseSdkRegistry(
|
|
|
26
27
|
root: string,
|
|
27
28
|
pathExists: PathExists,
|
|
28
29
|
): Promise<RegistryKeyToPath> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
ast = parse(registryContent, {
|
|
34
|
-
sourceType: "module",
|
|
35
|
-
plugins: ["typescript"],
|
|
36
|
-
});
|
|
37
|
-
} catch {
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const body = ast.program.body;
|
|
42
|
-
|
|
43
|
-
// Build import map: local name -> resolved path (relative to root)
|
|
44
|
-
const importMap = new Map<string, string>();
|
|
45
|
-
for (const node of body) {
|
|
46
|
-
if (node.type !== "ImportDeclaration") continue;
|
|
47
|
-
const imp = node;
|
|
48
|
-
const specifier = imp.specifiers[0];
|
|
49
|
-
if (!specifier || specifier.type !== "ImportDefaultSpecifier") continue;
|
|
50
|
-
const localName = specifier.local?.name;
|
|
51
|
-
const source = imp.source?.value;
|
|
52
|
-
if (typeof localName !== "string" || typeof source !== "string") continue;
|
|
53
|
-
const resolved = await resolveImportPath(
|
|
54
|
-
source,
|
|
55
|
-
registryDir,
|
|
56
|
-
root,
|
|
57
|
-
pathExists,
|
|
58
|
-
);
|
|
59
|
-
if (resolved) importMap.set(localName, resolved);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Find the exported object
|
|
63
|
-
const exportedObject = findExportedObject(ast);
|
|
64
|
-
if (!exportedObject) return result;
|
|
65
|
-
|
|
66
|
-
for (const prop of exportedObject.properties) {
|
|
67
|
-
if (prop.type !== "ObjectProperty") continue;
|
|
68
|
-
const key = getPropertyKey(
|
|
69
|
-
prop as { key: { type: string; name?: string; value?: string } },
|
|
70
|
-
);
|
|
71
|
-
if (!key) continue;
|
|
72
|
-
|
|
73
|
-
const value = prop.value as {
|
|
74
|
-
type: string;
|
|
75
|
-
name?: string;
|
|
76
|
-
body?: { type: string };
|
|
77
|
-
};
|
|
78
|
-
let resolvedPath: string | undefined;
|
|
79
|
-
|
|
80
|
-
if (value.type === "Identifier") {
|
|
81
|
-
resolvedPath = importMap.get(value.name ?? "");
|
|
82
|
-
} else if (value.type === "CallExpression") {
|
|
83
|
-
resolvedPath = await resolveImportPathFromCall(
|
|
84
|
-
value as unknown as Parameters<typeof resolveImportPathFromCall>[0],
|
|
85
|
-
registryDir,
|
|
86
|
-
root,
|
|
87
|
-
pathExists,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
// ObjectProperty with ArrowFunctionExpression: () => import('./x')
|
|
91
|
-
else if (value.type === "ArrowFunctionExpression") {
|
|
92
|
-
const body = value.body;
|
|
93
|
-
if (body?.type === "CallExpression") {
|
|
94
|
-
resolvedPath = await resolveImportPathFromCall(
|
|
95
|
-
body as unknown as Parameters<typeof resolveImportPathFromCall>[0],
|
|
96
|
-
registryDir,
|
|
97
|
-
root,
|
|
98
|
-
pathExists,
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (resolvedPath) result.set(key, resolvedPath);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return result;
|
|
30
|
+
return parseSdkRegistryFromContent(registryContent, (importPath) =>
|
|
31
|
+
resolveImportPath(importPath, registryDir, root, pathExists),
|
|
32
|
+
);
|
|
107
33
|
}
|
|
108
34
|
|
|
109
35
|
async function resolveImportPath(
|
|
@@ -116,112 +42,13 @@ async function resolveImportPath(
|
|
|
116
42
|
const absoluteBase = path
|
|
117
43
|
.normalize(path.join(registryDir, importPath))
|
|
118
44
|
.replace(/\.(js|ts|tsx)$/, "");
|
|
119
|
-
|
|
120
|
-
|
|
45
|
+
|
|
46
|
+
for (const extension of RESOLUTION_EXTENSIONS) {
|
|
47
|
+
const candidate = absoluteBase + extension;
|
|
121
48
|
if (await pathExists(candidate)) {
|
|
122
49
|
return path.relative(root, candidate).replace(/\\/g, "/");
|
|
123
50
|
}
|
|
124
51
|
}
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
52
|
|
|
128
|
-
async function resolveImportPathFromCall(
|
|
129
|
-
call: {
|
|
130
|
-
callee: { type: string };
|
|
131
|
-
arguments: Array<{ type: string; value?: string }>;
|
|
132
|
-
},
|
|
133
|
-
registryDir: string,
|
|
134
|
-
root: string,
|
|
135
|
-
pathExists: PathExists,
|
|
136
|
-
): Promise<string | undefined> {
|
|
137
|
-
const callee = call.callee;
|
|
138
|
-
if (callee.type !== "Import") return undefined;
|
|
139
|
-
const arg = call.arguments[0];
|
|
140
|
-
if (arg?.type !== "StringLiteral" || typeof arg.value !== "string")
|
|
141
|
-
return undefined;
|
|
142
|
-
return resolveImportPath(arg.value, registryDir, root, pathExists);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function getPropertyKey(prop: {
|
|
146
|
-
key: { type: string; name?: string; value?: string };
|
|
147
|
-
}): string | undefined {
|
|
148
|
-
const key = prop.key;
|
|
149
|
-
if (key.type === "Identifier") return key.name;
|
|
150
|
-
if (key.type === "StringLiteral") return key.value;
|
|
151
|
-
return undefined;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function findExportedObject(
|
|
155
|
-
ast: ReturnType<typeof parse>,
|
|
156
|
-
):
|
|
157
|
-
| { properties: Array<{ type: string; key: unknown; value: unknown }> }
|
|
158
|
-
| undefined {
|
|
159
|
-
for (const node of ast.program.body) {
|
|
160
|
-
if (node.type !== "ExportDefaultDeclaration") continue;
|
|
161
|
-
const decl = node.declaration as { type: string; name?: string };
|
|
162
|
-
|
|
163
|
-
const obj = getObjectExpression(
|
|
164
|
-
decl as { type: string; expression?: unknown; properties?: unknown[] },
|
|
165
|
-
);
|
|
166
|
-
if (obj) {
|
|
167
|
-
return obj as {
|
|
168
|
-
properties: Array<{ type: string; key: unknown; value: unknown }>;
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
if (decl.type === "Identifier") {
|
|
172
|
-
const varName = decl.name;
|
|
173
|
-
if (!varName) continue;
|
|
174
|
-
const def = findVariableDeclaration(ast, varName);
|
|
175
|
-
if (def?.init) {
|
|
176
|
-
return def.init as unknown as {
|
|
177
|
-
properties: Array<{ type: string; key: unknown; value: unknown }>;
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return undefined;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function getObjectExpression(node: {
|
|
186
|
-
type: string;
|
|
187
|
-
expression?: unknown;
|
|
188
|
-
properties?: unknown[];
|
|
189
|
-
}): { properties: unknown[] } | undefined {
|
|
190
|
-
if (node.type === "ObjectExpression") {
|
|
191
|
-
return node as { properties: unknown[] };
|
|
192
|
-
}
|
|
193
|
-
// TypeScript: { x } as const → TSAsExpression or TSSatisfiesExpression
|
|
194
|
-
if (
|
|
195
|
-
(node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") &&
|
|
196
|
-
"expression" in node
|
|
197
|
-
) {
|
|
198
|
-
const inner = node.expression as { type: string; properties?: unknown[] };
|
|
199
|
-
if (inner?.type === "ObjectExpression") {
|
|
200
|
-
return inner as { properties: unknown[] };
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return undefined;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function findVariableDeclaration(
|
|
207
|
-
ast: ReturnType<typeof parse>,
|
|
208
|
-
name: string,
|
|
209
|
-
): { init: { properties: unknown[] } } | undefined {
|
|
210
|
-
for (const node of ast.program.body) {
|
|
211
|
-
if (node.type !== "VariableDeclaration") continue;
|
|
212
|
-
const decl = node;
|
|
213
|
-
for (const declarator of decl.declarations) {
|
|
214
|
-
if (
|
|
215
|
-
declarator.id.type === "Identifier" &&
|
|
216
|
-
declarator.id.name === name &&
|
|
217
|
-
declarator.init
|
|
218
|
-
) {
|
|
219
|
-
const obj = getObjectExpression(
|
|
220
|
-
declarator.init as { type: string; expression?: unknown },
|
|
221
|
-
);
|
|
222
|
-
if (obj) return { init: obj };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
53
|
return undefined;
|
|
227
54
|
}
|
|
@@ -10,7 +10,8 @@ describe("parseSdkRegistry", () => {
|
|
|
10
10
|
return (
|
|
11
11
|
rel === "server/apis/GetUsers/api.ts" ||
|
|
12
12
|
rel === "server/apis/v2/GetUsers/api.ts" ||
|
|
13
|
-
rel === "server/apis/CreateOrder/api.ts"
|
|
13
|
+
rel === "server/apis/CreateOrder/api.ts" ||
|
|
14
|
+
rel === "server/apis/JsOnly/api.js"
|
|
14
15
|
);
|
|
15
16
|
};
|
|
16
17
|
|
|
@@ -130,4 +131,19 @@ export default { GetUsers } as const;
|
|
|
130
131
|
);
|
|
131
132
|
expect(result.size).toBe(0);
|
|
132
133
|
});
|
|
134
|
+
|
|
135
|
+
it("resolves .js files when .ts/.tsx are missing", async () => {
|
|
136
|
+
const content = `
|
|
137
|
+
import JsOnly from './JsOnly/api.js';
|
|
138
|
+
export default { JsOnly };
|
|
139
|
+
`;
|
|
140
|
+
const result = await parseSdkRegistry(
|
|
141
|
+
content,
|
|
142
|
+
registryDir,
|
|
143
|
+
root,
|
|
144
|
+
pathExists,
|
|
145
|
+
);
|
|
146
|
+
expect(result.get("JsOnly")).toBe("server/apis/JsOnly/api.js");
|
|
147
|
+
expect(result.size).toBe(1);
|
|
148
|
+
});
|
|
133
149
|
});
|