simplemdg-dev-cli 2.0.4 → 2.4.4
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 +63 -354
- package/USER_GUIDE.md +55 -378
- package/dist/commands/cds.command.js +69 -60
- package/dist/commands/cds.command.js.map +1 -1
- package/dist/commands/cf-db.command.d.ts +2 -0
- package/dist/commands/cf-db.command.js +606 -0
- package/dist/commands/cf-db.command.js.map +1 -0
- package/dist/commands/cf.command.js +291 -280
- package/dist/commands/cf.command.js.map +1 -1
- package/dist/commands/gitlab.command.d.ts +2 -0
- package/dist/commands/gitlab.command.js +351 -0
- package/dist/commands/gitlab.command.js.map +1 -0
- package/dist/commands/npmrc.command.js +50 -44
- package/dist/commands/npmrc.command.js.map +1 -1
- package/dist/core/cache.d.ts +1 -1
- package/dist/core/cache.js +58 -31
- package/dist/core/cache.js.map +1 -1
- package/dist/core/cds.js +32 -22
- package/dist/core/cds.js.map +1 -1
- package/dist/core/cf-env-parser.d.ts +1 -1
- package/dist/core/cf-env-parser.js +4 -1
- package/dist/core/cf-env-parser.js.map +1 -1
- package/dist/core/cf.d.ts +1 -1
- package/dist/core/cf.js +46 -31
- package/dist/core/cf.js.map +1 -1
- package/dist/core/db/db-btp.d.ts +48 -0
- package/dist/core/db/db-btp.js +162 -0
- package/dist/core/db/db-btp.js.map +1 -0
- package/dist/core/db/db-cache.d.ts +35 -0
- package/dist/core/db/db-cache.js +164 -0
- package/dist/core/db/db-cache.js.map +1 -0
- package/dist/core/db/db-connection.d.ts +22 -0
- package/dist/core/db/db-connection.js +73 -0
- package/dist/core/db/db-connection.js.map +1 -0
- package/dist/core/db/db-crypto.d.ts +3 -0
- package/dist/core/db/db-crypto.js +54 -0
- package/dist/core/db/db-crypto.js.map +1 -0
- package/dist/core/db/db-hana-adapter.d.ts +32 -0
- package/dist/core/db/db-hana-adapter.js +243 -0
- package/dist/core/db/db-hana-adapter.js.map +1 -0
- package/dist/core/db/db-metadata.d.ts +25 -0
- package/dist/core/db/db-metadata.js +150 -0
- package/dist/core/db/db-metadata.js.map +1 -0
- package/dist/core/db/db-postgres-adapter.d.ts +30 -0
- package/dist/core/db/db-postgres-adapter.js +245 -0
- package/dist/core/db/db-postgres-adapter.js.map +1 -0
- package/dist/core/db/db-query-files.d.ts +20 -0
- package/dist/core/db/db-query-files.js +106 -0
- package/dist/core/db/db-query-files.js.map +1 -0
- package/dist/core/db/db-query-history.d.ts +5 -0
- package/dist/core/db/db-query-history.js +49 -0
- package/dist/core/db/db-query-history.js.map +1 -0
- package/dist/core/db/db-row.d.ts +22 -0
- package/dist/core/db/db-row.js +70 -0
- package/dist/core/db/db-row.js.map +1 -0
- package/dist/core/db/db-studio-html.d.ts +4 -0
- package/dist/core/db/db-studio-html.js +437 -0
- package/dist/core/db/db-studio-html.js.map +1 -0
- package/dist/core/db/db-studio-server.d.ts +11 -0
- package/dist/core/db/db-studio-server.js +465 -0
- package/dist/core/db/db-studio-server.js.map +1 -0
- package/dist/core/db/db-types.d.ts +174 -0
- package/dist/core/db/db-types.js +3 -0
- package/dist/core/db/db-types.js.map +1 -0
- package/dist/core/db/db-vcap-parser.d.ts +7 -0
- package/dist/core/db/db-vcap-parser.js +137 -0
- package/dist/core/db/db-vcap-parser.js.map +1 -0
- package/dist/core/doctor.d.ts +1 -1
- package/dist/core/doctor.js +14 -8
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/guide.js +31 -26
- package/dist/core/guide.js.map +1 -1
- package/dist/core/install.d.ts +1 -1
- package/dist/core/install.js +17 -11
- package/dist/core/install.js.map +1 -1
- package/dist/core/navigator.d.ts +17 -0
- package/dist/core/navigator.js +140 -0
- package/dist/core/navigator.js.map +1 -0
- package/dist/core/npmrc.js +29 -16
- package/dist/core/npmrc.js.map +1 -1
- package/dist/core/process.js +11 -6
- package/dist/core/process.js.map +1 -1
- package/dist/core/prompts.js +16 -8
- package/dist/core/prompts.js.map +1 -1
- package/dist/core/repository.d.ts +1 -1
- package/dist/core/repository.js +16 -9
- package/dist/core/repository.js.map +1 -1
- package/dist/core/scanner.d.ts +1 -1
- package/dist/core/scanner.js +13 -7
- package/dist/core/scanner.js.map +1 -1
- package/dist/core/tooling.d.ts +28 -0
- package/dist/core/tooling.js +168 -0
- package/dist/core/tooling.js.map +1 -0
- package/dist/core/types.js +2 -1
- package/dist/core/version-conflict.d.ts +2 -2
- package/dist/core/version-conflict.js +11 -6
- package/dist/core/version-conflict.js.map +1 -1
- package/dist/index.js +65 -48
- package/dist/index.js.map +1 -1
- package/dist/types-local.js +2 -1
- package/package.json +12 -6
- package/src/commands/cds.command.ts +529 -0
- package/src/commands/cf-db.command.ts +636 -0
- package/src/commands/cf.command.ts +3345 -0
- package/src/commands/gitlab.command.ts +373 -0
- package/src/commands/npmrc.command.ts +581 -0
- package/src/core/cache.ts +332 -0
- package/src/core/cds.ts +278 -0
- package/src/core/cf-env-parser.ts +131 -0
- package/src/core/cf.ts +271 -0
- package/src/core/db/db-btp.ts +207 -0
- package/src/core/db/db-cache.ts +215 -0
- package/src/core/db/db-connection.ts +79 -0
- package/src/core/db/db-crypto.ts +53 -0
- package/src/core/db/db-hana-adapter.ts +294 -0
- package/src/core/db/db-metadata.ts +174 -0
- package/src/core/db/db-postgres-adapter.ts +275 -0
- package/src/core/db/db-query-files.ts +130 -0
- package/src/core/db/db-query-history.ts +53 -0
- package/src/core/db/db-row.ts +93 -0
- package/src/core/db/db-studio-html.ts +439 -0
- package/src/core/db/db-studio-server.ts +559 -0
- package/src/core/db/db-types.ts +195 -0
- package/src/core/db/db-vcap-parser.ts +182 -0
- package/src/core/doctor.ts +70 -0
- package/src/core/guide.ts +261 -0
- package/src/core/install.ts +91 -0
- package/src/core/navigator.ts +164 -0
- package/src/core/npmrc.ts +171 -0
- package/src/core/process.ts +75 -0
- package/src/core/prompts.ts +225 -0
- package/src/core/repository.ts +36 -0
- package/src/core/scanner.ts +41 -0
- package/src/core/tooling.ts +207 -0
- package/src/core/types.ts +152 -0
- package/src/core/version-conflict.ts +46 -0
- package/src/index.ts +460 -0
- package/src/types/external.d.ts +3 -0
- package/src/types-local.ts +11 -0
- package/tsconfig.json +17 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import prompts from "prompts";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import { askRootHelpMode, openUserGuideInBrowser, printUserGuide } from "./core/guide";
|
|
8
|
+
import { installRepository } from "./core/install";
|
|
9
|
+
import { scanRepositoryVariables } from "./core/scanner";
|
|
10
|
+
import { doctorPackage } from "./core/doctor";
|
|
11
|
+
import {
|
|
12
|
+
readCache,
|
|
13
|
+
rememberOverrideValue,
|
|
14
|
+
rememberVariableValue,
|
|
15
|
+
} from "./core/cache";
|
|
16
|
+
import { resolveRepositoryPath } from "./core/repository";
|
|
17
|
+
import {
|
|
18
|
+
inspectPackageConflicts,
|
|
19
|
+
parseLoadedLocationConflicts,
|
|
20
|
+
rememberResolvedOverrideVersions,
|
|
21
|
+
} from "./core/version-conflict";
|
|
22
|
+
import { registerCloudFoundryCommands } from "./commands/cf.command";
|
|
23
|
+
import { registerCdsCommands } from "./commands/cds.command";
|
|
24
|
+
import { registerNpmrcCommands } from "./commands/npmrc.command";
|
|
25
|
+
import { registerGitLabCommands } from "./commands/gitlab.command";
|
|
26
|
+
import { enableInteractiveNavigation, runGroupNavigator } from "./core/navigator";
|
|
27
|
+
import type { TInstallCommandOptions, TKeyValueMap } from "./types-local";
|
|
28
|
+
|
|
29
|
+
const program = new Command();
|
|
30
|
+
|
|
31
|
+
function parseKeyValueList(values: string[] | undefined): TKeyValueMap {
|
|
32
|
+
const result: TKeyValueMap = {};
|
|
33
|
+
|
|
34
|
+
for (const value of values ?? []) {
|
|
35
|
+
const index = value.indexOf("=");
|
|
36
|
+
|
|
37
|
+
if (index === -1) {
|
|
38
|
+
throw new Error(`Invalid key=value: ${value}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const key = value.slice(0, index).trim();
|
|
42
|
+
const keyValue = value.slice(index + 1).trim();
|
|
43
|
+
|
|
44
|
+
if (!key || !keyValue) {
|
|
45
|
+
throw new Error(`Invalid key=value: ${value}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
result[key] = keyValue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function askMissingVariables(options: {
|
|
55
|
+
repositoryPath: string;
|
|
56
|
+
filePatterns: string[];
|
|
57
|
+
providedValues: Record<string, string>;
|
|
58
|
+
}): Promise<Record<string, string>> {
|
|
59
|
+
const scannedVariables = await scanRepositoryVariables({
|
|
60
|
+
repositoryPath: options.repositoryPath,
|
|
61
|
+
filePatterns: options.filePatterns,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const variableNames = [...new Set(scannedVariables.map((item) => item.variableName))];
|
|
65
|
+
const cache = await readCache();
|
|
66
|
+
const result: Record<string, string> = { ...options.providedValues };
|
|
67
|
+
|
|
68
|
+
if (variableNames.length === 0) {
|
|
69
|
+
console.log("No package variables found.");
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log("");
|
|
74
|
+
console.log("Detected package variables:");
|
|
75
|
+
|
|
76
|
+
for (const variableName of variableNames) {
|
|
77
|
+
const occurrences = scannedVariables
|
|
78
|
+
.filter((item) => item.variableName === variableName)
|
|
79
|
+
.reduce((total, item) => total + item.occurrences, 0);
|
|
80
|
+
|
|
81
|
+
console.log(`- ${variableName} (${occurrences} occurrence(s))`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log("");
|
|
85
|
+
|
|
86
|
+
for (const variableName of variableNames) {
|
|
87
|
+
if (result[variableName]) {
|
|
88
|
+
await rememberVariableValue(variableName, result[variableName]);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const cachedValues = cache.variables[variableName] ?? [];
|
|
93
|
+
|
|
94
|
+
if (cachedValues.length > 0) {
|
|
95
|
+
const response = await prompts({
|
|
96
|
+
type: "select",
|
|
97
|
+
name: "selectedValue",
|
|
98
|
+
message: `Value for ${variableName}`,
|
|
99
|
+
choices: [
|
|
100
|
+
...cachedValues.map((value) => ({ title: value, value })),
|
|
101
|
+
{ title: "Enter new value", value: "__ENTER_NEW_VALUE__" },
|
|
102
|
+
],
|
|
103
|
+
initial: 0,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (!response.selectedValue) {
|
|
107
|
+
throw new Error(`Missing value for ${variableName}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (response.selectedValue !== "__ENTER_NEW_VALUE__") {
|
|
111
|
+
result[variableName] = response.selectedValue as string;
|
|
112
|
+
await rememberVariableValue(variableName, response.selectedValue as string);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const response = await prompts({
|
|
118
|
+
type: "text",
|
|
119
|
+
name: "value",
|
|
120
|
+
message: `Enter value for ${variableName}`,
|
|
121
|
+
initial: cachedValues[0] ?? "",
|
|
122
|
+
validate: (value: string) => value?.trim() ? true : `${variableName} is required`,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (!response.value) {
|
|
126
|
+
throw new Error(`Missing value for ${variableName}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
result[variableName] = response.value as string;
|
|
130
|
+
await rememberVariableValue(variableName, response.value as string);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function askOverrideVersion(options: {
|
|
137
|
+
packageName: string;
|
|
138
|
+
suggestedVersions: string[];
|
|
139
|
+
reason: string;
|
|
140
|
+
}): Promise<string | undefined> {
|
|
141
|
+
console.log("");
|
|
142
|
+
console.log(`Detected package conflict: ${options.packageName}`);
|
|
143
|
+
console.log(options.reason);
|
|
144
|
+
console.log("");
|
|
145
|
+
|
|
146
|
+
const choices = [
|
|
147
|
+
...options.suggestedVersions.map((version) => ({ title: version, value: version })),
|
|
148
|
+
{ title: "Enter new version", value: "__ENTER_NEW_VERSION__" },
|
|
149
|
+
{ title: "Skip", value: "__SKIP__" },
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
const response = await prompts({
|
|
153
|
+
type: "select",
|
|
154
|
+
name: "value",
|
|
155
|
+
message: `Override version for ${options.packageName}`,
|
|
156
|
+
choices,
|
|
157
|
+
initial: 0,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (!response.value || response.value === "__SKIP__") {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (response.value !== "__ENTER_NEW_VERSION__") {
|
|
165
|
+
return response.value as string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const input = await prompts({
|
|
169
|
+
type: "text",
|
|
170
|
+
name: "version",
|
|
171
|
+
message: `Enter version for ${options.packageName}`,
|
|
172
|
+
initial: options.suggestedVersions[0] ?? "",
|
|
173
|
+
validate: (value: string) => value?.trim() ? true : "Version is required",
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return input.version as string | undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function askOverridesFromDoctor(options: {
|
|
180
|
+
repositoryPath: string;
|
|
181
|
+
packageNames: string[];
|
|
182
|
+
currentOverrides: Record<string, string>;
|
|
183
|
+
}): Promise<Record<string, string>> {
|
|
184
|
+
const overrides: Record<string, string> = { ...options.currentOverrides };
|
|
185
|
+
const conflicts = await inspectPackageConflicts({
|
|
186
|
+
repositoryPath: options.repositoryPath,
|
|
187
|
+
packageNames: options.packageNames,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
for (const conflict of conflicts) {
|
|
191
|
+
if (overrides[conflict.packageName]) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const selectedVersion = await askOverrideVersion({
|
|
196
|
+
packageName: conflict.packageName,
|
|
197
|
+
suggestedVersions: conflict.suggestedVersions,
|
|
198
|
+
reason: [
|
|
199
|
+
`Found ${conflict.doctorResult.occurrences.length} installed location(s).`,
|
|
200
|
+
`Versions: ${conflict.doctorResult.versions.join(", ") || "unknown"}`,
|
|
201
|
+
`This may cause "was loaded from different locations" errors.`,
|
|
202
|
+
].join("\n"),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
if (selectedVersion) {
|
|
206
|
+
overrides[conflict.packageName] = selectedVersion;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
await rememberResolvedOverrideVersions(overrides);
|
|
211
|
+
return overrides;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function askOverridesFromLoadedLocationError(options: {
|
|
215
|
+
repositoryPath: string;
|
|
216
|
+
output: string;
|
|
217
|
+
currentOverrides: Record<string, string>;
|
|
218
|
+
}): Promise<Record<string, string>> {
|
|
219
|
+
const overrides: Record<string, string> = { ...options.currentOverrides };
|
|
220
|
+
const conflicts = parseLoadedLocationConflicts(options.output);
|
|
221
|
+
|
|
222
|
+
for (const conflict of conflicts) {
|
|
223
|
+
if (overrides[conflict.packageName]) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const doctorConflicts = await inspectPackageConflicts({
|
|
228
|
+
repositoryPath: options.repositoryPath,
|
|
229
|
+
packageNames: [conflict.packageName],
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const suggestedVersions = doctorConflicts[0]?.suggestedVersions ?? [];
|
|
233
|
+
const selectedVersion = await askOverrideVersion({
|
|
234
|
+
packageName: conflict.packageName,
|
|
235
|
+
suggestedVersions,
|
|
236
|
+
reason: conflict.rawMessage,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (selectedVersion) {
|
|
240
|
+
overrides[conflict.packageName] = selectedVersion;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
await rememberResolvedOverrideVersions(overrides);
|
|
245
|
+
return overrides;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function runInstallCommand(options: TInstallCommandOptions): Promise<void> {
|
|
249
|
+
const repositoryPath = await resolveRepositoryPath(options.cwd ?? process.cwd());
|
|
250
|
+
const installCommand = options.cmd ?? "npm install";
|
|
251
|
+
const filePatterns = options.pattern ?? ["package.json"];
|
|
252
|
+
const providedVariableValues = parseKeyValueList(options.set);
|
|
253
|
+
let temporaryOverrides = parseKeyValueList(options.override);
|
|
254
|
+
|
|
255
|
+
const variableValues = await askMissingVariables({
|
|
256
|
+
repositoryPath,
|
|
257
|
+
filePatterns,
|
|
258
|
+
providedValues: providedVariableValues,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const checkPackageNames = options.checkPackage?.length ? options.checkPackage : ["@sap/cds"];
|
|
262
|
+
|
|
263
|
+
if (options.autoDoctor !== false) {
|
|
264
|
+
temporaryOverrides = await askOverridesFromDoctor({
|
|
265
|
+
repositoryPath,
|
|
266
|
+
packageNames: checkPackageNames,
|
|
267
|
+
currentOverrides: temporaryOverrides,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
for (const [packageName, version] of Object.entries(temporaryOverrides)) {
|
|
272
|
+
await rememberOverrideValue(packageName, version);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let installResult = await installRepository({
|
|
276
|
+
repositoryPath,
|
|
277
|
+
installCommand,
|
|
278
|
+
variableValues,
|
|
279
|
+
temporaryOverrides,
|
|
280
|
+
filePatterns,
|
|
281
|
+
onLog: (value) => process.stdout.write(value),
|
|
282
|
+
onErrorLog: (value) => process.stderr.write(value),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const fullOutput = `${installResult.stdout}\n${installResult.stderr}`;
|
|
286
|
+
const loadedLocationConflicts = parseLoadedLocationConflicts(fullOutput);
|
|
287
|
+
|
|
288
|
+
if (loadedLocationConflicts.length > 0) {
|
|
289
|
+
console.log("");
|
|
290
|
+
console.log("Loaded-from-different-locations error detected.");
|
|
291
|
+
console.log("The tool can retry install with temporary overrides.");
|
|
292
|
+
console.log("");
|
|
293
|
+
|
|
294
|
+
const nextOverrides = await askOverridesFromLoadedLocationError({
|
|
295
|
+
repositoryPath,
|
|
296
|
+
output: fullOutput,
|
|
297
|
+
currentOverrides: temporaryOverrides,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const hasNewOverride = JSON.stringify(nextOverrides) !== JSON.stringify(temporaryOverrides);
|
|
301
|
+
|
|
302
|
+
if (hasNewOverride) {
|
|
303
|
+
console.log("");
|
|
304
|
+
console.log("Retrying install with temporary overrides...");
|
|
305
|
+
console.log("");
|
|
306
|
+
|
|
307
|
+
installResult = await installRepository({
|
|
308
|
+
repositoryPath,
|
|
309
|
+
installCommand,
|
|
310
|
+
variableValues,
|
|
311
|
+
temporaryOverrides: nextOverrides,
|
|
312
|
+
filePatterns,
|
|
313
|
+
onLog: (value) => process.stdout.write(value),
|
|
314
|
+
onErrorLog: (value) => process.stderr.write(value),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
process.exitCode = installResult.exitCode;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
program.name("simplemdg").description("SimpleMDG local development helper").version("2.4.0");
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
program
|
|
326
|
+
.command("guide")
|
|
327
|
+
.alias("docs")
|
|
328
|
+
.description("Open or print the SimpleMDG Dev CLI user guide")
|
|
329
|
+
.option("--web", "Open the visual local guide in browser")
|
|
330
|
+
.option("--terminal", "Print guide in terminal")
|
|
331
|
+
.option("--port <port>", "Local guide server port")
|
|
332
|
+
.action(async (options: { web?: boolean; terminal?: boolean; port?: string }) => {
|
|
333
|
+
if (options.terminal) {
|
|
334
|
+
await printUserGuide();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (options.web) {
|
|
339
|
+
await openUserGuideInBrowser(options.port);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const mode = await askRootHelpMode();
|
|
344
|
+
|
|
345
|
+
if (mode === "web") {
|
|
346
|
+
await openUserGuideInBrowser(options.port);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (mode === "terminal") {
|
|
351
|
+
await printUserGuide();
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
program.outputHelp();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
program
|
|
359
|
+
.command("scan")
|
|
360
|
+
.description("Scan current repository for ${VARIABLE_NAME} placeholders")
|
|
361
|
+
.option("--cwd <path>", "Repository path", process.cwd())
|
|
362
|
+
.option("--pattern <pattern...>", "File patterns", ["package.json"])
|
|
363
|
+
.action(async (options: { cwd: string; pattern: string[] }) => {
|
|
364
|
+
const repositoryPath = await resolveRepositoryPath(options.cwd);
|
|
365
|
+
const scannedVariables = await scanRepositoryVariables({ repositoryPath, filePatterns: options.pattern });
|
|
366
|
+
|
|
367
|
+
if (scannedVariables.length === 0) {
|
|
368
|
+
console.log("No variables found.");
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
for (const item of scannedVariables) {
|
|
373
|
+
console.log(`${item.variableName} | ${item.occurrences} occurrence(s) | ${item.filePath}`);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
program
|
|
378
|
+
.command("install")
|
|
379
|
+
.alias("i")
|
|
380
|
+
.description("Install current repository with temporary variable replacement and temporary overrides")
|
|
381
|
+
.option("--cwd <path>", "Repository path", process.cwd())
|
|
382
|
+
.option("--cmd <command>", "Install command", "npm install")
|
|
383
|
+
.option("--set <keyValue...>", "Variable value. Example: --set SIMPLEMDG_BRANCH=sandbox")
|
|
384
|
+
.option("--override <keyValue...>", "Temporary override. Example: --override @sap/cds=9.8.3")
|
|
385
|
+
.option("--pattern <pattern...>", "File patterns", ["package.json"])
|
|
386
|
+
.option("--check-package <packageName...>", "Packages to check for duplicated loaded locations", ["@sap/cds"])
|
|
387
|
+
.option("--no-auto-doctor", "Disable automatic duplicated package inspection")
|
|
388
|
+
.action(runInstallCommand);
|
|
389
|
+
|
|
390
|
+
program
|
|
391
|
+
.command("doctor")
|
|
392
|
+
.description("Inspect duplicated package versions in current repository")
|
|
393
|
+
.option("--cwd <path>", "Repository path", process.cwd())
|
|
394
|
+
.option("--package <packageName>", "Package name", "@sap/cds")
|
|
395
|
+
.action(async (options: { cwd: string; package: string }) => {
|
|
396
|
+
const repositoryPath = await resolveRepositoryPath(options.cwd);
|
|
397
|
+
const result = await doctorPackage({ repositoryPath, packageName: options.package });
|
|
398
|
+
|
|
399
|
+
console.log(`Package: ${result.packageName}`);
|
|
400
|
+
console.log(`Versions: ${result.versions.join(", ") || "N/A"}`);
|
|
401
|
+
console.log(`Occurrences: ${result.occurrences.length}`);
|
|
402
|
+
|
|
403
|
+
for (const occurrence of result.occurrences) {
|
|
404
|
+
console.log(`- ${occurrence.version ?? "unknown"} | ${occurrence.path ?? "unknown path"}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (result.hasMultipleVersions || result.occurrences.length > 1) {
|
|
408
|
+
console.log("");
|
|
409
|
+
console.log("Suggestion:");
|
|
410
|
+
console.log(`simplemdg install --override ${result.packageName}=<version>`);
|
|
411
|
+
console.log("");
|
|
412
|
+
console.log("Example:");
|
|
413
|
+
console.log(`simplemdg install --override ${result.packageName}=9.8.3`);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
registerCloudFoundryCommands(program);
|
|
418
|
+
registerCdsCommands(program);
|
|
419
|
+
registerNpmrcCommands(program);
|
|
420
|
+
registerGitLabCommands(program);
|
|
421
|
+
|
|
422
|
+
// Turn every group command (cf, cf db, cds, npmrc, gitlab, ...) into an
|
|
423
|
+
// interactive menu so a partial command like `smdg cf` or `smdg cf db` lists
|
|
424
|
+
// its subcommands to pick from instead of printing help.
|
|
425
|
+
enableInteractiveNavigation(program);
|
|
426
|
+
|
|
427
|
+
async function runCli(): Promise<void> {
|
|
428
|
+
const userArguments = process.argv.slice(2);
|
|
429
|
+
|
|
430
|
+
if (userArguments.length === 0) {
|
|
431
|
+
await runGroupNavigator(program);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const isRootHelp = process.argv.length <= 3 && ["--help", "-h"].includes(process.argv[2] ?? "");
|
|
436
|
+
|
|
437
|
+
if (isRootHelp) {
|
|
438
|
+
const mode = await askRootHelpMode();
|
|
439
|
+
|
|
440
|
+
if (mode === "web") {
|
|
441
|
+
await openUserGuideInBrowser();
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (mode === "terminal") {
|
|
446
|
+
await printUserGuide();
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
program.outputHelp();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
await program.parseAsync();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
runCli().catch((error: unknown) => {
|
|
458
|
+
console.error(error instanceof Error ? error.message : error);
|
|
459
|
+
process.exit(1);
|
|
460
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"rootDir": "src",
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"resolveJsonModule": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts"]
|
|
17
|
+
}
|