@git.zone/cli 2.13.15 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/gitzone.cli.js +46 -35
- package/dist_ts/helpers.climode.d.ts +22 -0
- package/dist_ts/helpers.climode.js +158 -0
- package/dist_ts/helpers.smartconfig.d.ts +11 -0
- package/dist_ts/helpers.smartconfig.js +139 -0
- package/dist_ts/mod_commit/index.d.ts +2 -0
- package/dist_ts/mod_commit/index.js +204 -92
- package/dist_ts/mod_config/index.d.ts +7 -2
- package/dist_ts/mod_config/index.js +390 -176
- package/dist_ts/mod_format/classes.formatcontext.d.ts +11 -2
- package/dist_ts/mod_format/classes.formatcontext.js +14 -4
- package/dist_ts/mod_format/formatters/packagejson.formatter.js +1 -67
- package/dist_ts/mod_format/formatters/smartconfig.formatter.d.ts +2 -2
- package/dist_ts/mod_format/formatters/smartconfig.formatter.js +46 -39
- package/dist_ts/mod_format/index.d.ts +4 -1
- package/dist_ts/mod_format/index.js +221 -75
- package/dist_ts/mod_format/mod.plugins.d.ts +1 -2
- package/dist_ts/mod_format/mod.plugins.js +2 -3
- package/dist_ts/mod_services/index.d.ts +2 -0
- package/dist_ts/mod_services/index.js +366 -168
- package/dist_ts/mod_standard/index.d.ts +3 -1
- package/dist_ts/mod_standard/index.js +159 -59
- package/package.json +1 -1
- package/readme.hints.md +25 -32
- package/readme.md +87 -65
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/gitzone.cli.ts +50 -38
- package/ts/helpers.climode.ts +212 -0
- package/ts/helpers.smartconfig.ts +192 -0
- package/ts/mod_commit/index.ts +325 -98
- package/ts/mod_config/index.ts +490 -182
- package/ts/mod_format/classes.formatcontext.ts +20 -3
- package/ts/mod_format/formatters/packagejson.formatter.ts +0 -91
- package/ts/mod_format/formatters/smartconfig.formatter.ts +55 -39
- package/ts/mod_format/index.ts +279 -90
- package/ts/mod_format/mod.plugins.ts +0 -2
- package/ts/mod_services/index.ts +550 -183
- package/ts/mod_standard/index.ts +191 -58
package/ts/gitzone.cli.ts
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
import * as plugins from
|
|
2
|
-
import * as paths from
|
|
3
|
-
import { GitzoneConfig } from
|
|
1
|
+
import * as plugins from "./plugins.js";
|
|
2
|
+
import * as paths from "./paths.js";
|
|
3
|
+
import { GitzoneConfig } from "./classes.gitzoneconfig.js";
|
|
4
|
+
import { getRawCliMode } from "./helpers.climode.js";
|
|
4
5
|
|
|
5
6
|
const gitzoneSmartcli = new plugins.smartcli.Smartcli();
|
|
6
7
|
|
|
7
8
|
export let run = async () => {
|
|
8
9
|
const done = plugins.smartpromise.defer();
|
|
10
|
+
const rawCliMode = await getRawCliMode();
|
|
9
11
|
|
|
10
12
|
// get packageInfo
|
|
11
13
|
const projectInfo = new plugins.projectinfo.ProjectInfo(paths.packageDir);
|
|
12
14
|
|
|
13
15
|
// check for updates
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
if (rawCliMode.checkUpdates) {
|
|
17
|
+
const smartupdateInstance = new plugins.smartupdate.SmartUpdate();
|
|
18
|
+
await smartupdateInstance.check(
|
|
19
|
+
"gitzone",
|
|
20
|
+
projectInfo.npm.version,
|
|
21
|
+
"http://gitzone.gitlab.io/gitzone/changelog.html",
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
if (rawCliMode.output === "human") {
|
|
25
|
+
console.log("---------------------------------------------");
|
|
26
|
+
}
|
|
21
27
|
gitzoneSmartcli.addVersion(projectInfo.npm.version);
|
|
22
28
|
|
|
23
29
|
// ======> Standard task <======
|
|
@@ -26,8 +32,13 @@ export let run = async () => {
|
|
|
26
32
|
* standard task
|
|
27
33
|
*/
|
|
28
34
|
gitzoneSmartcli.standardCommand().subscribe(async (argvArg) => {
|
|
29
|
-
const modStandard = await import(
|
|
30
|
-
await modStandard.run();
|
|
35
|
+
const modStandard = await import("./mod_standard/index.js");
|
|
36
|
+
await modStandard.run(argvArg);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
gitzoneSmartcli.addCommand("help").subscribe(async (argvArg) => {
|
|
40
|
+
const modStandard = await import("./mod_standard/index.js");
|
|
41
|
+
await modStandard.run(argvArg);
|
|
31
42
|
});
|
|
32
43
|
|
|
33
44
|
// ======> Specific tasks <======
|
|
@@ -35,43 +46,44 @@ export let run = async () => {
|
|
|
35
46
|
/**
|
|
36
47
|
* commit something
|
|
37
48
|
*/
|
|
38
|
-
gitzoneSmartcli.addCommand(
|
|
39
|
-
const modCommit = await import(
|
|
49
|
+
gitzoneSmartcli.addCommand("commit").subscribe(async (argvArg) => {
|
|
50
|
+
const modCommit = await import("./mod_commit/index.js");
|
|
40
51
|
await modCommit.run(argvArg);
|
|
41
52
|
});
|
|
42
53
|
|
|
43
54
|
/**
|
|
44
55
|
* deprecate a package on npm
|
|
45
56
|
*/
|
|
46
|
-
gitzoneSmartcli.addCommand(
|
|
47
|
-
const modDeprecate = await import(
|
|
57
|
+
gitzoneSmartcli.addCommand("deprecate").subscribe(async (argvArg) => {
|
|
58
|
+
const modDeprecate = await import("./mod_deprecate/index.js");
|
|
48
59
|
await modDeprecate.run();
|
|
49
60
|
});
|
|
50
61
|
|
|
51
62
|
/**
|
|
52
63
|
* docker
|
|
53
64
|
*/
|
|
54
|
-
gitzoneSmartcli.addCommand(
|
|
55
|
-
const modDocker = await import(
|
|
65
|
+
gitzoneSmartcli.addCommand("docker").subscribe(async (argvArg) => {
|
|
66
|
+
const modDocker = await import("./mod_docker/index.js");
|
|
56
67
|
await modDocker.run(argvArg);
|
|
57
68
|
});
|
|
58
69
|
|
|
59
70
|
/**
|
|
60
71
|
* Update all files that comply with the gitzone standard
|
|
61
72
|
*/
|
|
62
|
-
gitzoneSmartcli.addCommand(
|
|
73
|
+
gitzoneSmartcli.addCommand("format").subscribe(async (argvArg) => {
|
|
63
74
|
const config = GitzoneConfig.fromCwd();
|
|
64
|
-
const modFormat = await import(
|
|
75
|
+
const modFormat = await import("./mod_format/index.js");
|
|
65
76
|
|
|
66
77
|
// Handle format with options
|
|
67
78
|
// Default is dry-mode, use --write/-w to apply changes
|
|
68
79
|
await modFormat.run({
|
|
80
|
+
...argvArg,
|
|
69
81
|
write: argvArg.write || argvArg.w,
|
|
70
|
-
dryRun: argvArg[
|
|
82
|
+
dryRun: argvArg["dry-run"],
|
|
71
83
|
yes: argvArg.yes,
|
|
72
|
-
planOnly: argvArg[
|
|
73
|
-
savePlan: argvArg[
|
|
74
|
-
fromPlan: argvArg[
|
|
84
|
+
planOnly: argvArg["plan-only"],
|
|
85
|
+
savePlan: argvArg["save-plan"],
|
|
86
|
+
fromPlan: argvArg["from-plan"],
|
|
75
87
|
detailed: argvArg.detailed,
|
|
76
88
|
interactive: argvArg.interactive !== false,
|
|
77
89
|
verbose: argvArg.verbose,
|
|
@@ -82,54 +94,54 @@ export let run = async () => {
|
|
|
82
94
|
/**
|
|
83
95
|
* run meta commands
|
|
84
96
|
*/
|
|
85
|
-
gitzoneSmartcli.addCommand(
|
|
97
|
+
gitzoneSmartcli.addCommand("meta").subscribe(async (argvArg) => {
|
|
86
98
|
const config = GitzoneConfig.fromCwd();
|
|
87
|
-
const modMeta = await import(
|
|
99
|
+
const modMeta = await import("./mod_meta/index.js");
|
|
88
100
|
modMeta.run(argvArg);
|
|
89
101
|
});
|
|
90
102
|
|
|
91
103
|
/**
|
|
92
104
|
* open assets
|
|
93
105
|
*/
|
|
94
|
-
gitzoneSmartcli.addCommand(
|
|
95
|
-
const modOpen = await import(
|
|
106
|
+
gitzoneSmartcli.addCommand("open").subscribe(async (argvArg) => {
|
|
107
|
+
const modOpen = await import("./mod_open/index.js");
|
|
96
108
|
modOpen.run(argvArg);
|
|
97
109
|
});
|
|
98
110
|
|
|
99
111
|
/**
|
|
100
112
|
* add a readme to a project
|
|
101
113
|
*/
|
|
102
|
-
gitzoneSmartcli.addCommand(
|
|
103
|
-
const modTemplate = await import(
|
|
114
|
+
gitzoneSmartcli.addCommand("template").subscribe(async (argvArg) => {
|
|
115
|
+
const modTemplate = await import("./mod_template/index.js");
|
|
104
116
|
modTemplate.run(argvArg);
|
|
105
117
|
});
|
|
106
118
|
|
|
107
119
|
/**
|
|
108
120
|
* start working on a project
|
|
109
121
|
*/
|
|
110
|
-
gitzoneSmartcli.addCommand(
|
|
111
|
-
const modTemplate = await import(
|
|
122
|
+
gitzoneSmartcli.addCommand("start").subscribe(async (argvArg) => {
|
|
123
|
+
const modTemplate = await import("./mod_start/index.js");
|
|
112
124
|
modTemplate.run(argvArg);
|
|
113
125
|
});
|
|
114
126
|
|
|
115
|
-
gitzoneSmartcli.addCommand(
|
|
116
|
-
const modHelpers = await import(
|
|
127
|
+
gitzoneSmartcli.addCommand("helpers").subscribe(async (argvArg) => {
|
|
128
|
+
const modHelpers = await import("./mod_helpers/index.js");
|
|
117
129
|
modHelpers.run(argvArg);
|
|
118
130
|
});
|
|
119
131
|
|
|
120
132
|
/**
|
|
121
133
|
* manage release configuration
|
|
122
134
|
*/
|
|
123
|
-
gitzoneSmartcli.addCommand(
|
|
124
|
-
const modConfig = await import(
|
|
135
|
+
gitzoneSmartcli.addCommand("config").subscribe(async (argvArg) => {
|
|
136
|
+
const modConfig = await import("./mod_config/index.js");
|
|
125
137
|
await modConfig.run(argvArg);
|
|
126
138
|
});
|
|
127
139
|
|
|
128
140
|
/**
|
|
129
141
|
* manage development services (MongoDB, S3/MinIO)
|
|
130
142
|
*/
|
|
131
|
-
gitzoneSmartcli.addCommand(
|
|
132
|
-
const modServices = await import(
|
|
143
|
+
gitzoneSmartcli.addCommand("services").subscribe(async (argvArg) => {
|
|
144
|
+
const modServices = await import("./mod_services/index.js");
|
|
133
145
|
await modServices.run(argvArg);
|
|
134
146
|
});
|
|
135
147
|
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { getCliConfigValue } from "./helpers.smartconfig.js";
|
|
2
|
+
|
|
3
|
+
export type TCliOutputMode = "human" | "plain" | "json";
|
|
4
|
+
|
|
5
|
+
export interface ICliMode {
|
|
6
|
+
output: TCliOutputMode;
|
|
7
|
+
interactive: boolean;
|
|
8
|
+
json: boolean;
|
|
9
|
+
plain: boolean;
|
|
10
|
+
quiet: boolean;
|
|
11
|
+
yes: boolean;
|
|
12
|
+
help: boolean;
|
|
13
|
+
agent: boolean;
|
|
14
|
+
checkUpdates: boolean;
|
|
15
|
+
isTty: boolean;
|
|
16
|
+
command?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ICliConfigSettings {
|
|
20
|
+
interactive?: boolean;
|
|
21
|
+
output?: TCliOutputMode;
|
|
22
|
+
checkUpdates?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type TArgSource = Record<string, any> & { _?: string[] };
|
|
26
|
+
|
|
27
|
+
const camelCase = (value: string): string => {
|
|
28
|
+
return value.replace(/-([a-z])/g, (_match, group: string) =>
|
|
29
|
+
group.toUpperCase(),
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const getArgValue = (argvArg: TArgSource, key: string): any => {
|
|
34
|
+
const keyVariants = [key, camelCase(key), key.replace(/-/g, "")];
|
|
35
|
+
for (const keyVariant of keyVariants) {
|
|
36
|
+
if (argvArg[keyVariant] !== undefined) {
|
|
37
|
+
return argvArg[keyVariant];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const parseRawArgv = (argv: string[]): TArgSource => {
|
|
44
|
+
const parsedArgv: TArgSource = { _: [] };
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < argv.length; i++) {
|
|
47
|
+
const currentArg = argv[i];
|
|
48
|
+
|
|
49
|
+
if (currentArg.startsWith("--no-")) {
|
|
50
|
+
const key = currentArg.slice(5);
|
|
51
|
+
parsedArgv[key] = false;
|
|
52
|
+
parsedArgv[camelCase(key)] = false;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (currentArg.startsWith("--")) {
|
|
57
|
+
const withoutPrefix = currentArg.slice(2);
|
|
58
|
+
const [rawKey, inlineValue] = withoutPrefix.split("=", 2);
|
|
59
|
+
if (inlineValue !== undefined) {
|
|
60
|
+
parsedArgv[rawKey] = inlineValue;
|
|
61
|
+
parsedArgv[camelCase(rawKey)] = inlineValue;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const nextArg = argv[i + 1];
|
|
66
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
67
|
+
parsedArgv[rawKey] = nextArg;
|
|
68
|
+
parsedArgv[camelCase(rawKey)] = nextArg;
|
|
69
|
+
i++;
|
|
70
|
+
} else {
|
|
71
|
+
parsedArgv[rawKey] = true;
|
|
72
|
+
parsedArgv[camelCase(rawKey)] = true;
|
|
73
|
+
}
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (currentArg.startsWith("-") && currentArg.length > 1) {
|
|
78
|
+
for (const shortFlag of currentArg.slice(1).split("")) {
|
|
79
|
+
parsedArgv[shortFlag] = true;
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
parsedArgv._ = parsedArgv._ || [];
|
|
85
|
+
parsedArgv._.push(currentArg);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return parsedArgv;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const normalizeOutputMode = (value: unknown): TCliOutputMode | undefined => {
|
|
92
|
+
if (value === "human" || value === "plain" || value === "json") {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const resolveCliMode = (
|
|
99
|
+
argvArg: TArgSource,
|
|
100
|
+
cliConfig: ICliConfigSettings,
|
|
101
|
+
): ICliMode => {
|
|
102
|
+
const isTty = Boolean(process.stdout?.isTTY && process.stdin?.isTTY);
|
|
103
|
+
const agentMode = Boolean(getArgValue(argvArg, "agent"));
|
|
104
|
+
const outputOverride = normalizeOutputMode(getArgValue(argvArg, "output"));
|
|
105
|
+
|
|
106
|
+
let output: TCliOutputMode =
|
|
107
|
+
normalizeOutputMode(cliConfig.output) || (isTty ? "human" : "plain");
|
|
108
|
+
if (agentMode || getArgValue(argvArg, "json")) {
|
|
109
|
+
output = "json";
|
|
110
|
+
} else if (getArgValue(argvArg, "plain")) {
|
|
111
|
+
output = "plain";
|
|
112
|
+
} else if (outputOverride) {
|
|
113
|
+
output = outputOverride;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const interactiveSetting = getArgValue(argvArg, "interactive");
|
|
117
|
+
let interactive = cliConfig.interactive ?? isTty;
|
|
118
|
+
if (interactiveSetting === true) {
|
|
119
|
+
interactive = true;
|
|
120
|
+
} else if (interactiveSetting === false) {
|
|
121
|
+
interactive = false;
|
|
122
|
+
}
|
|
123
|
+
if (!isTty || output !== "human" || agentMode) {
|
|
124
|
+
interactive = false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const checkUpdatesSetting = getArgValue(argvArg, "check-updates");
|
|
128
|
+
let checkUpdates = cliConfig.checkUpdates ?? output === "human";
|
|
129
|
+
if (checkUpdatesSetting === true) {
|
|
130
|
+
checkUpdates = true;
|
|
131
|
+
} else if (checkUpdatesSetting === false) {
|
|
132
|
+
checkUpdates = false;
|
|
133
|
+
}
|
|
134
|
+
if (output !== "human" || agentMode) {
|
|
135
|
+
checkUpdates = false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
output,
|
|
140
|
+
interactive,
|
|
141
|
+
json: output === "json",
|
|
142
|
+
plain: output === "plain",
|
|
143
|
+
quiet: Boolean(
|
|
144
|
+
getArgValue(argvArg, "quiet") ||
|
|
145
|
+
getArgValue(argvArg, "q") ||
|
|
146
|
+
output === "json",
|
|
147
|
+
),
|
|
148
|
+
yes: Boolean(getArgValue(argvArg, "yes") || getArgValue(argvArg, "y")),
|
|
149
|
+
help: Boolean(
|
|
150
|
+
getArgValue(argvArg, "help") ||
|
|
151
|
+
getArgValue(argvArg, "h") ||
|
|
152
|
+
argvArg._?.[0] === "help",
|
|
153
|
+
),
|
|
154
|
+
agent: agentMode,
|
|
155
|
+
checkUpdates,
|
|
156
|
+
isTty,
|
|
157
|
+
command: argvArg._?.[0],
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const getCliModeConfig = async (): Promise<ICliConfigSettings> => {
|
|
162
|
+
return await getCliConfigValue<ICliConfigSettings>("cli", {});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const getCliMode = async (
|
|
166
|
+
argvArg: TArgSource = {},
|
|
167
|
+
): Promise<ICliMode> => {
|
|
168
|
+
const cliConfig = await getCliModeConfig();
|
|
169
|
+
return resolveCliMode(argvArg, cliConfig);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export const getRawCliMode = async (): Promise<ICliMode> => {
|
|
173
|
+
const cliConfig = await getCliModeConfig();
|
|
174
|
+
const rawArgv = parseRawArgv(process.argv.slice(2));
|
|
175
|
+
return resolveCliMode(rawArgv, cliConfig);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const printJson = (data: unknown): void => {
|
|
179
|
+
console.log(JSON.stringify(data, null, 2));
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export const runWithSuppressedOutput = async <T>(
|
|
183
|
+
fn: () => Promise<T>,
|
|
184
|
+
): Promise<T> => {
|
|
185
|
+
const originalConsole = {
|
|
186
|
+
log: console.log,
|
|
187
|
+
info: console.info,
|
|
188
|
+
warn: console.warn,
|
|
189
|
+
error: console.error,
|
|
190
|
+
};
|
|
191
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
192
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
193
|
+
const noop = () => undefined;
|
|
194
|
+
|
|
195
|
+
console.log = noop;
|
|
196
|
+
console.info = noop;
|
|
197
|
+
console.warn = noop;
|
|
198
|
+
console.error = noop;
|
|
199
|
+
process.stdout.write = (() => true) as typeof process.stdout.write;
|
|
200
|
+
process.stderr.write = (() => true) as typeof process.stderr.write;
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
return await fn();
|
|
204
|
+
} finally {
|
|
205
|
+
console.log = originalConsole.log;
|
|
206
|
+
console.info = originalConsole.info;
|
|
207
|
+
console.warn = originalConsole.warn;
|
|
208
|
+
console.error = originalConsole.error;
|
|
209
|
+
process.stdout.write = originalStdoutWrite;
|
|
210
|
+
process.stderr.write = originalStderrWrite;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as plugins from "./plugins.js";
|
|
2
|
+
import { rename, writeFile } from "fs/promises";
|
|
3
|
+
|
|
4
|
+
export const CLI_NAMESPACE = "@git.zone/cli";
|
|
5
|
+
|
|
6
|
+
const isPlainObject = (value: unknown): value is Record<string, any> => {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getSmartconfigPath = (cwd: string = process.cwd()): string => {
|
|
11
|
+
return plugins.path.join(cwd, ".smartconfig.json");
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const readSmartconfigFile = async (
|
|
15
|
+
cwd: string = process.cwd(),
|
|
16
|
+
): Promise<Record<string, any>> => {
|
|
17
|
+
const smartconfigPath = getSmartconfigPath(cwd);
|
|
18
|
+
if (!(await plugins.smartfs.file(smartconfigPath).exists())) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const content = (await plugins.smartfs
|
|
23
|
+
.file(smartconfigPath)
|
|
24
|
+
.encoding("utf8")
|
|
25
|
+
.read()) as string;
|
|
26
|
+
if (content.trim() === "") {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
return JSON.parse(content);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const writeSmartconfigFile = async (
|
|
33
|
+
data: Record<string, any>,
|
|
34
|
+
cwd: string = process.cwd(),
|
|
35
|
+
): Promise<void> => {
|
|
36
|
+
const smartconfigPath = getSmartconfigPath(cwd);
|
|
37
|
+
const tempPath = `${smartconfigPath}.tmp-${Date.now()}`;
|
|
38
|
+
const content = JSON.stringify(data, null, 2);
|
|
39
|
+
await writeFile(tempPath, content, "utf8");
|
|
40
|
+
await rename(tempPath, smartconfigPath);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const normalizeCliConfigPath = (configPath: string): string => {
|
|
44
|
+
const trimmedPath = configPath.trim();
|
|
45
|
+
if (!trimmedPath || trimmedPath === CLI_NAMESPACE) {
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (trimmedPath.startsWith(`${CLI_NAMESPACE}.`)) {
|
|
50
|
+
return trimmedPath.slice(`${CLI_NAMESPACE}.`.length);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return trimmedPath;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const getCliConfigPathSegments = (configPath: string): string[] => {
|
|
57
|
+
const normalizedPath = normalizeCliConfigPath(configPath);
|
|
58
|
+
if (!normalizedPath) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return normalizedPath
|
|
63
|
+
.split(".")
|
|
64
|
+
.map((segment) => segment.trim())
|
|
65
|
+
.filter(Boolean);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const getCliNamespaceConfig = (
|
|
69
|
+
smartconfigData: Record<string, any>,
|
|
70
|
+
): Record<string, any> => {
|
|
71
|
+
const cliConfig = smartconfigData[CLI_NAMESPACE];
|
|
72
|
+
if (isPlainObject(cliConfig)) {
|
|
73
|
+
return cliConfig;
|
|
74
|
+
}
|
|
75
|
+
return {};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const getCliConfigValueFromData = (
|
|
79
|
+
smartconfigData: Record<string, any>,
|
|
80
|
+
configPath: string,
|
|
81
|
+
): any => {
|
|
82
|
+
const segments = getCliConfigPathSegments(configPath);
|
|
83
|
+
let currentValue: any = getCliNamespaceConfig(smartconfigData);
|
|
84
|
+
|
|
85
|
+
for (const segment of segments) {
|
|
86
|
+
if (!isPlainObject(currentValue) && !Array.isArray(currentValue)) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
currentValue = (currentValue as any)?.[segment];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return currentValue;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const getCliConfigValue = async <T>(
|
|
96
|
+
configPath: string,
|
|
97
|
+
defaultValue: T,
|
|
98
|
+
cwd: string = process.cwd(),
|
|
99
|
+
): Promise<T> => {
|
|
100
|
+
const smartconfigData = await readSmartconfigFile(cwd);
|
|
101
|
+
const configValue = getCliConfigValueFromData(smartconfigData, configPath);
|
|
102
|
+
|
|
103
|
+
if (configValue === undefined) {
|
|
104
|
+
return defaultValue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (isPlainObject(defaultValue) && isPlainObject(configValue)) {
|
|
108
|
+
return {
|
|
109
|
+
...defaultValue,
|
|
110
|
+
...configValue,
|
|
111
|
+
} as T;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return configValue as T;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const setCliConfigValueInData = (
|
|
118
|
+
smartconfigData: Record<string, any>,
|
|
119
|
+
configPath: string,
|
|
120
|
+
value: any,
|
|
121
|
+
): Record<string, any> => {
|
|
122
|
+
const segments = getCliConfigPathSegments(configPath);
|
|
123
|
+
|
|
124
|
+
if (!isPlainObject(smartconfigData[CLI_NAMESPACE])) {
|
|
125
|
+
smartconfigData[CLI_NAMESPACE] = {};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (segments.length === 0) {
|
|
129
|
+
smartconfigData[CLI_NAMESPACE] = value;
|
|
130
|
+
return smartconfigData;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let currentValue = smartconfigData[CLI_NAMESPACE];
|
|
134
|
+
for (const segment of segments.slice(0, -1)) {
|
|
135
|
+
if (!isPlainObject(currentValue[segment])) {
|
|
136
|
+
currentValue[segment] = {};
|
|
137
|
+
}
|
|
138
|
+
currentValue = currentValue[segment];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
currentValue[segments[segments.length - 1]] = value;
|
|
142
|
+
return smartconfigData;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const unsetCliConfigValueInData = (
|
|
146
|
+
smartconfigData: Record<string, any>,
|
|
147
|
+
configPath: string,
|
|
148
|
+
): boolean => {
|
|
149
|
+
const segments = getCliConfigPathSegments(configPath);
|
|
150
|
+
if (segments.length === 0) {
|
|
151
|
+
if (smartconfigData[CLI_NAMESPACE] !== undefined) {
|
|
152
|
+
delete smartconfigData[CLI_NAMESPACE];
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const parentSegments = segments.slice(0, -1);
|
|
159
|
+
let currentValue: any = getCliNamespaceConfig(smartconfigData);
|
|
160
|
+
const objectPath: Array<Record<string, any>> = [currentValue];
|
|
161
|
+
|
|
162
|
+
for (const segment of parentSegments) {
|
|
163
|
+
if (!isPlainObject(currentValue[segment])) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
currentValue = currentValue[segment];
|
|
167
|
+
objectPath.push(currentValue);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const lastSegment = segments[segments.length - 1];
|
|
171
|
+
if (!(lastSegment in currentValue)) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
delete currentValue[lastSegment];
|
|
176
|
+
|
|
177
|
+
for (let i = objectPath.length - 1; i >= 1; i--) {
|
|
178
|
+
if (Object.keys(objectPath[i]).length > 0) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const parentObject = objectPath[i - 1];
|
|
183
|
+
const parentKey = parentSegments[i - 1];
|
|
184
|
+
delete parentObject[parentKey];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (Object.keys(getCliNamespaceConfig(smartconfigData)).length === 0) {
|
|
188
|
+
delete smartconfigData[CLI_NAMESPACE];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return true;
|
|
192
|
+
};
|