nolo-cli 0.1.32 → 0.1.34
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/README.md +4 -10
- package/agent-runtime/agentRecordConfig.ts +10 -0
- package/agent-runtime/hostAdapter.ts +10 -1
- package/agent-runtime/index.ts +9 -20
- package/agent-runtime/localLoop.ts +49 -2
- package/agent-runtime/localToolPolicy.ts +76 -34
- package/agent-runtime/localWorkspaceTools.ts +30 -333
- package/agent-runtime/openAiCompatibleProvider.ts +7 -3
- package/agent-runtime/openAiCompatibleProviderConfig.ts +15 -26
- package/agent-runtime/platformChatProvider.ts +47 -73
- package/agent-runtime/providerResolution.ts +244 -0
- package/agent-runtime/runtimeToolPolicy.ts +77 -29
- package/agent-runtime/shellCommandPolicy.ts +120 -0
- package/agentAliases.ts +14 -83
- package/agentCommandSupport.ts +3 -6
- package/agentInternalCommandEntries.ts +4 -13
- package/agentListCommands.ts +18 -27
- package/agentMachineCommands.ts +40 -336
- package/agentPullCommand.ts +30 -55
- package/agentRecordCommands.ts +84 -1
- package/agentRecordHelpers.ts +102 -186
- package/agentRunCommand.ts +438 -107
- package/agentRuntimeLocal.ts +2 -9
- package/ai/agent/cliExecutor.ts +19 -323
- package/ai/tools/toolNameAliases.ts +70 -0
- package/authCommands.ts +2 -36
- package/cli/agentAliases.ts +14 -83
- package/cli/agentCommandSupport.ts +3 -6
- package/cli/agentInternalCommandEntries.ts +4 -13
- package/cli/agentListCommands.ts +18 -27
- package/cli/agentMachineCommands.ts +40 -336
- package/cli/agentPullCommand.ts +30 -55
- package/cli/agentRecordCommands.ts +84 -1
- package/cli/agentRecordHelpers.ts +102 -186
- package/cli/agentRunCommand.ts +438 -107
- package/cli/agentRuntimeLocal.ts +2 -9
- package/cli/authCommands.ts +2 -36
- package/cli/cliCommandDispatch.ts +2 -2
- package/cli/cliEnvHelpers.ts +34 -107
- package/cli/client/agentRun.ts +854 -57
- package/cli/client/localRuntimeAdapter.ts +59 -159
- package/cli/client/streamingOutput.ts +3 -1
- package/cli/client/taskRunPrompt.ts +24 -7
- package/cli/commandRegistry.ts +4 -5
- package/cli/connectorRunArtifact.ts +10 -34
- package/cli/connectorWebSocketTarget.ts +6 -10
- package/cli/internalCommandEntries.ts +0 -8
- package/cli/localRuntimeDb.ts +2 -39
- package/cli/machineCommands.ts +189 -190
- package/cli/machineDaemonCommands.ts +165 -9
- package/cli/machineHeartbeatCommands.ts +2 -1
- package/cli/machineStatusCommands.ts +13 -5
- package/cli/machineWatchCommands.ts +1 -1
- package/cli/machineWsRunDispatch.ts +30 -44
- package/cli/machineWsSession.ts +0 -2
- package/cli/offlineMarxistsAgentCommand.ts +314 -0
- package/cli/runtimeDoctorCommands.ts +72 -15
- package/cli/scriptCommandEntries.ts +45 -5
- package/cli/tableCommands.ts +133 -33
- package/cli/taskRunCommand.ts +211 -16
- package/cli/tui/session.ts +372 -43
- package/cli/workflowInternalCommandEntries.ts +0 -20
- package/cliCommandDispatch.ts +2 -2
- package/cliEnvHelpers.ts +34 -107
- package/client/agentConfigResolver.test.ts +2 -0
- package/client/agentRun.test.ts +12 -208
- package/client/agentRun.ts +854 -57
- package/client/localProviderResolver.test.ts +26 -2
- package/client/localRuntimeAdapter.test.ts +296 -171
- package/client/localRuntimeAdapter.ts +59 -159
- package/client/localToolPolicy.test.ts +4 -28
- package/client/streamingOutput.ts +3 -1
- package/client/taskRunPrompt.ts +24 -7
- package/commandRegistry.ts +4 -5
- package/connectorRunArtifact.ts +10 -34
- package/connectorWebSocketTarget.ts +6 -10
- package/database/server/serverStoreFactory.ts +2 -8
- package/internalCommandEntries.ts +0 -8
- package/localRuntimeDb.ts +2 -39
- package/machineCommands.ts +189 -190
- package/machineDaemonCommands.ts +165 -9
- package/machineHeartbeatCommands.ts +2 -1
- package/machineStatusCommands.ts +13 -5
- package/machineWatchCommands.ts +1 -1
- package/machineWsRunDispatch.ts +30 -44
- package/machineWsSession.ts +0 -2
- package/offlineMarxistsAgentCommand.ts +314 -0
- package/package.json +52 -188
- package/runtimeDoctorCommands.ts +72 -15
- package/scriptCommandEntries.ts +45 -5
- package/tableCommands.ts +133 -33
- package/taskRunCommand.ts +211 -16
- package/tui/session.ts +372 -43
- package/workflowInternalCommandEntries.ts +0 -20
- package/agent-runtime/dialogStatus.ts +0 -139
- package/agent-runtime/hostRuntimeConfig.ts +0 -86
- package/agentCreateCustomCommands.ts +0 -278
- package/agentDialogsCommands.ts +0 -227
- package/agentDoctorCommands.ts +0 -203
- package/agentRunLocalWorkspace.ts +0 -182
- package/agentRunParsing.ts +0 -298
- package/agentSuperviseCommands.ts +0 -8
- package/agentUnpublishCommands.ts +0 -113
- package/ai/agent/agentRunDialogLineage.ts +0 -56
- package/ai/policy/types.ts +0 -64
- package/ai/skills/skillSummaryMarker.ts +0 -26
- package/app/types.ts +0 -358
- package/build.ts +0 -16
- package/buildPublish.ts +0 -138
- package/buildPublishArtifactAssembly.ts +0 -724
- package/buildPublishImportAnalysis.ts +0 -242
- package/chat/messages/fetchMessages.ts +0 -84
- package/chat/messages/types.ts +0 -185
- package/cli/agentCreateCustomCommands.ts +0 -278
- package/cli/agentDialogsCommands.ts +0 -227
- package/cli/agentDoctorCommands.ts +0 -203
- package/cli/agentRunLocalWorkspace.ts +0 -182
- package/cli/agentRunParsing.ts +0 -298
- package/cli/agentSuperviseCommands.ts +0 -8
- package/cli/agentUnpublishCommands.ts +0 -113
- package/cli/buildPublish.ts +0 -138
- package/cli/buildPublishArtifactAssembly.ts +0 -724
- package/cli/buildPublishImportAnalysis.ts +0 -242
- package/cli/cliIoTypes.ts +0 -3
- package/cli/cliRuntimeDoctorReport.ts +0 -193
- package/cli/client/agentRunInput.ts +0 -10
- package/cli/client/agentRunLocalExecution.ts +0 -124
- package/cli/client/agentRunLocalExecutor.ts +0 -179
- package/cli/client/agentRunRuntimeSelection.ts +0 -145
- package/cli/client/agentRunServerTransport.ts +0 -397
- package/cli/client/agentRunTaskRunRecorder.ts +0 -176
- package/cli/customCodingAgentFlow.ts +0 -208
- package/cli/customCodingAgentRecord.ts +0 -179
- package/cli/dialogDataAccess.ts +0 -186
- package/cli/dialogInternalCommandEntries.ts +0 -11
- package/cli/dialogReadCommands.ts +0 -180
- package/cli/dialogReadHelpers.ts +0 -226
- package/cli/dialogStatusCommands.ts +0 -123
- package/cli/docInternalCommandEntries.ts +0 -20
- package/cli/hybridReadHelpers.ts +0 -109
- package/cli/machineCommandPrompts.ts +0 -79
- package/cli/machineCommandResolution.ts +0 -43
- package/cli/noloReadBridgePrompt.ts +0 -16
- package/cli/pageCreateCommands.ts +0 -219
- package/cli/pageDeleteCommands.ts +0 -167
- package/cli/pageReadCommands.ts +0 -151
- package/cli/pageUpdateCommands.ts +0 -249
- package/cli/pageWriteHelpers.ts +0 -209
- package/cli/publishPackage.ts +0 -36
- package/cli/runtimeInternalCommandEntries.ts +0 -15
- package/cli/runtimePassthroughCommands.ts +0 -22
- package/cli/scriptPassthroughHelpers.ts +0 -28
- package/cli/secretScanHelpers.ts +0 -31
- package/cli/spaceAttachCommands.ts +0 -134
- package/cli/spaceCategoryCommands.ts +0 -263
- package/cli/spaceCommands.ts +0 -295
- package/cli/spaceDeleteCommands.ts +0 -312
- package/cli/spaceInternalCommandEntries.ts +0 -21
- package/cli/spaceMutationHelpers.ts +0 -135
- package/cli/spaceReadCommands.ts +0 -323
- package/cli/tableDataOutput.ts +0 -41
- package/cli/tableDataSafety.ts +0 -26
- package/cli/tableMetaCommands.ts +0 -307
- package/cli/tableMutationCommands.ts +0 -266
- package/cli/tableQueryParsing.ts +0 -90
- package/cli/tableQueryRequest.ts +0 -53
- package/cli/taskRunActions.ts +0 -122
- package/cli/taskRunParsing.ts +0 -86
- package/cli/taskRunPromptShared.ts +0 -55
- package/cli/tui/tuiCatalog.ts +0 -22
- package/cli/tui/tuiCommandInterpreter.ts +0 -253
- package/cli/tui/tuiPresentation.ts +0 -146
- package/cliIoTypes.ts +0 -3
- package/cliRuntimeDoctorReport.ts +0 -193
- package/client/agentRunInput.ts +0 -10
- package/client/agentRunLocalExecution.test.ts +0 -123
- package/client/agentRunLocalExecution.ts +0 -124
- package/client/agentRunLocalExecutor.ts +0 -179
- package/client/agentRunRuntimeSelection.test.ts +0 -159
- package/client/agentRunRuntimeSelection.ts +0 -145
- package/client/agentRunServerTransport.ts +0 -397
- package/client/agentRunTaskRunRecorder.ts +0 -176
- package/connector-experimental/daemonLauncher.ts +0 -223
- package/create/space/spaceKeys.ts +0 -65
- package/create/types.ts +0 -21
- package/customCodingAgentFlow.ts +0 -208
- package/customCodingAgentRecord.ts +0 -179
- package/database/keys.ts +0 -765
- package/database/tombstones.ts +0 -52
- package/database/utils/ulid.ts +0 -1
- package/dialogDataAccess.ts +0 -186
- package/dialogInternalCommandEntries.ts +0 -11
- package/dialogReadCommands.ts +0 -180
- package/dialogReadHelpers.ts +0 -226
- package/dialogStatusCommands.ts +0 -123
- package/docInternalCommandEntries.ts +0 -20
- package/hybridReadHelpers.ts +0 -109
- package/machineCommandPrompts.ts +0 -79
- package/machineCommandResolution.ts +0 -43
- package/noloReadBridgePrompt.ts +0 -16
- package/pageCreateCommands.ts +0 -219
- package/pageDeleteCommands.ts +0 -167
- package/pageReadCommands.ts +0 -151
- package/pageUpdateCommands.ts +0 -249
- package/pageWriteHelpers.ts +0 -209
- package/publishPackage.ts +0 -36
- package/runtimeInternalCommandEntries.ts +0 -15
- package/runtimePassthroughCommands.ts +0 -22
- package/scriptPassthroughHelpers.ts +0 -28
- package/secretScanHelpers.ts +0 -31
- package/share/helpers.ts +0 -302
- package/share/keys.ts +0 -243
- package/share/types.ts +0 -100
- package/spaceAttachCommands.ts +0 -134
- package/spaceCategoryCommands.ts +0 -263
- package/spaceCommands.ts +0 -295
- package/spaceDeleteCommands.ts +0 -312
- package/spaceInternalCommandEntries.ts +0 -21
- package/spaceMutationHelpers.ts +0 -135
- package/spaceReadCommands.ts +0 -323
- package/tableDataOutput.ts +0 -41
- package/tableDataSafety.ts +0 -26
- package/tableMetaCommands.ts +0 -307
- package/tableMutationCommands.ts +0 -266
- package/tableQueryParsing.ts +0 -90
- package/tableQueryRequest.ts +0 -53
- package/taskRunActions.ts +0 -122
- package/taskRunParsing.ts +0 -86
- package/taskRunPromptShared.ts +0 -55
- package/tui/tuiCatalog.ts +0 -22
- package/tui/tuiCommandInterpreter.test.ts +0 -169
- package/tui/tuiCommandInterpreter.ts +0 -253
- package/tui/tuiPresentation.test.ts +0 -154
- package/tui/tuiPresentation.ts +0 -146
|
@@ -1,724 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
copyFileSync,
|
|
3
|
-
existsSync,
|
|
4
|
-
mkdirSync,
|
|
5
|
-
readFileSync,
|
|
6
|
-
readdirSync,
|
|
7
|
-
rmSync,
|
|
8
|
-
statSync,
|
|
9
|
-
writeFileSync,
|
|
10
|
-
} from "node:fs";
|
|
11
|
-
import { dirname, join, relative } from "node:path";
|
|
12
|
-
import {
|
|
13
|
-
collectTypeScriptSourceFiles,
|
|
14
|
-
extractLocalRelativeImports,
|
|
15
|
-
findTypeScriptFiles,
|
|
16
|
-
} from "./buildPublishImportAnalysis";
|
|
17
|
-
|
|
18
|
-
type WarnFn = (message: string, error?: unknown) => void;
|
|
19
|
-
|
|
20
|
-
type ReachableWorkspaceFilesByPackage = Record<string, string[]>;
|
|
21
|
-
|
|
22
|
-
type WorkspaceFileTarget = {
|
|
23
|
-
packageName: string;
|
|
24
|
-
relativeFilePath: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type WorkspaceGraph = {
|
|
28
|
-
packageOrder: string[];
|
|
29
|
-
filesByPackage: ReachableWorkspaceFilesByPackage;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type InlineWorkspaceDependenciesOptions = {
|
|
33
|
-
sourceDir: string;
|
|
34
|
-
distDir: string;
|
|
35
|
-
workspaceDeps: string[];
|
|
36
|
-
reachableFilesByPackage?: ReachableWorkspaceFilesByPackage;
|
|
37
|
-
extractExternalImports: (content: string) => string[];
|
|
38
|
-
rewriteCrossPackageImports: (
|
|
39
|
-
content: string,
|
|
40
|
-
workspaceDeps: string[],
|
|
41
|
-
relativeFilePath: string
|
|
42
|
-
) => string;
|
|
43
|
-
warn: WarnFn;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export type BuildPublishArtifactAssemblyOptions = {
|
|
47
|
-
sourceDir: string;
|
|
48
|
-
distDir: string;
|
|
49
|
-
filesToCopy: string[];
|
|
50
|
-
extractExternalImports: (content: string) => string[];
|
|
51
|
-
rewriteCrossPackageImports: (
|
|
52
|
-
content: string,
|
|
53
|
-
workspaceDeps: string[],
|
|
54
|
-
relativeFilePath: string
|
|
55
|
-
) => string;
|
|
56
|
-
collectWorkspaceDependencies?: (
|
|
57
|
-
sourceDir: string,
|
|
58
|
-
filesToCopy: string[]
|
|
59
|
-
) => string[];
|
|
60
|
-
inlineWorkspaceDependencies: (
|
|
61
|
-
options: InlineWorkspaceDependenciesOptions
|
|
62
|
-
) => Promise<{
|
|
63
|
-
inlinedDeps: string[];
|
|
64
|
-
inlinedFiles?: string[];
|
|
65
|
-
externalDeps: Record<string, string>;
|
|
66
|
-
}>;
|
|
67
|
-
warn: WarnFn;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export async function buildPublishArtifactAssembly(
|
|
71
|
-
options: BuildPublishArtifactAssemblyOptions
|
|
72
|
-
): Promise<{
|
|
73
|
-
resolvedFilesToCopy: string[];
|
|
74
|
-
workspaceDeps: string[];
|
|
75
|
-
inlinedDeps: string[];
|
|
76
|
-
inlinedFiles: string[];
|
|
77
|
-
externalDeps: Record<string, string>;
|
|
78
|
-
}> {
|
|
79
|
-
const {
|
|
80
|
-
sourceDir,
|
|
81
|
-
distDir,
|
|
82
|
-
filesToCopy,
|
|
83
|
-
extractExternalImports,
|
|
84
|
-
rewriteCrossPackageImports,
|
|
85
|
-
inlineWorkspaceDependencies,
|
|
86
|
-
warn,
|
|
87
|
-
} = options;
|
|
88
|
-
|
|
89
|
-
rmSync(distDir, { recursive: true, force: true });
|
|
90
|
-
mkdirSync(distDir, { recursive: true });
|
|
91
|
-
|
|
92
|
-
const resolvedFilesToCopy = expandLocalFileDependencies(
|
|
93
|
-
sourceDir,
|
|
94
|
-
resolveFilesToCopy(sourceDir, filesToCopy)
|
|
95
|
-
);
|
|
96
|
-
const reachableWorkspaceGraph = collectReachableWorkspaceFiles(
|
|
97
|
-
sourceDir,
|
|
98
|
-
resolvedFilesToCopy
|
|
99
|
-
);
|
|
100
|
-
const workspaceDeps = reachableWorkspaceGraph.packageOrder;
|
|
101
|
-
|
|
102
|
-
for (const file of resolvedFilesToCopy) {
|
|
103
|
-
const sourcePath = join(sourceDir, file);
|
|
104
|
-
const destPath = join(distDir, file);
|
|
105
|
-
|
|
106
|
-
if (!existsSync(sourcePath)) {
|
|
107
|
-
warn(`Warning: file not found: ${sourcePath}`);
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const destDir = dirname(destPath);
|
|
112
|
-
if (!existsSync(destDir)) {
|
|
113
|
-
mkdirSync(destDir, { recursive: true });
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (file.endsWith(".ts")) {
|
|
117
|
-
const content = readFileSync(sourcePath, "utf8");
|
|
118
|
-
const rewritten = rewriteCrossPackageImports(content, workspaceDeps, file);
|
|
119
|
-
writeFileSync(destPath, rewritten);
|
|
120
|
-
} else {
|
|
121
|
-
copyFileSync(sourcePath, destPath);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const {
|
|
126
|
-
inlinedDeps,
|
|
127
|
-
inlinedFiles = [],
|
|
128
|
-
externalDeps,
|
|
129
|
-
} = await inlineWorkspaceDependencies({
|
|
130
|
-
sourceDir,
|
|
131
|
-
distDir,
|
|
132
|
-
workspaceDeps,
|
|
133
|
-
reachableFilesByPackage: reachableWorkspaceGraph.filesByPackage,
|
|
134
|
-
extractExternalImports,
|
|
135
|
-
rewriteCrossPackageImports,
|
|
136
|
-
warn,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
resolvedFilesToCopy,
|
|
141
|
-
workspaceDeps,
|
|
142
|
-
inlinedDeps,
|
|
143
|
-
inlinedFiles,
|
|
144
|
-
externalDeps,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export async function inlineWorkspaceDependencies(
|
|
149
|
-
options: InlineWorkspaceDependenciesOptions
|
|
150
|
-
): Promise<{
|
|
151
|
-
inlinedDeps: string[];
|
|
152
|
-
inlinedFiles: string[];
|
|
153
|
-
externalDeps: Record<string, string>;
|
|
154
|
-
}> {
|
|
155
|
-
const {
|
|
156
|
-
sourceDir,
|
|
157
|
-
distDir,
|
|
158
|
-
workspaceDeps,
|
|
159
|
-
reachableFilesByPackage,
|
|
160
|
-
extractExternalImports,
|
|
161
|
-
rewriteCrossPackageImports,
|
|
162
|
-
warn,
|
|
163
|
-
} = options;
|
|
164
|
-
if (workspaceDeps.length === 0) {
|
|
165
|
-
return { inlinedDeps: [], inlinedFiles: [], externalDeps: {} };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const packagesDir = join(sourceDir, "..");
|
|
169
|
-
const repoRoot = join(packagesDir, "..");
|
|
170
|
-
const workspaceGraph = reachableFilesByPackage
|
|
171
|
-
? {
|
|
172
|
-
packageOrder: buildWorkspacePackageOrder(
|
|
173
|
-
workspaceDeps,
|
|
174
|
-
reachableFilesByPackage
|
|
175
|
-
),
|
|
176
|
-
filesByPackage: reachableFilesByPackage,
|
|
177
|
-
}
|
|
178
|
-
: collectWholePackageWorkspaceFiles(sourceDir, workspaceDeps);
|
|
179
|
-
const inlinedDeps: string[] = [];
|
|
180
|
-
const inlinedFiles: string[] = [];
|
|
181
|
-
|
|
182
|
-
for (const depName of workspaceGraph.packageOrder) {
|
|
183
|
-
const depSourceDir = join(packagesDir, depName);
|
|
184
|
-
if (!existsSync(depSourceDir)) {
|
|
185
|
-
warn(`Warning: workspace dependency not found: ${depSourceDir}`);
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
for (const relativeFilePath of workspaceGraph.filesByPackage[depName] || []) {
|
|
190
|
-
if (!shouldInlineWorkspaceFile(relativeFilePath)) {
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const sourcePath = join(depSourceDir, relativeFilePath);
|
|
195
|
-
if (!existsSync(sourcePath)) {
|
|
196
|
-
warn(`Warning: workspace file not found: ${sourcePath}`);
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const distRelativePath = join(depName, relativeFilePath).replace(/\\/g, "/");
|
|
201
|
-
const destPath = join(distDir, distRelativePath);
|
|
202
|
-
const destDir = dirname(destPath);
|
|
203
|
-
if (!existsSync(destDir)) {
|
|
204
|
-
mkdirSync(destDir, { recursive: true });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (relativeFilePath.endsWith(".ts")) {
|
|
208
|
-
const content = readFileSync(sourcePath, "utf8");
|
|
209
|
-
const rewritten = rewriteCrossPackageImports(
|
|
210
|
-
content,
|
|
211
|
-
workspaceGraph.packageOrder,
|
|
212
|
-
distRelativePath
|
|
213
|
-
);
|
|
214
|
-
writeFileSync(destPath, rewritten);
|
|
215
|
-
} else {
|
|
216
|
-
copyFileSync(sourcePath, destPath);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
inlinedFiles.push(distRelativePath);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
inlinedDeps.push(depName);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const externalDeps = discoverExternalImportsFromWorkspaceFiles({
|
|
226
|
-
packagesDir,
|
|
227
|
-
repoRoot,
|
|
228
|
-
extractExternalImports,
|
|
229
|
-
filesByPackage: workspaceGraph.filesByPackage,
|
|
230
|
-
workspacePackageDirs: new Set(workspaceGraph.packageOrder),
|
|
231
|
-
warn,
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
return { inlinedDeps, inlinedFiles, externalDeps };
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export { collectTypeScriptSourceFiles, findTypeScriptFiles };
|
|
238
|
-
|
|
239
|
-
export function expandLocalFileDependencies(sourceDir: string, filesToCopy: string[]): string[] {
|
|
240
|
-
const resolved = new Set(filesToCopy);
|
|
241
|
-
const pending = filesToCopy.filter((file) => file.endsWith(".ts"));
|
|
242
|
-
|
|
243
|
-
while (pending.length > 0) {
|
|
244
|
-
const relativeFilePath = pending.pop()!;
|
|
245
|
-
const absoluteFilePath = join(sourceDir, relativeFilePath);
|
|
246
|
-
if (!existsSync(absoluteFilePath)) {
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const content = readFileSync(absoluteFilePath, "utf8");
|
|
251
|
-
for (const importPath of extractLocalRelativeImports(content)) {
|
|
252
|
-
const discoveredPath = resolveLocalImportPath(sourceDir, relativeFilePath, importPath);
|
|
253
|
-
if (!discoveredPath || resolved.has(discoveredPath)) {
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
resolved.add(discoveredPath);
|
|
257
|
-
if (discoveredPath.endsWith(".ts")) {
|
|
258
|
-
pending.push(discoveredPath);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return Array.from(resolved);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function resolveLocalImportPath(
|
|
267
|
-
sourceDir: string,
|
|
268
|
-
relativeFilePath: string,
|
|
269
|
-
importPath: string
|
|
270
|
-
): string | null {
|
|
271
|
-
const fileDir = dirname(join(sourceDir, relativeFilePath));
|
|
272
|
-
const importBase = join(fileDir, importPath);
|
|
273
|
-
const candidate = resolveImportAbsolutePath(importBase);
|
|
274
|
-
if (!candidate) {
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const resolvedRelativePath = relative(sourceDir, candidate).replace(/\\/g, "/");
|
|
279
|
-
if (resolvedRelativePath.startsWith("..")) {
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return resolvedRelativePath;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export function resolveFilesToCopy(sourceDir: string, filesToCopy: string[]): string[] {
|
|
287
|
-
const resolved = new Set<string>();
|
|
288
|
-
|
|
289
|
-
for (const entry of filesToCopy) {
|
|
290
|
-
if (entry.endsWith("/**/*.ts")) {
|
|
291
|
-
const baseDir = entry.slice(0, -"/**/*.ts".length);
|
|
292
|
-
const absoluteBaseDir = join(sourceDir, baseDir);
|
|
293
|
-
if (!existsSync(absoluteBaseDir)) {
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
for (const filePath of findTypeScriptFiles(absoluteBaseDir)) {
|
|
297
|
-
resolved.add(relative(sourceDir, filePath));
|
|
298
|
-
}
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
resolved.add(entry);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return Array.from(resolved);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
export function copyDirectory(
|
|
309
|
-
src: string,
|
|
310
|
-
dest: string,
|
|
311
|
-
filter?: (file: string) => boolean,
|
|
312
|
-
transform?: (file: string, content: string) => string
|
|
313
|
-
): void {
|
|
314
|
-
if (!existsSync(src)) {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (!existsSync(dest)) {
|
|
319
|
-
mkdirSync(dest, { recursive: true });
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
for (const entry of readdirSync(src)) {
|
|
323
|
-
const srcPath = join(src, entry);
|
|
324
|
-
const destPath = join(dest, entry);
|
|
325
|
-
const stat = statSync(srcPath);
|
|
326
|
-
|
|
327
|
-
if (stat.isDirectory()) {
|
|
328
|
-
copyDirectory(srcPath, destPath, filter, transform);
|
|
329
|
-
} else if (stat.isFile() && (!filter || filter(srcPath))) {
|
|
330
|
-
const parentDir = dirname(destPath);
|
|
331
|
-
if (!existsSync(parentDir)) {
|
|
332
|
-
mkdirSync(parentDir, { recursive: true });
|
|
333
|
-
}
|
|
334
|
-
if (transform && srcPath.endsWith(".ts")) {
|
|
335
|
-
writeFileSync(destPath, transform(srcPath, readFileSync(srcPath, "utf8")));
|
|
336
|
-
} else {
|
|
337
|
-
copyFileSync(srcPath, destPath);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function collectReachableWorkspaceFiles(
|
|
344
|
-
sourceDir: string,
|
|
345
|
-
entryFiles: string[]
|
|
346
|
-
): WorkspaceGraph {
|
|
347
|
-
const packagesDir = join(sourceDir, "..");
|
|
348
|
-
const workspacePackageDirs = listWorkspacePackageDirs(sourceDir);
|
|
349
|
-
const packageOrder: string[] = [];
|
|
350
|
-
const filesByPackage = new Map<string, Set<string>>();
|
|
351
|
-
const pending: WorkspaceFileTarget[] = [];
|
|
352
|
-
|
|
353
|
-
const enqueue = (target: WorkspaceFileTarget | null) => {
|
|
354
|
-
if (!target || !shouldInlineWorkspaceFile(target.relativeFilePath)) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
let files = filesByPackage.get(target.packageName);
|
|
359
|
-
if (!files) {
|
|
360
|
-
files = new Set<string>();
|
|
361
|
-
filesByPackage.set(target.packageName, files);
|
|
362
|
-
packageOrder.push(target.packageName);
|
|
363
|
-
}
|
|
364
|
-
if (files.has(target.relativeFilePath)) {
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
files.add(target.relativeFilePath);
|
|
368
|
-
if (target.relativeFilePath.endsWith(".ts")) {
|
|
369
|
-
pending.push(target);
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
for (const relativeFilePath of entryFiles) {
|
|
374
|
-
if (!relativeFilePath.endsWith(".ts")) {
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
const sourcePath = join(sourceDir, relativeFilePath);
|
|
378
|
-
if (!existsSync(sourcePath)) {
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
const content = readFileSync(sourcePath, "utf8");
|
|
382
|
-
for (const importPath of extractModuleSpecifiers(content)) {
|
|
383
|
-
enqueue(
|
|
384
|
-
resolveWorkspaceImport({
|
|
385
|
-
packagesDir,
|
|
386
|
-
workspacePackageDirs,
|
|
387
|
-
importerPackageDir: sourceDir,
|
|
388
|
-
importerRelativeFilePath: relativeFilePath,
|
|
389
|
-
importPath,
|
|
390
|
-
})
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
while (pending.length > 0) {
|
|
396
|
-
const target = pending.pop()!;
|
|
397
|
-
const packageDir = join(packagesDir, target.packageName);
|
|
398
|
-
const sourcePath = join(packageDir, target.relativeFilePath);
|
|
399
|
-
if (!existsSync(sourcePath)) {
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const content = readFileSync(sourcePath, "utf8");
|
|
404
|
-
for (const importPath of extractModuleSpecifiers(content)) {
|
|
405
|
-
enqueue(
|
|
406
|
-
resolveWorkspaceImport({
|
|
407
|
-
packagesDir,
|
|
408
|
-
workspacePackageDirs,
|
|
409
|
-
importerPackageDir: packageDir,
|
|
410
|
-
importerRelativeFilePath: target.relativeFilePath,
|
|
411
|
-
importPath,
|
|
412
|
-
})
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
packageOrder,
|
|
419
|
-
filesByPackage: Object.fromEntries(
|
|
420
|
-
packageOrder.map((packageName) => [
|
|
421
|
-
packageName,
|
|
422
|
-
Array.from(filesByPackage.get(packageName) ?? []),
|
|
423
|
-
])
|
|
424
|
-
),
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function collectWholePackageWorkspaceFiles(
|
|
429
|
-
sourceDir: string,
|
|
430
|
-
workspaceDeps: string[]
|
|
431
|
-
): WorkspaceGraph {
|
|
432
|
-
const packagesDir = join(sourceDir, "..");
|
|
433
|
-
const workspacePackageDirs = listWorkspacePackageDirs(sourceDir);
|
|
434
|
-
const packageOrder: string[] = [];
|
|
435
|
-
const filesByPackage = new Map<string, Set<string>>();
|
|
436
|
-
const pendingPackages = [...workspaceDeps];
|
|
437
|
-
|
|
438
|
-
const addWholePackage = (packageName: string) => {
|
|
439
|
-
if (filesByPackage.has(packageName)) {
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
const depDir = join(packagesDir, packageName);
|
|
444
|
-
if (!existsSync(depDir)) {
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
const packageFiles = new Set(
|
|
449
|
-
findTypeScriptFiles(depDir)
|
|
450
|
-
.map((filePath) => relative(depDir, filePath).replace(/\\/g, "/"))
|
|
451
|
-
.filter((relativeFilePath) => shouldInlineWorkspaceFile(relativeFilePath))
|
|
452
|
-
);
|
|
453
|
-
filesByPackage.set(packageName, packageFiles);
|
|
454
|
-
packageOrder.push(packageName);
|
|
455
|
-
|
|
456
|
-
for (const relativeFilePath of packageFiles) {
|
|
457
|
-
const content = readFileSync(join(depDir, relativeFilePath), "utf8");
|
|
458
|
-
for (const importPath of extractModuleSpecifiers(content)) {
|
|
459
|
-
const resolved = resolveWorkspaceImport({
|
|
460
|
-
packagesDir,
|
|
461
|
-
workspacePackageDirs,
|
|
462
|
-
importerPackageDir: depDir,
|
|
463
|
-
importerRelativeFilePath: relativeFilePath,
|
|
464
|
-
importPath,
|
|
465
|
-
});
|
|
466
|
-
if (!resolved || filesByPackage.has(resolved.packageName)) {
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
pendingPackages.push(resolved.packageName);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
while (pendingPackages.length > 0) {
|
|
475
|
-
addWholePackage(pendingPackages.shift()!);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return {
|
|
479
|
-
packageOrder,
|
|
480
|
-
filesByPackage: Object.fromEntries(
|
|
481
|
-
packageOrder.map((packageName) => [
|
|
482
|
-
packageName,
|
|
483
|
-
Array.from(filesByPackage.get(packageName) ?? []),
|
|
484
|
-
])
|
|
485
|
-
),
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function buildWorkspacePackageOrder(
|
|
490
|
-
workspaceDeps: string[],
|
|
491
|
-
filesByPackage: ReachableWorkspaceFilesByPackage
|
|
492
|
-
): string[] {
|
|
493
|
-
const ordered = new Set(workspaceDeps);
|
|
494
|
-
for (const packageName of Object.keys(filesByPackage)) {
|
|
495
|
-
ordered.add(packageName);
|
|
496
|
-
}
|
|
497
|
-
return Array.from(ordered);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
function discoverExternalImportsFromWorkspaceFiles(args: {
|
|
501
|
-
packagesDir: string;
|
|
502
|
-
repoRoot: string;
|
|
503
|
-
extractExternalImports: (content: string) => string[];
|
|
504
|
-
filesByPackage: ReachableWorkspaceFilesByPackage;
|
|
505
|
-
workspacePackageDirs: Set<string>;
|
|
506
|
-
warn: WarnFn;
|
|
507
|
-
}): Record<string, string> {
|
|
508
|
-
const {
|
|
509
|
-
packagesDir,
|
|
510
|
-
repoRoot,
|
|
511
|
-
extractExternalImports,
|
|
512
|
-
filesByPackage,
|
|
513
|
-
workspacePackageDirs,
|
|
514
|
-
warn,
|
|
515
|
-
} = args;
|
|
516
|
-
const externalDeps: Record<string, string> = {};
|
|
517
|
-
const rootDeps = readManifestDependencies(join(repoRoot, "package.json"), warn);
|
|
518
|
-
|
|
519
|
-
for (const [packageName, files] of Object.entries(filesByPackage)) {
|
|
520
|
-
const packageDeps = readManifestDependencies(
|
|
521
|
-
join(packagesDir, packageName, "package.json"),
|
|
522
|
-
warn
|
|
523
|
-
);
|
|
524
|
-
for (const relativeFilePath of files) {
|
|
525
|
-
if (!relativeFilePath.endsWith(".ts")) {
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const sourcePath = join(packagesDir, packageName, relativeFilePath);
|
|
530
|
-
if (!existsSync(sourcePath)) {
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
try {
|
|
535
|
-
const content = readFileSync(sourcePath, "utf8");
|
|
536
|
-
for (const importName of extractExternalImports(content)) {
|
|
537
|
-
if (workspacePackageDirs.has(importName)) {
|
|
538
|
-
continue;
|
|
539
|
-
}
|
|
540
|
-
const resolvedVersion = packageDeps[importName] ?? rootDeps[importName];
|
|
541
|
-
if (resolvedVersion && !externalDeps[importName]) {
|
|
542
|
-
externalDeps[importName] = resolvedVersion;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
} catch (error) {
|
|
546
|
-
warn(`Warning: could not scan ${sourcePath}:`, error);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
return externalDeps;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
function readManifestDependencies(
|
|
555
|
-
manifestPath: string,
|
|
556
|
-
warn: WarnFn
|
|
557
|
-
): Record<string, string> {
|
|
558
|
-
if (!existsSync(manifestPath)) {
|
|
559
|
-
return {};
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
try {
|
|
563
|
-
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
564
|
-
const deps: Record<string, string> = {};
|
|
565
|
-
if (manifest.dependencies) {
|
|
566
|
-
for (const [name, version] of Object.entries(manifest.dependencies)) {
|
|
567
|
-
if (typeof version === "string" && !version.startsWith("workspace:")) {
|
|
568
|
-
deps[name] = version;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
return deps;
|
|
573
|
-
} catch (error) {
|
|
574
|
-
warn(`Warning: could not read package.json at ${manifestPath}:`, error);
|
|
575
|
-
return {};
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
function listWorkspacePackageDirs(sourceDir: string): Set<string> {
|
|
580
|
-
const packagesDir = join(sourceDir, "..");
|
|
581
|
-
const workspaceDirs = new Set<string>();
|
|
582
|
-
|
|
583
|
-
for (const entry of readdirSync(packagesDir)) {
|
|
584
|
-
if (existsSync(join(packagesDir, entry, "package.json"))) {
|
|
585
|
-
workspaceDirs.add(entry);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return workspaceDirs;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
function shouldInlineWorkspaceFile(relativeFilePath: string): boolean {
|
|
593
|
-
return (
|
|
594
|
-
relativeFilePath.endsWith(".ts") &&
|
|
595
|
-
!relativeFilePath.includes("node_modules/") &&
|
|
596
|
-
!relativeFilePath.endsWith(".test.ts") &&
|
|
597
|
-
!relativeFilePath.endsWith(".spec.ts") &&
|
|
598
|
-
!relativeFilePath.includes("package.json")
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
function resolveWorkspaceImport(args: {
|
|
603
|
-
packagesDir: string;
|
|
604
|
-
workspacePackageDirs: Set<string>;
|
|
605
|
-
importerPackageDir: string;
|
|
606
|
-
importerRelativeFilePath: string;
|
|
607
|
-
importPath: string;
|
|
608
|
-
}): WorkspaceFileTarget | null {
|
|
609
|
-
const {
|
|
610
|
-
packagesDir,
|
|
611
|
-
workspacePackageDirs,
|
|
612
|
-
importerPackageDir,
|
|
613
|
-
importerRelativeFilePath,
|
|
614
|
-
importPath,
|
|
615
|
-
} = args;
|
|
616
|
-
|
|
617
|
-
if (importPath.startsWith("node:") || importPath.startsWith("/")) {
|
|
618
|
-
return null;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
if (importPath.startsWith(".")) {
|
|
622
|
-
const importBase = join(
|
|
623
|
-
dirname(join(importerPackageDir, importerRelativeFilePath)),
|
|
624
|
-
importPath
|
|
625
|
-
);
|
|
626
|
-
return toWorkspaceFileTarget(
|
|
627
|
-
packagesDir,
|
|
628
|
-
workspacePackageDirs,
|
|
629
|
-
resolveImportAbsolutePath(importBase)
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
const packageName = extractPackageNameFromImportPath(importPath);
|
|
634
|
-
if (!workspacePackageDirs.has(packageName)) {
|
|
635
|
-
return null;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const subPath =
|
|
639
|
-
importPath === packageName ? "index" : importPath.slice(packageName.length + 1);
|
|
640
|
-
return toWorkspaceFileTarget(
|
|
641
|
-
packagesDir,
|
|
642
|
-
workspacePackageDirs,
|
|
643
|
-
resolveImportAbsolutePath(join(packagesDir, packageName, subPath))
|
|
644
|
-
);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
function toWorkspaceFileTarget(
|
|
648
|
-
packagesDir: string,
|
|
649
|
-
workspacePackageDirs: Set<string>,
|
|
650
|
-
absoluteFilePath: string | null
|
|
651
|
-
): WorkspaceFileTarget | null {
|
|
652
|
-
if (!absoluteFilePath) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
const relativeToPackages = relative(packagesDir, absoluteFilePath).replace(/\\/g, "/");
|
|
657
|
-
if (
|
|
658
|
-
relativeToPackages.startsWith("..") ||
|
|
659
|
-
relativeToPackages.length === 0
|
|
660
|
-
) {
|
|
661
|
-
return null;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
const [packageName, ...pathParts] = relativeToPackages.split("/");
|
|
665
|
-
if (!workspacePackageDirs.has(packageName) || pathParts.length === 0) {
|
|
666
|
-
return null;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
return {
|
|
670
|
-
packageName,
|
|
671
|
-
relativeFilePath: pathParts.join("/"),
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
function resolveImportAbsolutePath(importBase: string): string | null {
|
|
676
|
-
const candidates = [
|
|
677
|
-
importBase,
|
|
678
|
-
`${importBase}.ts`,
|
|
679
|
-
`${importBase}.tsx`,
|
|
680
|
-
join(importBase, "index.ts"),
|
|
681
|
-
join(importBase, "index.tsx"),
|
|
682
|
-
`${importBase}.json`,
|
|
683
|
-
];
|
|
684
|
-
|
|
685
|
-
for (const candidate of candidates) {
|
|
686
|
-
if (!existsSync(candidate)) {
|
|
687
|
-
continue;
|
|
688
|
-
}
|
|
689
|
-
const stat = statSync(candidate);
|
|
690
|
-
if (stat.isFile()) {
|
|
691
|
-
return candidate;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
return null;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
function extractPackageNameFromImportPath(importPath: string): string {
|
|
699
|
-
if (importPath.startsWith("@")) {
|
|
700
|
-
const parts = importPath.split("/");
|
|
701
|
-
return parts.slice(0, 2).join("/");
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
const firstSlash = importPath.indexOf("/");
|
|
705
|
-
return firstSlash === -1 ? importPath : importPath.slice(0, firstSlash);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
function extractModuleSpecifiers(content: string): string[] {
|
|
709
|
-
const specifiers = new Set<string>();
|
|
710
|
-
const importOrExportRegex =
|
|
711
|
-
/(?:import|export)\s+(?:(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
712
|
-
const dynamicImportRegex = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
713
|
-
|
|
714
|
-
let match: RegExpExecArray | null;
|
|
715
|
-
while ((match = importOrExportRegex.exec(content)) !== null) {
|
|
716
|
-
specifiers.add(match[1]);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
while ((match = dynamicImportRegex.exec(content)) !== null) {
|
|
720
|
-
specifiers.add(match[1]);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
return Array.from(specifiers);
|
|
724
|
-
}
|