@akanjs/devkit 3.0.0-beta.19 → 3.0.0-beta.20
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/abstractDoc.test.ts +6 -15
- package/abstractDoc.ts +1 -4
- package/agentsIndex.test.ts +4 -7
- package/agentsIndex.ts +6 -22
- package/akanApp/BackendImportGraph.test.ts +8 -22
- package/akanApp/BackendImportGraph.ts +1 -20
- package/akanApp/akanApp.host.test.ts +1 -3
- package/akanApp/akanApp.host.ts +64 -250
- package/akanApp/devHostPolicy.test.ts +10 -34
- package/akanApp/devHostPolicy.ts +12 -98
- package/akanConfig/akanConfig.test.ts +30 -39
- package/akanConfig/akanConfig.ts +40 -136
- package/akanContext.ts +106 -159
- package/akanMcpContract.ts +28 -73
- package/appSelectionMemory.ts +1 -4
- package/applicationBuildReporter.ts +37 -5
- package/applicationBuildRunner.ts +25 -59
- package/applicationReleasePackager.ts +24 -44
- package/applicationTestPreload.ts +3 -12
- package/artifact/implicitRootLayout.test.ts +3 -19
- package/artifact/implicitRootLayout.ts +34 -91
- package/artifact/routeSeedIndex.ts +11 -44
- package/biomeBase.ts +2 -5
- package/capacitorApp.test.ts +4 -14
- package/capacitorApp.ts +86 -235
- package/cloud/cloudApi.test.ts +202 -0
- package/cloud/cloudApi.ts +33 -57
- package/cloud/configLock.test.ts +64 -0
- package/cloud/configLock.ts +96 -0
- package/cloud/constants.ts +3 -2
- package/cloud/globalConfig.ts +64 -31
- package/codeAgent/agent/AkanCodeServices.ts +15 -57
- package/codeAgent/agent/AkanContextFiles.ts +5 -28
- package/codeAgent/agent/CodeAgent.ts +33 -108
- package/codeAgent/agent/CodeAgentAsks.ts +7 -30
- package/codeAgent/agent/CodeAgentEventMapper.ts +9 -52
- package/codeAgent/agent/CodeAgentGate.ts +8 -34
- package/codeAgent/agent/CodeAgentProxy.ts +4 -13
- package/codeAgent/agent/CodeAgentRpcHost.ts +3 -16
- package/codeAgent/agent/CodeAgentRpcListener.ts +2 -10
- package/codeAgent/agent/CodeAgentStreamPrinter.ts +4 -15
- package/codeAgent/agent/CodeAgentSuspended.ts +1 -8
- package/codeAgent/agent/CodeAgentUi.ts +2 -7
- package/codeAgent/agent/CodeMailbox.ts +7 -34
- package/codeAgent/agent/CodeSessionFork.ts +4 -19
- package/codeAgent/agent/CodeSessionIndex.ts +5 -31
- package/codeAgent/agent/SubagentPool.ts +48 -58
- package/codeAgent/agent/akanCodeModel.ts +5 -39
- package/codeAgent/agent/akanCodePaths.ts +4 -24
- package/codeAgent/agent/akanContextFiles.test.ts +0 -2
- package/codeAgent/agent/akanSystemPrompt.ts +1 -9
- package/codeAgent/agent/codeAgent.test.ts +178 -0
- package/codeAgent/agent/codeAgentContract.test.ts +5 -28
- package/codeAgent/agent/codeMailbox.test.ts +0 -4
- package/codeAgent/agent/codeSessionFork.test.ts +0 -2
- package/codeAgent/agent/codeSessionIndex.test.ts +9 -4
- package/codeAgent/agent/consoleToStderr.ts +2 -12
- package/codeAgent/agent/jsonLines.ts +29 -0
- package/codeAgent/agent/stringArg.ts +5 -0
- package/codeAgent/feedback/DevLogFeedback.ts +3 -18
- package/codeAgent/feedback/PreviewChrome.ts +5 -29
- package/codeAgent/feedback/PreviewFeedback.ts +2 -9
- package/codeAgent/feedback/PreviewView.ts +3 -15
- package/codeAgent/feedback/TurnFeedback.ts +2 -17
- package/codeAgent/feedback/VerifyFeedback.ts +1 -7
- package/codeAgent/feedback/previewChrome.test.ts +1 -1
- package/codeAgent/index.ts +2 -10
- package/codeAgent/skills/akan-code/SKILL.md +12 -4
- package/codeAgent/tools/AkanCli.ts +4 -16
- package/codeAgent/tools/AkanCodePlugins.ts +21 -43
- package/codeAgent/tools/AkanEditScope.ts +2 -12
- package/codeAgent/tools/AkanEnvKeys.ts +3 -11
- package/codeAgent/tools/AkanToolPack.ts +6 -28
- package/codeAgent/tools/AkanVerifier.ts +1 -8
- package/codeAgent/tools/AskToolPack.ts +3 -15
- package/codeAgent/tools/MailToolPack.ts +0 -9
- package/codeAgent/tools/McpClient.ts +3 -24
- package/codeAgent/tools/McpOAuth.ts +6 -41
- package/codeAgent/tools/McpOAuthLoopback.ts +2 -15
- package/codeAgent/tools/McpServerConfig.ts +7 -26
- package/codeAgent/tools/McpSignIn.ts +46 -49
- package/codeAgent/tools/McpTokenStore.ts +6 -17
- package/codeAgent/tools/McpToolPack.ts +107 -35
- package/codeAgent/tools/SessionToolPack.ts +1 -11
- package/codeAgent/tools/WebToolPack.ts +1 -7
- package/codeAgent/tools/akanCodePlugins.test.ts +231 -63
- package/codeAgent/tools/askToolPack.test.ts +0 -3
- package/codeAgent/tools/mcpOAuth.test.ts +315 -27
- package/codeAgent/tools/mcpServerConfig.test.ts +21 -14
- package/codegenLock.test.ts +4 -13
- package/codegenLock.ts +3 -17
- package/commandDecorators/argMeta.ts +1 -5
- package/commandDecorators/camelToKebabCase.ts +1 -0
- package/commandDecorators/command.ts +44 -102
- package/commandDecorators/commandBuilder.ts +30 -61
- package/commandDecorators/commandDecorators.test.ts +1 -9
- package/commandDecorators/dependencyBuilder.ts +10 -1
- package/commandDecorators/helpFormatter.ts +66 -144
- package/commandDecorators/index.ts +0 -2
- package/commandDecorators/targetMeta.ts +9 -7
- package/createTunnel.ts +7 -14
- package/dependencyScanner.test.ts +4 -16
- package/dependencyScanner.ts +27 -78
- package/devkitUtils.test.ts +47 -19
- package/executors.test.ts +114 -60
- package/executors.ts +165 -484
- package/fileEditor.ts +9 -37
- package/{getDirname.test.ts → fileSys.test.ts} +1 -1
- package/fileSys.ts +6 -8
- package/formSetterScanner.ts +3 -16
- package/frontendBuild/allRoutesBuilder.ts +7 -21
- package/frontendBuild/autoImportSync.test.ts +14 -38
- package/frontendBuild/autoImportSync.ts +15 -67
- package/frontendBuild/buildRouteClient.test.ts +10 -36
- package/frontendBuild/bundleDefine.ts +12 -0
- package/frontendBuild/clientBuildTypes.ts +5 -36
- package/frontendBuild/clientEntriesBundler.ts +9 -40
- package/frontendBuild/clientEntryDiscovery.ts +6 -41
- package/frontendBuild/csrArtifactBuilder.ts +6 -25
- package/frontendBuild/cssCandidateCache.test.ts +0 -6
- package/frontendBuild/cssCandidateCache.ts +6 -41
- package/frontendBuild/cssCompiler.ts +29 -78
- package/frontendBuild/cssImportResolver.ts +5 -18
- package/frontendBuild/devChangePlanner.ts +7 -10
- package/frontendBuild/devGeneratedIndexSync.test.ts +12 -27
- package/frontendBuild/devGeneratedIndexSync.ts +1 -4
- package/frontendBuild/fontOptimizer.test.ts +5 -13
- package/frontendBuild/fontOptimizer.ts +15 -72
- package/frontendBuild/fontPruner.test.ts +5 -10
- package/frontendBuild/fontPruner.ts +5 -20
- package/frontendBuild/frontendBuild.test.ts +27 -52
- package/frontendBuild/hmrChangeClassifier.ts +2 -2
- package/frontendBuild/hmrWatcher.test.ts +7 -31
- package/frontendBuild/hmrWatcher.ts +14 -71
- package/frontendBuild/pagesBundleBuilder.ts +4 -29
- package/frontendBuild/precompressArtifacts.ts +5 -18
- package/frontendBuild/routeClientBuilder.ts +7 -47
- package/frontendBuild/routesManifestArtifactSerializer.ts +5 -36
- package/frontendBuild/sourceMtimeIndex.test.ts +37 -94
- package/frontendBuild/sourceMtimeIndex.ts +19 -130
- package/frontendBuild/ssrBaseArtifactBuilder.ts +2 -8
- package/frontendBuild/styleContract.ts +1 -8
- package/frontendBuild/themeValidator.ts +4 -26
- package/frontendBuild/watchRootResolver.test.ts +23 -42
- package/frontendBuild/watchRootResolver.ts +5 -27
- package/getRelatedCnsts.ts +12 -92
- package/incrementalBuilder/buildBatch.proc.ts +22 -57
- package/incrementalBuilder/buildBatchProtocol.ts +8 -36
- package/incrementalBuilder/buildBatchRunner.test.ts +34 -0
- package/incrementalBuilder/buildBatchRunner.ts +10 -31
- package/incrementalBuilder/builderChannel.test.ts +24 -49
- package/incrementalBuilder/builderChannel.ts +6 -37
- package/incrementalBuilder/builderRequestRouter.test.ts +0 -8
- package/incrementalBuilder/builderRequestRouter.ts +5 -24
- package/incrementalBuilder/devWatchBatch.test.ts +14 -18
- package/incrementalBuilder/incrementalBuilder.host.test.ts +18 -55
- package/incrementalBuilder/incrementalBuilder.host.ts +18 -76
- package/incrementalBuilder/incrementalBuilder.proc.test.ts +81 -0
- package/incrementalBuilder/incrementalBuilder.proc.ts +48 -161
- package/index.ts +3 -15
- package/integration/devResourceProbe.ts +50 -56
- package/integration/devStability.integration.test.ts +47 -194
- package/integration/devStabilityHarness.test.ts +9 -29
- package/integration/devStabilityHarness.ts +65 -330
- package/integration/ssrMemoryProbe.ts +41 -167
- package/libSource.test.ts +4 -15
- package/libSource.ts +19 -31
- package/lint/gritRules.test.ts +6 -23
- package/linter.test.ts +1 -2
- package/linter.ts +22 -115
- package/mobile/mobileTarget.ts +14 -13
- package/package.json +2 -2
- package/packageExports.test.ts +3 -18
- package/packageExportsMap.ts +3 -19
- package/piDependencyPins.test.ts +3 -14
- package/platformTest/IdleWatchedProcess.test.ts +5 -13
- package/platformTest/IdleWatchedProcess.ts +1 -5
- package/platformTest/LinuxDockerTarget.ts +20 -35
- package/platformTest/PlatformTestRun.test.ts +5 -9
- package/platformTest/PlatformTestTarget.ts +24 -2
- package/platformTest/TestSnapshot.test.ts +6 -14
- package/platformTest/TestSnapshot.ts +1 -5
- package/platformTest/WindowsSshTarget.ts +6 -22
- package/prompter.ts +3 -6
- package/qualityScanner.test.ts +6 -24
- package/qualityScanner.ts +196 -284
- package/recipeScanner.test.ts +7 -12
- package/recipeScanner.ts +9 -38
- package/repoIdentity.ts +2 -9
- package/routeSourceValidator.ts +7 -30
- package/scanInfo.ts +82 -214
- package/selectModel.ts +1 -2
- package/semver.ts +3 -5
- package/slicePlanner.test.ts +6 -24
- package/slicePlanner.ts +11 -32
- package/spinner.test.ts +3 -8
- package/spinner.ts +4 -16
- package/sshTunnel.ts +1 -6
- package/ssrScanner.test.ts +1 -6
- package/ssrScanner.ts +103 -113
- package/subspace.test.ts +6 -25
- package/subspace.ts +31 -109
- package/subspaceConfig.ts +3 -11
- package/testHelpers.ts +49 -34
- package/transforms/asyncDefaultExportDetector.ts +3 -11
- package/transforms/barrelAnalyzer.ts +43 -135
- package/transforms/barrelImportsPlugin.ts +38 -175
- package/transforms/externalizeFrameworkPlugin.test.ts +39 -118
- package/transforms/externalizeFrameworkPlugin.ts +13 -87
- package/transforms/moduleSyntax.ts +32 -0
- package/transforms/rscUseClientTransform.ts +35 -20
- package/transforms/transforms.test.ts +153 -44
- package/transforms/tsconfigPackageResolver.test.ts +6 -24
- package/transforms/useClientBundlePlugin.ts +2 -22
- package/typeChecker.ts +7 -63
- package/uploadRelease.ts +10 -25
- package/workflow/artifacts.ts +18 -0
- package/workflow/executor.test.ts +1 -12
- package/workflow/executor.ts +85 -146
- package/workflow/index.ts +0 -1
- package/workflow/moduleIndex.test.ts +4 -15
- package/workflow/moduleIndex.ts +9 -49
- package/workflow/plan.ts +18 -25
- package/workflow/render.ts +80 -96
- package/workflow/source.ts +33 -56
- package/workflow/sourceAst.ts +50 -0
- package/workspaceLayout.ts +4 -19
- package/commandDecorators/commandMeta.ts +0 -7
- package/commandDecorators/types.ts +0 -10
- package/getDirname.ts +0 -4
- package/local/optimize-resource/ipcprobe/child.ts +0 -1
- package/local/optimize-resource/ipcprobe/parent.ts +0 -11
- package/workflow/primitive.ts +0 -59
|
@@ -1,191 +1,119 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
|
|
3
3
|
import { type EnumChoice, getArgMetas } from "./argMeta";
|
|
4
|
+
import { camelToKebabCase } from "./camelToKebabCase";
|
|
4
5
|
import { type CommandCls, getTargetMetas } from "./targetMeta";
|
|
5
6
|
|
|
6
|
-
const camelToKebabCase = (str: string) => str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
7
7
|
const formatChoice = (choice: EnumChoice) => (typeof choice === "object" ? choice.label : choice.toString());
|
|
8
8
|
|
|
9
9
|
const groupCommands = (commands: CommandCls[]) => {
|
|
10
|
-
const groups = new Map<string, {
|
|
11
|
-
|
|
10
|
+
const groups = new Map<string, { key: string; args: string[]; desc?: string }[]>();
|
|
12
11
|
for (const command of commands) {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
if (!groups.has(groupName)) {
|
|
17
|
-
groups.set(groupName, { name: groupName, commands: [] });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const targetMetas = getTargetMetas(command);
|
|
21
|
-
for (const targetMeta of targetMetas) {
|
|
22
|
-
// Skip devOnly commands in help
|
|
12
|
+
const group = groups.getOrInsert(command.name.replace("Command", ""), []);
|
|
13
|
+
for (const targetMeta of getTargetMetas(command)) {
|
|
23
14
|
if (targetMeta.targetOption.devOnly) continue;
|
|
24
|
-
|
|
25
15
|
const [allArgMetas] = getArgMetas(command, targetMeta.key);
|
|
26
16
|
const args = allArgMetas
|
|
27
17
|
.filter((arg) => arg.type !== "Option")
|
|
28
18
|
.map((arg) => {
|
|
29
19
|
if (arg.type === "Workspace") return "";
|
|
30
20
|
if (arg.type === "Module") return "[sys:module]";
|
|
31
|
-
if (arg.type === "Argument") {
|
|
32
|
-
return `[${arg.name}]`;
|
|
33
|
-
}
|
|
21
|
+
if (arg.type === "Argument") return `[${arg.name}]`;
|
|
34
22
|
return `[${arg.type.toLowerCase()}]`;
|
|
35
23
|
})
|
|
36
24
|
.filter(Boolean);
|
|
37
|
-
|
|
38
|
-
const group = groups.get(groupName);
|
|
39
|
-
if (group) {
|
|
40
|
-
group.commands.push({
|
|
41
|
-
key: camelToKebabCase(targetMeta.key),
|
|
42
|
-
args,
|
|
43
|
-
desc: targetMeta.targetOption.desc,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
25
|
+
group.push({ key: camelToKebabCase(targetMeta.key), args, desc: targetMeta.targetOption.desc });
|
|
46
26
|
}
|
|
47
27
|
}
|
|
48
|
-
|
|
49
28
|
return groups;
|
|
50
29
|
};
|
|
51
30
|
|
|
52
31
|
export const formatHelp = (commands: CommandCls[], version: string) => {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// Header
|
|
57
|
-
lines.push("");
|
|
58
|
-
lines.push(chalk.bold.cyan(" ╔═══════════════════════════════════════════════════╗"));
|
|
59
|
-
lines.push(
|
|
32
|
+
const lines = [
|
|
33
|
+
"",
|
|
34
|
+
chalk.bold.cyan(" ╔═══════════════════════════════════════════════════╗"),
|
|
60
35
|
chalk.bold.cyan(" ║") +
|
|
61
36
|
chalk.bold.white(" Akan.js Framework CLI ") +
|
|
62
37
|
chalk.bold.cyan(" ║"),
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
lines.push(chalk.bold.magenta(` ${groupName}`));
|
|
84
|
-
lines.push("");
|
|
85
|
-
|
|
86
|
-
for (const cmd of group.commands) {
|
|
87
|
-
const cmdName = chalk.green(cmd.key);
|
|
88
|
-
const cmdArgs = cmd.args.length > 0 ? chalk.gray(` ${cmd.args.join(" ")}`) : "";
|
|
89
|
-
|
|
90
|
-
// Format description: wrap if too long
|
|
91
|
-
if (cmd.desc) {
|
|
92
|
-
const maxLineLength = 70;
|
|
93
|
-
const cmdPrefix = ` ${cmdName}${cmdArgs}`;
|
|
94
|
-
const indent = " ";
|
|
95
|
-
|
|
96
|
-
if (cmdPrefix.length + cmd.desc.length + 3 < maxLineLength) {
|
|
97
|
-
// Single line
|
|
98
|
-
lines.push(`${cmdPrefix} ${chalk.gray(cmd.desc)}`);
|
|
99
|
-
} else {
|
|
100
|
-
// Multi-line
|
|
101
|
-
lines.push(cmdPrefix);
|
|
102
|
-
lines.push(`${indent}${chalk.gray(cmd.desc)}`);
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
lines.push(` ${cmdName}${cmdArgs}`);
|
|
106
|
-
}
|
|
38
|
+
chalk.bold.cyan(" ╚═══════════════════════════════════════════════════╝"),
|
|
39
|
+
"",
|
|
40
|
+
chalk.gray(` Version: ${version}`),
|
|
41
|
+
"",
|
|
42
|
+
chalk.bold.yellow(" USAGE"),
|
|
43
|
+
"",
|
|
44
|
+
chalk.gray(" $ ") + chalk.white("akan") + chalk.gray(" <command> [options]"),
|
|
45
|
+
"",
|
|
46
|
+
chalk.bold.yellow(" COMMANDS"),
|
|
47
|
+
"",
|
|
48
|
+
];
|
|
49
|
+
for (const [groupName, cmds] of groupCommands(commands)) {
|
|
50
|
+
if (cmds.length === 0) continue;
|
|
51
|
+
lines.push(chalk.bold.magenta(` ${groupName}`), "");
|
|
52
|
+
for (const cmd of cmds) {
|
|
53
|
+
const cmdPrefix = ` ${chalk.green(cmd.key)}${cmd.args.length > 0 ? chalk.gray(` ${cmd.args.join(" ")}`) : ""}`;
|
|
54
|
+
if (!cmd.desc) lines.push(cmdPrefix);
|
|
55
|
+
else if (cmdPrefix.length + cmd.desc.length + 3 < 70) lines.push(`${cmdPrefix} ${chalk.gray(cmd.desc)}`);
|
|
56
|
+
else lines.push(cmdPrefix, ` ${chalk.gray(cmd.desc)}`);
|
|
107
57
|
}
|
|
108
58
|
lines.push("");
|
|
109
59
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// Footer
|
|
133
|
-
lines.push(chalk.gray(" Documentation: ") + chalk.cyan("https://akanjs.com/docs"));
|
|
134
|
-
lines.push(chalk.gray(" Report issues: ") + chalk.cyan("https://github.com/akan-team/akanjs/issues"));
|
|
135
|
-
lines.push("");
|
|
136
|
-
|
|
60
|
+
lines.push(
|
|
61
|
+
chalk.bold.yellow(" OPTIONS"),
|
|
62
|
+
"",
|
|
63
|
+
` ${chalk.green("-v, --verbose")} ${chalk.gray("Enable verbose output")}`,
|
|
64
|
+
` ${chalk.green("-h, --help")} ${chalk.gray("Display this help message")}`,
|
|
65
|
+
` ${chalk.green("-V, --version")} ${chalk.gray("Output version number")}`,
|
|
66
|
+
"",
|
|
67
|
+
chalk.bold.yellow(" EXAMPLES"),
|
|
68
|
+
"",
|
|
69
|
+
chalk.gray(" # Create a new workspace"),
|
|
70
|
+
chalk.white(" $ akan create-workspace myproject"),
|
|
71
|
+
"",
|
|
72
|
+
chalk.gray(" # Start development server"),
|
|
73
|
+
chalk.white(" $ akan start myapp"),
|
|
74
|
+
"",
|
|
75
|
+
chalk.gray(" # Create a new module"),
|
|
76
|
+
chalk.white(" $ akan create-module userProfile"),
|
|
77
|
+
"",
|
|
78
|
+
chalk.gray(" Documentation: ") + chalk.cyan("https://akanjs.com/docs"),
|
|
79
|
+
chalk.gray(" Report issues: ") + chalk.cyan("https://github.com/akan-team/akanjs/issues"),
|
|
80
|
+
"",
|
|
81
|
+
);
|
|
137
82
|
return lines.join("\n");
|
|
138
83
|
};
|
|
139
84
|
|
|
140
85
|
export const formatCommandHelp = (command: CommandCls, key: string) => {
|
|
141
|
-
const [allArgMetas,
|
|
86
|
+
const [allArgMetas, optionArgs] = getArgMetas(command, key);
|
|
142
87
|
const kebabKey = camelToKebabCase(key);
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
const targetMeta = targetMetas.find((t) => t.key === key);
|
|
147
|
-
const commandDesc = targetMeta?.targetOption.desc;
|
|
148
|
-
|
|
149
|
-
lines.push("");
|
|
150
|
-
lines.push(chalk.bold.cyan(` Command: ${kebabKey}`));
|
|
151
|
-
if (commandDesc) {
|
|
152
|
-
lines.push(chalk.gray(` ${commandDesc}`));
|
|
153
|
-
}
|
|
154
|
-
lines.push("");
|
|
155
|
-
|
|
156
|
-
// Usage
|
|
157
|
-
const args = allArgMetas
|
|
158
|
-
.filter((arg) => arg.type !== "Option")
|
|
88
|
+
const commandDesc = getTargetMetas(command).find((t) => t.key === key)?.targetOption.desc;
|
|
89
|
+
const nonOptionArgs = allArgMetas.filter((arg) => arg.type !== "Option");
|
|
90
|
+
const args = nonOptionArgs
|
|
159
91
|
.map((arg) => {
|
|
160
92
|
if (arg.type === "Workspace") return "";
|
|
161
93
|
if (arg.type === "Module") return "[sys:module]";
|
|
162
94
|
if (arg.type === "Apps") return "[apps...]";
|
|
163
|
-
if (arg.type === "Argument") {
|
|
164
|
-
return `[${camelToKebabCase(arg.name)}]`;
|
|
165
|
-
}
|
|
95
|
+
if (arg.type === "Argument") return `[${camelToKebabCase(arg.name)}]`;
|
|
166
96
|
return `[${arg.type.toLowerCase()}]`;
|
|
167
97
|
})
|
|
168
98
|
.filter(Boolean)
|
|
169
99
|
.join(" ");
|
|
170
100
|
|
|
171
|
-
lines
|
|
172
|
-
lines.push(
|
|
173
|
-
lines.push(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
101
|
+
const lines = ["", chalk.bold.cyan(` Command: ${kebabKey}`)];
|
|
102
|
+
if (commandDesc) lines.push(chalk.gray(` ${commandDesc}`));
|
|
103
|
+
lines.push(
|
|
104
|
+
"",
|
|
105
|
+
chalk.bold.yellow(" USAGE"),
|
|
106
|
+
"",
|
|
107
|
+
chalk.gray(" $ ") + chalk.white(`akan ${kebabKey}`) + (args ? chalk.gray(` ${args}`) : ""),
|
|
108
|
+
"",
|
|
109
|
+
);
|
|
178
110
|
if (nonOptionArgs.length > 0) {
|
|
179
|
-
lines.push(chalk.bold.yellow(" ARGUMENTS"));
|
|
180
|
-
lines.push("");
|
|
181
|
-
|
|
111
|
+
lines.push(chalk.bold.yellow(" ARGUMENTS"), "");
|
|
182
112
|
for (const arg of nonOptionArgs) {
|
|
183
113
|
if (arg.type === "Workspace") continue;
|
|
184
|
-
|
|
185
114
|
let argName: string;
|
|
186
115
|
let argDesc: string;
|
|
187
116
|
let example = "";
|
|
188
|
-
|
|
189
117
|
if (arg.type === "Argument") {
|
|
190
118
|
argName = camelToKebabCase(arg.name);
|
|
191
119
|
argDesc = arg.argsOption.desc ?? "";
|
|
@@ -200,19 +128,13 @@ export const formatCommandHelp = (command: CommandCls, key: string) => {
|
|
|
200
128
|
argName = arg.type.toLowerCase();
|
|
201
129
|
argDesc = `${arg.type} name in this workspace`;
|
|
202
130
|
}
|
|
203
|
-
|
|
204
131
|
lines.push(` ${chalk.green(argName)} ${chalk.gray(argDesc)}${example}`);
|
|
205
132
|
}
|
|
206
|
-
|
|
207
133
|
lines.push("");
|
|
208
134
|
}
|
|
209
135
|
|
|
210
|
-
// Options
|
|
211
|
-
const optionArgs = argMetas.filter((a) => a.type === "Option");
|
|
212
136
|
if (optionArgs.length > 0) {
|
|
213
|
-
lines.push(chalk.bold.yellow(" OPTIONS"));
|
|
214
|
-
lines.push("");
|
|
215
|
-
|
|
137
|
+
lines.push(chalk.bold.yellow(" OPTIONS"), "");
|
|
216
138
|
for (const arg of optionArgs) {
|
|
217
139
|
const opt = arg.argsOption;
|
|
218
140
|
const flag = opt.flag ? `-${opt.flag}, ` : "";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ArgMeta, InternalArgMeta } from "./argMeta";
|
|
2
|
-
import
|
|
2
|
+
import { camelToKebabCase } from "./camelToKebabCase";
|
|
3
|
+
import type { Cls, DependencyCls } from "./dependencyBuilder";
|
|
3
4
|
|
|
4
5
|
export const COMMAND_META: unique symbol = Symbol("akan.command.meta");
|
|
5
6
|
|
|
@@ -22,12 +23,7 @@ export const getTargetMetas = (command: CommandCls): TargetMeta[] => {
|
|
|
22
23
|
return [...targetMetaMap.values()];
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* CLI names a target answers to. Shared with the command-manifest generator so a lazily-loaded CLI
|
|
29
|
-
* resolves `argv[2]` to the same module that `runCommands` would have registered it under.
|
|
30
|
-
*/
|
|
26
|
+
/** Shared with the command-manifest generator, so a lazily loaded CLI maps argv[2] to the module runCommands would. */
|
|
31
27
|
export const getTargetCommandNames = (targetMeta: TargetMeta): string[] => {
|
|
32
28
|
const kebabKey = camelToKebabCase(targetMeta.key);
|
|
33
29
|
if (targetMeta.targetOption.short !== true) return [kebabKey];
|
|
@@ -48,3 +44,9 @@ export interface TargetOption {
|
|
|
48
44
|
runsOnWorkspaceRoot?: boolean;
|
|
49
45
|
stdio?: boolean;
|
|
50
46
|
}
|
|
47
|
+
|
|
48
|
+
export const Commands = () => {
|
|
49
|
+
return (target: Cls) => {
|
|
50
|
+
// not implemented yet
|
|
51
|
+
};
|
|
52
|
+
};
|
package/createTunnel.ts
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
import type { SshOptions } from "akanjs/base";
|
|
2
|
-
|
|
3
1
|
import { type AppExecutor, WorkspaceExecutor } from "./executors";
|
|
4
2
|
import { createSshTunnel } from "./sshTunnel";
|
|
5
3
|
|
|
6
|
-
const getSshTunnelOptions = (app: AppExecutor, environment: string): SshOptions => {
|
|
7
|
-
const { serveDomain, repoName } = WorkspaceExecutor.getBaseDevEnv();
|
|
8
|
-
return {
|
|
9
|
-
host: `${app.name}-${environment}.${serveDomain}`,
|
|
10
|
-
port: process.env.SSH_TUNNEL_PORT ? parseInt(process.env.SSH_TUNNEL_PORT) : 32767,
|
|
11
|
-
username: process.env.SSH_TUNNEL_USERNAME ?? "root",
|
|
12
|
-
password: process.env.SSH_TUNNEL_PASSWORD ?? repoName,
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
|
|
16
4
|
interface TunnelOption {
|
|
17
5
|
app: AppExecutor;
|
|
18
6
|
environment: string;
|
|
@@ -22,7 +10,7 @@ export const createTunnel = async (
|
|
|
22
10
|
service: "redis" | "postgres",
|
|
23
11
|
{ app, environment, port = service === "postgres" ? 5432 : 6379 }: TunnelOption,
|
|
24
12
|
) => {
|
|
25
|
-
const
|
|
13
|
+
const { serveDomain, repoName } = WorkspaceExecutor.getBaseDevEnv();
|
|
26
14
|
await createSshTunnel({
|
|
27
15
|
localHost: "0.0.0.0",
|
|
28
16
|
localPort: port,
|
|
@@ -30,7 +18,12 @@ export const createTunnel = async (
|
|
|
30
18
|
srcPort: port,
|
|
31
19
|
dstHost: `${service}-0.${service}-svc.${app.name}-${environment}.svc.cluster.local`,
|
|
32
20
|
dstPort: service === "postgres" ? 5432 : 6379,
|
|
33
|
-
sshOptions
|
|
21
|
+
sshOptions: {
|
|
22
|
+
host: `${app.name}-${environment}.${serveDomain}`,
|
|
23
|
+
port: process.env.SSH_TUNNEL_PORT ? parseInt(process.env.SSH_TUNNEL_PORT) : 32767,
|
|
24
|
+
username: process.env.SSH_TUNNEL_USERNAME ?? "root",
|
|
25
|
+
password: process.env.SSH_TUNNEL_PASSWORD ?? repoName,
|
|
26
|
+
},
|
|
34
27
|
});
|
|
35
28
|
return `localhost:${port}`;
|
|
36
29
|
};
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
4
2
|
import path from "node:path";
|
|
5
3
|
import { TypeScriptDependencyScanner } from "./dependencyScanner";
|
|
4
|
+
import { tempDirs, writeText } from "./testHelpers";
|
|
6
5
|
import type { PackageJson } from "./types";
|
|
7
6
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const makeTempRoot = async () => {
|
|
11
|
-
const root = await mkdtemp(path.join(os.tmpdir(), "akan-devkit-depscan-"));
|
|
12
|
-
tempRoots.push(root);
|
|
13
|
-
return root;
|
|
14
|
-
};
|
|
7
|
+
const makeTempRoot = tempDirs("akan-devkit-depscan-");
|
|
15
8
|
|
|
16
9
|
const write = async (root: string, relPath: string, content: string) => {
|
|
17
10
|
const filePath = path.join(root, relPath);
|
|
18
|
-
await
|
|
19
|
-
await writeFile(filePath, content);
|
|
11
|
+
await writeText(filePath, content);
|
|
20
12
|
return filePath;
|
|
21
13
|
};
|
|
22
14
|
|
|
@@ -27,10 +19,6 @@ const scannerFor = async (root: string, dependencies: Record<string, string> = {
|
|
|
27
19
|
rootPackageJson: { dependencies } as unknown as PackageJson,
|
|
28
20
|
});
|
|
29
21
|
|
|
30
|
-
afterEach(async () => {
|
|
31
|
-
await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
32
|
-
});
|
|
33
|
-
|
|
34
22
|
describe("TypeScriptDependencyScanner — getPackageBuildDependencies", () => {
|
|
35
23
|
test("collects imports from ordinary source files", async () => {
|
|
36
24
|
const root = await makeTempRoot();
|
package/dependencyScanner.ts
CHANGED
|
@@ -7,8 +7,7 @@ import { FileSys } from "./fileSys";
|
|
|
7
7
|
import type { PackageJson, TsConfigJson } from "./types";
|
|
8
8
|
|
|
9
9
|
const testFileRegex = /\.(?:test|spec)\.[cm]?[tj]sx?$/;
|
|
10
|
-
// `__fixtures__` holds deliberately invalid
|
|
11
|
-
// biome's `!` override already skip them, and their imports are violations rather than real dependencies.
|
|
10
|
+
// `__fixtures__` holds deliberately invalid lint-rule samples, whose imports are violations, not dependencies.
|
|
12
11
|
const skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android", "__fixtures__"];
|
|
13
12
|
const isSkippedPath = (filePath: string) => {
|
|
14
13
|
const posixPath = filePath.split(path.sep).join("/");
|
|
@@ -75,11 +74,8 @@ export class TypeScriptDependencyScanner {
|
|
|
75
74
|
): Promise<{ npmDeps: string[]; npmDevDeps: string[]; missingDeps: string[] }> {
|
|
76
75
|
const runtimeDeps = new Set<string>();
|
|
77
76
|
const devDeps = new Set<string>();
|
|
78
|
-
const sourceFiles = await this.#
|
|
79
|
-
|
|
80
|
-
excludeTestFiles: true,
|
|
81
|
-
});
|
|
82
|
-
const cssFiles = await this.#findCssFiles(this.#directory);
|
|
77
|
+
const sourceFiles = await this.#findFiles("**/*.{ts,tsx}", { excludeBuildFiles: true, excludeTestFiles: true });
|
|
78
|
+
const cssFiles = await this.#findFiles("**/*.css");
|
|
83
79
|
|
|
84
80
|
for (const filePath of sourceFiles) {
|
|
85
81
|
const fileContent = await FileSys.readText(filePath);
|
|
@@ -135,25 +131,19 @@ export class TypeScriptDependencyScanner {
|
|
|
135
131
|
depSets: DepSets,
|
|
136
132
|
fileDependencies: Map<string, string[]>,
|
|
137
133
|
): DepSets {
|
|
138
|
-
const importedDepSets = new
|
|
139
|
-
for (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (depSets[j]?.has(importName)) {
|
|
150
|
-
importedDepSets[j]?.add(importName);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
134
|
+
const importedDepSets = depSets.map(() => new Set<string>());
|
|
135
|
+
for (const imps of fileDependencies.values())
|
|
136
|
+
for (const imp of imps) {
|
|
137
|
+
if (imp.startsWith(".")) continue;
|
|
138
|
+
const parts = imp.split("/");
|
|
139
|
+
for (let length = 1; length <= parts.length; length++) {
|
|
140
|
+
const importName = parts.slice(0, length).join("/");
|
|
141
|
+
const setIndex = depSets.findIndex((depSet) => depSet.has(importName));
|
|
142
|
+
if (setIndex === -1) continue;
|
|
143
|
+
importedDepSets[setIndex]?.add(importName);
|
|
144
|
+
break;
|
|
154
145
|
}
|
|
155
|
-
}
|
|
156
|
-
});
|
|
146
|
+
}
|
|
157
147
|
return importedDepSets as DepSets;
|
|
158
148
|
}
|
|
159
149
|
|
|
@@ -163,48 +153,24 @@ export class TypeScriptDependencyScanner {
|
|
|
163
153
|
this.#fileTypeDependencies.clear();
|
|
164
154
|
this.#visitedFiles.clear();
|
|
165
155
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
for (const file of files) await this.#analyzeFile(file, this.#directory);
|
|
169
|
-
|
|
156
|
+
for (const file of await this.#findFiles("**/*.{ts,tsx}")) await this.#analyzeFile(file, this.#directory);
|
|
170
157
|
return this.#fileDependencies;
|
|
171
158
|
}
|
|
172
159
|
|
|
173
|
-
async #
|
|
174
|
-
|
|
160
|
+
async #findFiles(
|
|
161
|
+
pattern: string,
|
|
175
162
|
{
|
|
176
163
|
excludeBuildFiles = false,
|
|
177
164
|
excludeTestFiles = false,
|
|
178
165
|
}: { excludeBuildFiles?: boolean; excludeTestFiles?: boolean } = {},
|
|
179
166
|
): Promise<string[]> {
|
|
180
167
|
const files: string[] = [];
|
|
181
|
-
|
|
182
|
-
const glob = new Bun.Glob("**/*.{ts,tsx}");
|
|
183
|
-
for await (const filePath of glob.scan({ cwd: directory, onlyFiles: true })) {
|
|
168
|
+
for await (const filePath of new Bun.Glob(pattern).scan({ cwd: this.#directory, onlyFiles: true })) {
|
|
184
169
|
if (isSkippedPath(filePath)) continue;
|
|
185
170
|
if (excludeBuildFiles && filePath === "build.ts") continue;
|
|
186
171
|
if (excludeTestFiles && testFileRegex.test(filePath)) continue;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const relativePath = path.relative(this.#workspaceRoot, fullPath);
|
|
190
|
-
if (this.#ig.ignores(relativePath)) continue;
|
|
191
|
-
|
|
192
|
-
files.push(fullPath);
|
|
193
|
-
}
|
|
194
|
-
return files;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async #findCssFiles(directory: string): Promise<string[]> {
|
|
198
|
-
const files: string[] = [];
|
|
199
|
-
const glob = new Bun.Glob("**/*.css");
|
|
200
|
-
for await (const filePath of glob.scan({ cwd: directory, onlyFiles: true })) {
|
|
201
|
-
if (isSkippedPath(filePath)) continue;
|
|
202
|
-
|
|
203
|
-
const fullPath = path.join(directory, filePath);
|
|
204
|
-
const relativePath = path.relative(this.#workspaceRoot, fullPath);
|
|
205
|
-
if (this.#ig.ignores(relativePath)) continue;
|
|
206
|
-
|
|
207
|
-
files.push(fullPath);
|
|
172
|
+
const fullPath = path.join(this.#directory, filePath);
|
|
173
|
+
if (!this.#ig.ignores(path.relative(this.#workspaceRoot, fullPath))) files.push(fullPath);
|
|
208
174
|
}
|
|
209
175
|
return files;
|
|
210
176
|
}
|
|
@@ -217,12 +183,8 @@ export class TypeScriptDependencyScanner {
|
|
|
217
183
|
try {
|
|
218
184
|
const fileContent = await FileSys.readText(filePath);
|
|
219
185
|
const { imports, typeImports } = this.#extractImports(fileContent, filePath);
|
|
220
|
-
|
|
221
|
-
// Convert imports to absolute or relative paths
|
|
222
186
|
const resolvedImports = await this.#resolveImports(imports, filePath, baseDir);
|
|
223
187
|
const resolvedTypeImports = await this.#resolveImports(typeImports, filePath, baseDir);
|
|
224
|
-
|
|
225
|
-
// Store the dependencies
|
|
226
188
|
const relativePath = path.relative(baseDir, filePath);
|
|
227
189
|
this.#fileDependencies.set(relativePath, [...new Set([...resolvedImports, ...resolvedTypeImports])]);
|
|
228
190
|
this.#fileRuntimeDependencies.set(relativePath, resolvedImports);
|
|
@@ -235,12 +197,8 @@ export class TypeScriptDependencyScanner {
|
|
|
235
197
|
async #resolveImports(imports: string[], filePath: string, baseDir: string): Promise<string[]> {
|
|
236
198
|
return await Promise.all(
|
|
237
199
|
imports.map(async (importPath) => {
|
|
238
|
-
if (importPath.startsWith("."))
|
|
239
|
-
|
|
240
|
-
const resolvedPath = `./${path.join(path.relative(baseDir, filePath), importPath)}`;
|
|
241
|
-
return await this.#ensureExtension(resolvedPath);
|
|
242
|
-
}
|
|
243
|
-
return importPath; // Keep package imports as is
|
|
200
|
+
if (!importPath.startsWith(".")) return importPath;
|
|
201
|
+
return await this.#ensureExtension(`./${path.join(path.relative(baseDir, filePath), importPath)}`);
|
|
244
202
|
}),
|
|
245
203
|
);
|
|
246
204
|
}
|
|
@@ -326,19 +284,10 @@ export class TypeScriptDependencyScanner {
|
|
|
326
284
|
const projectImports = imports.filter((i) => !i.startsWith("react") && !i.startsWith("@"));
|
|
327
285
|
const externalImports = imports.filter((i) => i.startsWith("react") || i.startsWith("@"));
|
|
328
286
|
|
|
329
|
-
if (projectImports.length > 0)
|
|
330
|
-
graph +=
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (externalImports.length > 0) {
|
|
337
|
-
graph += " External dependencies:\n";
|
|
338
|
-
externalImports.forEach((imp) => {
|
|
339
|
-
graph += ` → ${imp}\n`;
|
|
340
|
-
});
|
|
341
|
-
}
|
|
287
|
+
if (projectImports.length > 0)
|
|
288
|
+
graph += ` Project dependencies:\n${projectImports.map((imp) => ` → ${imp}\n`).join("")}`;
|
|
289
|
+
if (externalImports.length > 0)
|
|
290
|
+
graph += ` External dependencies:\n${externalImports.map((imp) => ` → ${imp}\n`).join("")}`;
|
|
342
291
|
|
|
343
292
|
graph += "\n";
|
|
344
293
|
}
|
package/devkitUtils.test.ts
CHANGED
|
@@ -1,29 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import os from "node:os";
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { realpath } from "node:fs/promises";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import { ApplicationBuildReporter } from "./applicationBuildReporter";
|
|
6
5
|
import { resolveSignalTestPreloadPath } from "./applicationTestPreload";
|
|
7
6
|
import { TypeScriptDependencyScanner } from "./dependencyScanner";
|
|
8
7
|
import { AppExecutor, WorkspaceExecutor } from "./executors";
|
|
8
|
+
import { tempDirs, writeText as write } from "./testHelpers";
|
|
9
9
|
import type { PackageJson, TsConfigJson } from "./types";
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const makeTempRoot = async () => {
|
|
14
|
-
const root = await mkdtemp(path.join(os.tmpdir(), "akan-devkit-utils-"));
|
|
15
|
-
tempRoots.push(root);
|
|
16
|
-
return root;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const write = async (filePath: string, content: string) => {
|
|
20
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
21
|
-
await writeFile(filePath, content);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
afterEach(async () => {
|
|
25
|
-
await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
26
|
-
});
|
|
11
|
+
const makeTempRoot = tempDirs("akan-devkit-utils-");
|
|
27
12
|
|
|
28
13
|
describe("resolveSignalTestPreloadPath", () => {
|
|
29
14
|
test("resolves the preload file from an installed akanjs package", async () => {
|
|
@@ -213,4 +198,47 @@ describe("ApplicationBuildReporter", () => {
|
|
|
213
198
|
["failed", " first", " second", " third"].join("\n"),
|
|
214
199
|
);
|
|
215
200
|
});
|
|
201
|
+
|
|
202
|
+
test("says where the bundler placed each reason, relative to the workspace root", async () => {
|
|
203
|
+
const root = await makeTempRoot();
|
|
204
|
+
const refuseWith = (message: string) => ({
|
|
205
|
+
name: "refuse",
|
|
206
|
+
setup: (build: Bun.PluginBuilder) => {
|
|
207
|
+
build.onLoad({ filter: /plugged\.ts$/ }, () => {
|
|
208
|
+
throw new Error(message);
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
const failureOf = (entry: string, plugins: Bun.BunPlugin[] = []) =>
|
|
213
|
+
Bun.build({ entrypoints: [path.join(root, entry)], plugins }).then(
|
|
214
|
+
() => null,
|
|
215
|
+
(error: unknown) => error,
|
|
216
|
+
);
|
|
217
|
+
await write(
|
|
218
|
+
path.join(root, "src/entry.ts"),
|
|
219
|
+
'export const a = 1;\nimport { gone } from "./not-there";\nexport const b = gone;\n',
|
|
220
|
+
);
|
|
221
|
+
await write(path.join(root, "src/plugged.ts"), "export const b = 1;\n");
|
|
222
|
+
|
|
223
|
+
const unresolved = await failureOf("src/entry.ts");
|
|
224
|
+
expect(ApplicationBuildReporter.formatError(unresolved, root)).toBe(
|
|
225
|
+
["Bundle failed", ' Could not resolve: "./not-there" (src/entry.ts:2:22)'].join("\n"),
|
|
226
|
+
);
|
|
227
|
+
const outside = path.join(await realpath(root), "src/entry.ts");
|
|
228
|
+
expect(ApplicationBuildReporter.formatError(unresolved, path.join(root, "elsewhere"))).toBe(
|
|
229
|
+
["Bundle failed", ` Could not resolve: "./not-there" (${outside}:2:22)`].join("\n"),
|
|
230
|
+
);
|
|
231
|
+
expect(
|
|
232
|
+
ApplicationBuildReporter.formatError(
|
|
233
|
+
await failureOf("src/plugged.ts", [refuseWith("refused\nsecond line")]),
|
|
234
|
+
root,
|
|
235
|
+
),
|
|
236
|
+
).toBe(["Bundle failed", " refused (src/plugged.ts)", " second line"].join("\n"));
|
|
237
|
+
expect(
|
|
238
|
+
ApplicationBuildReporter.formatError(
|
|
239
|
+
await failureOf("src/plugged.ts", [refuseWith("src/plugged.ts is refused")]),
|
|
240
|
+
root,
|
|
241
|
+
),
|
|
242
|
+
).toBe(["Bundle failed", " src/plugged.ts is refused"].join("\n"));
|
|
243
|
+
});
|
|
216
244
|
});
|