@ldsg/cli 0.3.43 → 0.3.44

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.
Files changed (133) hide show
  1. package/.rush/temp/package-deps_build.json +15 -18
  2. package/.rush/temp/shrinkwrap-deps.json +1 -1
  3. package/.tsbuildinfo +1 -1
  4. package/CHANGELOG.json +23 -0
  5. package/CHANGELOG.md +8 -1
  6. package/README.md +3 -3
  7. package/dist/__tests__/bootstrap-generator.test.js +120 -0
  8. package/dist/__tests__/bootstrap-generator.test.js.map +1 -0
  9. package/dist/__tests__/generate-bootstrap.test.d.ts +1 -0
  10. package/dist/__tests__/generate-bootstrap.test.js +97 -0
  11. package/dist/__tests__/generate-bootstrap.test.js.map +1 -0
  12. package/dist/__tests__/resolve-module-builder.test.d.ts +1 -0
  13. package/dist/__tests__/resolve-module-builder.test.js +83 -0
  14. package/dist/__tests__/resolve-module-builder.test.js.map +1 -0
  15. package/dist/__tests__/resolve-root.test.d.ts +1 -0
  16. package/dist/__tests__/resolve-root.test.js +32 -0
  17. package/dist/__tests__/resolve-root.test.js.map +1 -0
  18. package/dist/cli.js +4 -431
  19. package/dist/cli.js.map +1 -1
  20. package/dist/commands/generate/index.d.ts +2 -0
  21. package/dist/commands/generate/index.js +35 -0
  22. package/dist/commands/generate/index.js.map +1 -0
  23. package/dist/commands/generate/types/generate.d.ts +12 -0
  24. package/dist/commands/generate/types/generate.js +3 -0
  25. package/dist/commands/generate/types/generate.js.map +1 -0
  26. package/dist/commands/generate/types/generator.d.ts +4 -0
  27. package/dist/commands/generate/types/generator.js +3 -0
  28. package/dist/commands/generate/types/generator.js.map +1 -0
  29. package/dist/commands/generate/types/index.d.ts +2 -0
  30. package/dist/commands/generate/types/index.js +19 -0
  31. package/dist/commands/generate/types/index.js.map +1 -0
  32. package/dist/commands/generate/types.d.ts +8 -0
  33. package/dist/{types/get-extend-app-data-params.js → commands/generate/types.js} +1 -1
  34. package/dist/commands/generate/types.js.map +1 -0
  35. package/dist/commands/generate/utils/generate-application/index.d.ts +6 -0
  36. package/dist/commands/generate/utils/generate-application/index.js +28 -0
  37. package/dist/commands/generate/utils/generate-application/index.js.map +1 -0
  38. package/dist/commands/generate/utils/generate-application/types/generator.d.ts +9 -0
  39. package/dist/commands/generate/utils/generate-application/types/generator.js +3 -0
  40. package/dist/commands/generate/utils/generate-application/types/generator.js.map +1 -0
  41. package/dist/commands/generate/utils/generate-application/types/index.d.ts +1 -0
  42. package/dist/commands/generate/utils/generate-application/types/index.js +18 -0
  43. package/dist/commands/generate/utils/generate-application/types/index.js.map +1 -0
  44. package/dist/commands/generate/utils/generate-application/utils/build-app-generator/index.d.ts +9 -0
  45. package/dist/commands/generate/utils/generate-application/utils/build-app-generator/index.js +30 -0
  46. package/dist/commands/generate/utils/generate-application/utils/build-app-generator/index.js.map +1 -0
  47. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/index.d.ts +13 -0
  48. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/index.js +125 -0
  49. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/index.js.map +1 -0
  50. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/constants.d.ts +3 -0
  51. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/constants.js +7 -0
  52. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/constants.js.map +1 -0
  53. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/index.d.ts +4 -0
  54. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/index.js +69 -0
  55. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/index.js.map +1 -0
  56. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/prepare-bootstrap-app-files.d.ts +3 -0
  57. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/prepare-bootstrap-app-files.js +32 -0
  58. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/prepare-bootstrap-app-files.js.map +1 -0
  59. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/render-bootstrap-entry.d.ts +2 -0
  60. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/render-bootstrap-entry.js +62 -0
  61. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/render-bootstrap-entry.js.map +1 -0
  62. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/resolve-dependencies.d.ts +11 -0
  63. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/resolve-dependencies.js +84 -0
  64. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/generate-bootstrap/resolve-dependencies.js.map +1 -0
  65. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/get-resource-record-by-id.d.ts +2 -0
  66. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/get-resource-record-by-id.js +15 -0
  67. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/get-resource-record-by-id.js.map +1 -0
  68. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/resolve-resource-definition-resource-record.d.ts +2 -0
  69. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/resolve-resource-definition-resource-record.js +21 -0
  70. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/resolve-resource-definition-resource-record.js.map +1 -0
  71. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/resolve-root-resource-record.d.ts +2 -0
  72. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/resolve-root-resource-record.js +18 -0
  73. package/dist/commands/generate/utils/generate-application/utils/build-bootstrap/utils/resource-record/resolve-root-resource-record.js.map +1 -0
  74. package/dist/commands/generate/utils/generate-application/utils/build-meta-generator/index.d.ts +8 -0
  75. package/dist/commands/generate/utils/generate-application/utils/build-meta-generator/index.js +32 -0
  76. package/dist/commands/generate/utils/generate-application/utils/build-meta-generator/index.js.map +1 -0
  77. package/dist/commands/generate/utils/generate-application/utils/generate-app/index.d.ts +8 -0
  78. package/dist/commands/generate/utils/generate-application/utils/generate-app/index.js +10 -0
  79. package/dist/commands/generate/utils/generate-application/utils/generate-app/index.js.map +1 -0
  80. package/dist/commands/generate/utils/generate-application/utils/index.d.ts +3 -0
  81. package/dist/commands/generate/utils/generate-application/utils/index.js +20 -0
  82. package/dist/commands/generate/utils/generate-application/utils/index.js.map +1 -0
  83. package/dist/commands/generate/utils/parse-extra-options.d.ts +5 -0
  84. package/dist/commands/generate/utils/parse-extra-options.js +59 -0
  85. package/dist/commands/generate/utils/parse-extra-options.js.map +1 -0
  86. package/dist/commands/resource/index.d.ts +2 -0
  87. package/dist/commands/resource/index.js +392 -0
  88. package/dist/commands/resource/index.js.map +1 -0
  89. package/dist/generator/bootstrap-generator.d.ts +19 -0
  90. package/dist/generator/bootstrap-generator.js +59 -0
  91. package/dist/generator/bootstrap-generator.js.map +1 -0
  92. package/dist/generator/module-builder.d.ts +2 -0
  93. package/dist/generator/module-builder.js +284 -0
  94. package/dist/generator/module-builder.js.map +1 -0
  95. package/dist/generator/resolve-module-builder.d.ts +8 -0
  96. package/dist/generator/resolve-module-builder.js +41 -0
  97. package/dist/generator/resolve-module-builder.js.map +1 -0
  98. package/dist/generator/resolve-root.d.ts +5 -0
  99. package/dist/generator/resolve-root.js +48 -0
  100. package/dist/generator/resolve-root.js.map +1 -0
  101. package/jest.config.js +4 -1
  102. package/package.json +5 -5
  103. package/src/cli.ts +4 -510
  104. package/src/commands/generate/index.ts +54 -0
  105. package/src/commands/generate/utils/generate-application/index.ts +50 -0
  106. package/src/commands/generate/utils/generate-application/utils/build-app-generator/index.ts +39 -0
  107. package/src/commands/generate/utils/generate-application/utils/build-meta-generator/index.ts +45 -0
  108. package/src/commands/generate/utils/generate-application/utils/generate-app/index.ts +17 -0
  109. package/src/commands/generate/utils/generate-application/utils/index.ts +3 -0
  110. package/src/commands/generate/utils/parse-extra-options.ts +80 -0
  111. package/src/commands/resource/index.ts +455 -0
  112. package/dist/__tests__/get-extend-app-data-params-using-workspace-ldsg-module.test.js +0 -81
  113. package/dist/__tests__/get-extend-app-data-params-using-workspace-ldsg-module.test.js.map +0 -1
  114. package/dist/types/get-extend-app-data-params.d.ts +0 -10
  115. package/dist/types/get-extend-app-data-params.js.map +0 -1
  116. package/dist/utils/get-extend-app-data-params-using-npm-ldsg-module.d.ts +0 -2
  117. package/dist/utils/get-extend-app-data-params-using-npm-ldsg-module.js +0 -27
  118. package/dist/utils/get-extend-app-data-params-using-npm-ldsg-module.js.map +0 -1
  119. package/dist/utils/get-extend-app-data-params-using-workspace-ldsg-module/index.d.ts +0 -2
  120. package/dist/utils/get-extend-app-data-params-using-workspace-ldsg-module/index.js +0 -98
  121. package/dist/utils/get-extend-app-data-params-using-workspace-ldsg-module/index.js.map +0 -1
  122. package/src/__tests__/add-pnpm-overrides.test.ts +0 -91
  123. package/src/__tests__/commands.test.ts +0 -318
  124. package/src/__tests__/formatter.test.ts +0 -151
  125. package/src/__tests__/generate-app-index-ts.test.ts +0 -141
  126. package/src/__tests__/get-extend-app-data-params-using-workspace-ldsg-module.test.ts +0 -109
  127. package/src/__tests__/json-file-mutator.test.ts +0 -186
  128. package/src/__tests__/mutate.test.ts +0 -392
  129. package/src/__tests__/source-resolver.test.ts +0 -125
  130. package/src/types/get-extend-app-data-params.ts +0 -13
  131. package/src/utils/get-extend-app-data-params-using-npm-ldsg-module.ts +0 -34
  132. package/src/utils/get-extend-app-data-params-using-workspace-ldsg-module/index.ts +0 -159
  133. /package/dist/__tests__/{get-extend-app-data-params-using-workspace-ldsg-module.test.d.ts → bootstrap-generator.test.d.ts} +0 -0
@@ -0,0 +1,45 @@
1
+ import { extractZipToFolder, generateMetaGeneratorApp, installDependencies } from "@ldsg/utils";
2
+ import { GenerateParams, Generator } from "@ldsg/types";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { cwd } from "node:process";
6
+
7
+ export interface BuildMetaGeneratorParams extends GenerateParams {}
8
+
9
+ export interface BuildMetaGeneratorRes {
10
+ metaGenerator: Generator;
11
+ }
12
+
13
+ export type BuildMetaGenerator = (
14
+ params: BuildMetaGeneratorParams,
15
+ ) => Promise<BuildMetaGeneratorRes>;
16
+
17
+ export const buildMetaGenerator: BuildMetaGenerator = async (params) => {
18
+ const { archive } = await generateMetaGeneratorApp(params);
19
+
20
+ /**
21
+ * 解压、安装依赖、导出模块
22
+ */
23
+ {
24
+ const outputPath = path.join(os.homedir(), ".ldsg", "meta-generator");
25
+
26
+ extractZipToFolder({
27
+ archive,
28
+ outputPath,
29
+ });
30
+
31
+ installDependencies({ cwd: outputPath });
32
+ }
33
+
34
+ const res: BuildMetaGeneratorRes = {
35
+ metaGenerator: {
36
+ generate: async () => {
37
+ return {
38
+ archive,
39
+ };
40
+ },
41
+ },
42
+ };
43
+
44
+ return res;
45
+ };
@@ -0,0 +1,17 @@
1
+ import { GenerateParams, GenerateRes, Generator } from "@ldsg/types";
2
+
3
+ export interface GenerateAppParams extends GenerateParams {
4
+ appGenerator: Generator;
5
+ }
6
+
7
+ export interface GenerateAppRes extends GenerateRes {}
8
+
9
+ export type GenerateApp = (params: GenerateAppParams) => Promise<GenerateAppRes>;
10
+
11
+ export const generateApp: GenerateApp = async (params) => {
12
+ const { appGenerator, ...restParams } = params;
13
+
14
+ const res = await appGenerator.generate(restParams);
15
+
16
+ return res;
17
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./build-app-generator";
2
+ export * from "./build-meta-generator";
3
+ export * from "./generate-app";
@@ -0,0 +1,80 @@
1
+ /**
2
+ * 解析 CLI 剩余参数(不区分具体选项)
3
+ *
4
+ * 支持:
5
+ * - `--key value` / `--key=value`
6
+ * - `-f value` / `-f=value`
7
+ *
8
+ * 值会按 string | number | boolean 做基础转换;未被选项消费的 token 收集为位置参数。
9
+ */
10
+ export interface ParsedExtraArgs {
11
+ /** 未知选项 */
12
+ options: Record<string, string | number | boolean>;
13
+ /** 位置参数,最后一个为输出目录 */
14
+ positionals: string[];
15
+ }
16
+
17
+ const coerce = (value: string): string | number | boolean => {
18
+ if (value === "true") return true;
19
+ if (value === "false") return false;
20
+ if (/^-?\d+(\.\d+)?$/.test(value)) return Number(value);
21
+ return value;
22
+ };
23
+
24
+ export const parseExtraOptions = (args: string[]): ParsedExtraArgs => {
25
+ const options: ParsedExtraArgs["options"] = {};
26
+ const positionals: string[] = [];
27
+ let currentKey: string | null = null;
28
+
29
+ for (let i = 0; i < args.length; i++) {
30
+ const token = args[i];
31
+
32
+ // `--` 之后的参数忽略
33
+ if (token === "--") {
34
+ break;
35
+ }
36
+
37
+ // --key / --key=value
38
+ if (token.startsWith("--")) {
39
+ const eq = token.indexOf("=");
40
+
41
+ if (eq > -1) {
42
+ options[token.slice(2, eq)] = coerce(token.slice(eq + 1));
43
+ currentKey = null;
44
+ } else {
45
+ currentKey = token.slice(2);
46
+ options[currentKey] = true;
47
+ }
48
+
49
+ continue;
50
+ }
51
+
52
+ // -f / -f=value
53
+ if (token.startsWith("-") && token.length > 1) {
54
+ if (currentKey !== null) {
55
+ currentKey = null;
56
+ }
57
+
58
+ const eq = token.indexOf("=");
59
+
60
+ if (eq > -1) {
61
+ options[token.slice(1, eq)] = coerce(token.slice(eq + 1));
62
+ } else {
63
+ currentKey = token.slice(1);
64
+ options[currentKey] = true;
65
+ }
66
+
67
+ continue;
68
+ }
69
+
70
+ // 普通值:作为上一个选项的值,否则视为位置参数
71
+ if (currentKey !== null) {
72
+ options[currentKey] = coerce(token);
73
+ currentKey = null;
74
+ } else {
75
+ positionals.push(token);
76
+ }
77
+ }
78
+
79
+ return { options, positionals };
80
+ };
@@ -0,0 +1,455 @@
1
+ import { Command } from "commander";
2
+ import { DEFAULT_SOURCE_PATH } from "../../constants";
3
+ import { getSourceDescription, isStdinSource, resolveSource } from "../../utils/source-resolver";
4
+ import {
5
+ formatError,
6
+ formatJson,
7
+ formatPrettyDiff,
8
+ formatPrettyList,
9
+ formatPrettyTree,
10
+ formatSuccess,
11
+ } from "../../utils/formatter";
12
+ import { createResource } from "./create";
13
+ import { updateResource } from "./update";
14
+ import { deleteResource } from "./delete";
15
+ import { getTree, listResources } from "./list";
16
+ import { getResource } from "./get";
17
+ import { diffResource } from "./diff";
18
+ import {
19
+ mutateRecordsDirect,
20
+ mutateResources,
21
+ pullRemoteResourceRecords,
22
+ purifyResourceRecord,
23
+ } from "./mutate";
24
+
25
+ async function parseExplicitRecords(
26
+ value?: string,
27
+ file?: string,
28
+ ): Promise<
29
+ | {
30
+ id: string;
31
+ kind: string;
32
+ parentId: string | null;
33
+ settings: Record<string, unknown>;
34
+ }[]
35
+ | undefined
36
+ > {
37
+ if (value && file) {
38
+ throw new Error("Cannot use both an inline value and a file for the same record list");
39
+ }
40
+
41
+ let data: unknown;
42
+
43
+ if (file) {
44
+ const fs = await import("fs-extra");
45
+ data = await fs.readJson(file);
46
+ } else if (value) {
47
+ data = JSON.parse(value);
48
+ } else {
49
+ return undefined;
50
+ }
51
+
52
+ const list = Array.isArray(data) ? data : [data];
53
+ return list.map((record) => purifyResourceRecord(record as never));
54
+ }
55
+
56
+ /**
57
+ * 注册 resource 命令组
58
+ *
59
+ * 对本地数据源中的资源记录做读写:list / get / tree / create / update / delete / diff,
60
+ * 以及与 RRM 交互的 pull / mutate。
61
+ */
62
+ export function registerResourceCommand(program: Command): void {
63
+ const resource = program
64
+ .command("resource")
65
+ .aliases(["r"])
66
+ .description("Manage resource records");
67
+
68
+ resource
69
+ .command("list")
70
+ .description("List resource records by filter")
71
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
72
+ .option("--kind <kind>", "filter by resource kind")
73
+ .option("--parent-id <id>", "filter by parent id")
74
+ .option("--root-id <id>", "filter by root resource id")
75
+ .option("--pretty", "human-readable output")
76
+ .action(async (options) => {
77
+ try {
78
+ const sourceDesc = getSourceDescription(options.source);
79
+ const sourceData = await resolveSource(options.source);
80
+ const { total, resources } = await listResources(sourceData.resourceRecords, {
81
+ kind: options.kind,
82
+ parentId: options.parentId,
83
+ rootId: options.rootId,
84
+ });
85
+
86
+ if (options.pretty) {
87
+ console.log(
88
+ formatPrettyList(
89
+ resources.map((r) => ({
90
+ id: r.id,
91
+ kind: r.kind,
92
+ parentId: r.parentId,
93
+ title: (r.settings as Record<string, unknown>)?.title as string | undefined,
94
+ })),
95
+ ),
96
+ );
97
+ } else {
98
+ console.log(formatJson(formatSuccess({ source: sourceDesc, total, resources })));
99
+ }
100
+ } catch (error) {
101
+ console.error(formatJson(formatError("LIST_ERROR", (error as Error).message)));
102
+ process.exit(1);
103
+ }
104
+ });
105
+
106
+ resource
107
+ .command("get <id>")
108
+ .description("Get a resource record by id")
109
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
110
+ .option("--children", "include direct children")
111
+ .option("--tree", "include full subtree")
112
+ .option("--pretty", "human-readable output")
113
+ .action(async (id, options) => {
114
+ try {
115
+ const sourceDesc = getSourceDescription(options.source);
116
+ const sourceData = await resolveSource(options.source);
117
+ const record = await getResource(sourceData.resourceRecords, id, {
118
+ children: options.children,
119
+ tree: options.tree,
120
+ });
121
+
122
+ if (!record) {
123
+ console.error(formatJson(formatError("NOT_FOUND", `Resource with id "${id}" not found`)));
124
+ process.exit(1);
125
+ }
126
+
127
+ if (options.pretty) {
128
+ console.log(formatJson(record));
129
+ } else {
130
+ console.log(formatJson(formatSuccess({ source: sourceDesc, record })));
131
+ }
132
+ } catch (error) {
133
+ console.error(formatJson(formatError("GET_ERROR", (error as Error).message)));
134
+ process.exit(1);
135
+ }
136
+ });
137
+
138
+ resource
139
+ .command("tree [root-id]")
140
+ .description("Display resource tree")
141
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
142
+ .option("--show-kind", "show resource kind prefix")
143
+ .option("--pretty", "human-readable output")
144
+ .action(async (rootId, options) => {
145
+ try {
146
+ const sourceDesc = getSourceDescription(options.source);
147
+ const sourceData = await resolveSource(options.source);
148
+ const result = await getTree(sourceData.resourceRecords, rootId, options.showKind);
149
+
150
+ if (options.pretty) {
151
+ console.log(formatPrettyTree(result.tree as never, options.showKind ?? false));
152
+ } else {
153
+ console.log(formatJson(formatSuccess({ source: sourceDesc, ...result })));
154
+ }
155
+ } catch (error) {
156
+ console.error(formatJson(formatError("TREE_ERROR", (error as Error).message)));
157
+ process.exit(1);
158
+ }
159
+ });
160
+
161
+ resource
162
+ .command("create")
163
+ .description("Create a new resource record")
164
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
165
+ .option("--kind <kind>", "resource kind")
166
+ .option("--parent-id <id>", "parent resource id")
167
+ .option("--settings <json>", "resource settings as JSON string")
168
+ .option("--from-file <path>", "read full resource record from JSON file")
169
+ .option("--from-stdin", "read full resource record from stdin")
170
+ .option("--dry-run", "preview without writing")
171
+ .action(async (options) => {
172
+ try {
173
+ if (isStdinSource(options.source)) {
174
+ console.error(
175
+ formatJson(
176
+ formatError("STDIN_NOT_WRITABLE", "stdin source does not support write operations"),
177
+ ),
178
+ );
179
+ process.exit(1);
180
+ }
181
+
182
+ const sourceData = await resolveSource(options.source);
183
+
184
+ let fromFileRecord: Record<string, unknown> | undefined;
185
+
186
+ if (options.fromFile) {
187
+ const fs = await import("fs-extra");
188
+ fromFileRecord = await fs.readJson(options.fromFile);
189
+ } else if (options.fromStdin) {
190
+ const chunks: Buffer[] = [];
191
+ process.stdin.setEncoding("utf-8");
192
+ for await (const chunk of process.stdin) {
193
+ chunks.push(Buffer.from(chunk));
194
+ }
195
+ const raw = Buffer.concat(chunks).toString("utf-8");
196
+ fromFileRecord = JSON.parse(raw);
197
+ }
198
+
199
+ let settings: Record<string, unknown> | undefined;
200
+ if (options.settings) {
201
+ settings = JSON.parse(options.settings);
202
+ }
203
+
204
+ const { record } = await createResource({
205
+ sourceData,
206
+ kind: options.kind,
207
+ parentId: options.parentId,
208
+ settings,
209
+ fromFileRecord: fromFileRecord as never,
210
+ dryRun: options.dryRun,
211
+ });
212
+
213
+ console.log(formatJson(formatSuccess({ record, dryRun: options.dryRun ?? false })));
214
+ } catch (error) {
215
+ console.error(formatJson(formatError("CREATE_ERROR", (error as Error).message)));
216
+ process.exit(1);
217
+ }
218
+ });
219
+
220
+ resource
221
+ .command("update <id>")
222
+ .description("Update a resource record")
223
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
224
+ .option("--settings <json>", "resource settings to merge (JSON string, required)")
225
+ .option("--dry-run", "preview without writing")
226
+ .action(async (id, options) => {
227
+ try {
228
+ if (isStdinSource(options.source)) {
229
+ console.error(
230
+ formatJson(
231
+ formatError("STDIN_NOT_WRITABLE", "stdin source does not support write operations"),
232
+ ),
233
+ );
234
+ process.exit(1);
235
+ }
236
+
237
+ const sourceData = await resolveSource(options.source);
238
+
239
+ if (!options.settings) {
240
+ console.error(
241
+ formatJson(formatError("MISSING_SETTINGS", "Required option: --settings <json>")),
242
+ );
243
+ process.exit(1);
244
+ }
245
+
246
+ const settings = JSON.parse(options.settings);
247
+ const { record } = await updateResource({
248
+ sourceData,
249
+ id,
250
+ settings,
251
+ dryRun: options.dryRun,
252
+ });
253
+
254
+ console.log(formatJson(formatSuccess({ record, dryRun: options.dryRun ?? false })));
255
+ } catch (error) {
256
+ console.error(formatJson(formatError("UPDATE_ERROR", (error as Error).message)));
257
+ process.exit(1);
258
+ }
259
+ });
260
+
261
+ resource
262
+ .command("delete <id>")
263
+ .description("Delete a resource record and its children")
264
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
265
+ .option("--dry-run", "preview deletion scope without writing")
266
+ .action(async (id, options) => {
267
+ try {
268
+ if (isStdinSource(options.source)) {
269
+ console.error(
270
+ formatJson(
271
+ formatError("STDIN_NOT_WRITABLE", "stdin source does not support write operations"),
272
+ ),
273
+ );
274
+ process.exit(1);
275
+ }
276
+
277
+ const sourceData = await resolveSource(options.source);
278
+ const { removed } = await deleteResource({
279
+ sourceData,
280
+ id,
281
+ dryRun: options.dryRun,
282
+ });
283
+
284
+ console.log(
285
+ formatJson(
286
+ formatSuccess({
287
+ dryRun: options.dryRun ?? false,
288
+ removedCount: removed.length,
289
+ removed: removed.map((r) => ({ id: r.id, kind: r.kind })),
290
+ }),
291
+ ),
292
+ );
293
+ } catch (error) {
294
+ console.error(formatJson(formatError("DELETE_ERROR", (error as Error).message)));
295
+ process.exit(1);
296
+ }
297
+ });
298
+
299
+ resource
300
+ .command("diff <id>")
301
+ .description("Diff a resource between two sources")
302
+ .option("--source-a <path>", "first source file (required)")
303
+ .option("--source-b <path>", "second source file (required)")
304
+ .option("--pretty", "human-readable output")
305
+ .action(async (id, options) => {
306
+ try {
307
+ if (!options.sourceA || !options.sourceB) {
308
+ console.error(
309
+ formatJson(formatError("MISSING_ARGS", "Required options: --source-a, --source-b")),
310
+ );
311
+ process.exit(1);
312
+ }
313
+
314
+ const sourceDataA = await resolveSource(options.sourceA);
315
+ const sourceDataB = await resolveSource(options.sourceB);
316
+
317
+ const result = await diffResource({
318
+ sourceA: getSourceDescription(options.sourceA),
319
+ sourceB: getSourceDescription(options.sourceB),
320
+ id,
321
+ recordsA: sourceDataA.resourceRecords,
322
+ recordsB: sourceDataB.resourceRecords,
323
+ });
324
+
325
+ if (options.pretty) {
326
+ console.log(formatPrettyDiff(result));
327
+ } else {
328
+ console.log(formatJson(formatSuccess(result)));
329
+ }
330
+ } catch (error) {
331
+ console.error(formatJson(formatError("DIFF_ERROR", (error as Error).message)));
332
+ process.exit(1);
333
+ }
334
+ });
335
+
336
+ resource
337
+ .command("pull")
338
+ .description("Pull resource records from RRM to a local file (read-only)")
339
+ .option("--endpoint <url>", "RRM GraphQL endpoint")
340
+ .option("--path <regex>", "scope remote records to a path regex (e.g. application id)")
341
+ .option("-o, --output <path>", `output file (default: ${DEFAULT_SOURCE_PATH})`)
342
+ .action(async (options) => {
343
+ try {
344
+ const result = await pullRemoteResourceRecords({
345
+ endpoint: options.endpoint,
346
+ path: options.path,
347
+ output: options.output,
348
+ });
349
+
350
+ console.log(formatJson(formatSuccess(result)));
351
+ } catch (error) {
352
+ console.error(formatJson(formatError("PULL_ERROR", (error as Error).message)));
353
+ process.exit(1);
354
+ }
355
+ });
356
+
357
+ resource
358
+ .command("mutate")
359
+ .description("Mutate local resource records on RRM via mutateResourceRecords")
360
+ .option("--source <path>", `data source (default: ${DEFAULT_SOURCE_PATH})`)
361
+ .option("--endpoint <url>", "RRM GraphQL endpoint")
362
+ .option("--token <token>", "RRM Bearer token (or RRM_ACCESS_TOKEN env)")
363
+ .option(
364
+ "--path <regex>",
365
+ "scope remote records to a path regex (e.g. application id) before splitting",
366
+ )
367
+ .option(
368
+ "--no-delete-missing",
369
+ "do not soft-delete remote-only records (default: soft-delete like console)",
370
+ )
371
+ .option("--no-write-back", "do not write server-assigned ids back to the local source file")
372
+ .option("--yes", "confirm soft-deletion without prompting")
373
+ .option("--dry-run", "preview the plan without sending")
374
+ .option("--create <json>", "explicit create records as JSON (skip auto split)")
375
+ .option("--update <json>", "explicit update records as JSON (skip auto split)")
376
+ .option("--create-file <path>", "explicit create records from JSON file (skip auto split)")
377
+ .option("--update-file <path>", "explicit update records from JSON file (skip auto split)")
378
+ .action(async (options) => {
379
+ try {
380
+ const explicitCreate = await parseExplicitRecords(options.create, options.createFile);
381
+ const explicitUpdate = await parseExplicitRecords(options.update, options.updateFile);
382
+
383
+ if (explicitCreate !== undefined || explicitUpdate !== undefined) {
384
+ const result = await mutateRecordsDirect({
385
+ endpoint: options.endpoint,
386
+ token: options.token,
387
+ createResourceRecords: explicitCreate ?? [],
388
+ updateResourceRecords: explicitUpdate ?? [],
389
+ dryRun: options.dryRun,
390
+ });
391
+
392
+ console.log(
393
+ formatJson(
394
+ formatSuccess({
395
+ mode: "explicit",
396
+ dryRun: result.dryRun,
397
+ createCount: result.createCount,
398
+ updateCount: result.updateCount,
399
+ createdResourceRecords: result.createdResourceRecords,
400
+ updatedResourceRecords: result.updatedResourceRecords,
401
+ }),
402
+ ),
403
+ );
404
+ return;
405
+ }
406
+
407
+ if (isStdinSource(options.source)) {
408
+ console.error(
409
+ formatJson(
410
+ formatError(
411
+ "STDIN_NOT_SUPPORTED",
412
+ "stdin source is not supported for mutate; use a local JSON file",
413
+ ),
414
+ ),
415
+ );
416
+ process.exit(1);
417
+ }
418
+
419
+ const sourceData = await resolveSource(options.source);
420
+
421
+ const result = await mutateResources({
422
+ sourceData,
423
+ endpoint: options.endpoint,
424
+ token: options.token,
425
+ path: options.path,
426
+ deleteMissing: options.deleteMissing,
427
+ writeBack: options.writeBack,
428
+ yes: options.yes,
429
+ dryRun: options.dryRun,
430
+ });
431
+
432
+ const { plan } = result;
433
+
434
+ console.log(
435
+ formatJson(
436
+ formatSuccess({
437
+ mode: "auto",
438
+ dryRun: result.dryRun,
439
+ source: getSourceDescription(options.source),
440
+ remoteCount: plan.remoteCount,
441
+ localCount: plan.localCount,
442
+ createCount: plan.createResourceRecords.length,
443
+ updateCount: plan.updateResourceRecords.length,
444
+ deleteCount: plan.deleteResourceRecords.length,
445
+ idMap: result.idMap,
446
+ writeBackPath: result.writeBackPath,
447
+ }),
448
+ ),
449
+ );
450
+ } catch (error) {
451
+ console.error(formatJson(formatError("MUTATE_ERROR", (error as Error).message)));
452
+ process.exit(1);
453
+ }
454
+ });
455
+ }
@@ -1,81 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const get_extend_app_data_params_using_workspace_ldsg_module_1 = require("../utils/get-extend-app-data-params-using-workspace-ldsg-module");
4
- jest.mock("@ldsg/utils", () => {
5
- const actual = jest.requireActual("@ldsg/utils");
6
- return {
7
- ...actual,
8
- RUSH_JSON_PATH: "/mock/rush.json",
9
- syncRushProjects: jest.fn(),
10
- };
11
- });
12
- const utils_1 = require("@ldsg/utils");
13
- const mockedSyncRushProjects = utils_1.syncRushProjects;
14
- const handlerId = "handler-1";
15
- const appData = {
16
- resourceRecords: [
17
- {
18
- id: handlerId,
19
- kind: "handler",
20
- parentId: "root",
21
- settings: {
22
- slug: "handler-1",
23
- title: "应用实例化资源处理程序",
24
- description: "",
25
- code: 'export * from "@ldsg/application";',
26
- dependencies: [
27
- { name: "@ldsg/application", version: "^1.0.0" },
28
- { name: "lodash", version: "^4.17.21" },
29
- ],
30
- },
31
- },
32
- ],
33
- };
34
- describe("getExtendAppDataParamsUsingWorkspaceLdsgModule", () => {
35
- beforeEach(() => {
36
- mockedSyncRushProjects.mockClear();
37
- });
38
- it("NESTED 布局:app 与 handler 项目文件夹按嵌套结构计算", async () => {
39
- const res = await (0, get_extend_app_data_params_using_workspace_ldsg_module_1.getExtendAppDataParamsUsingWorkspaceLdsgModule)({
40
- appData,
41
- layout: utils_1.ZipAppDataLayout.NESTED,
42
- outputPath: "../../apps/rrm",
43
- });
44
- expect(mockedSyncRushProjects).toHaveBeenCalledWith("/mock/rush.json", [
45
- { packageName: "@ldsg/app", projectFolder: "apps/rrm" },
46
- { packageName: handlerId, projectFolder: "apps/rrm/handlers/handler-1" },
47
- ]);
48
- const packageJsonFile = res.extraAppData.filesInAppModele.find((file) => file.path === "package.json");
49
- expect(packageJsonFile).toBeDefined();
50
- });
51
- it("FLAT 布局(默认):app 在输出根目录 app/ 下,handler 平铺", async () => {
52
- await (0, get_extend_app_data_params_using_workspace_ldsg_module_1.getExtendAppDataParamsUsingWorkspaceLdsgModule)({
53
- appData,
54
- outputPath: "../../generated",
55
- });
56
- expect(mockedSyncRushProjects).toHaveBeenCalledWith("/mock/rush.json", [
57
- { packageName: "@ldsg/app", projectFolder: "generated/app" },
58
- { packageName: handlerId, projectFolder: "generated/handler-1" },
59
- ]);
60
- });
61
- it("NESTED 布局:app 包名使用传入的 appPackageName,且 @ldsg 依赖改为 workspace:*", async () => {
62
- const res = await (0, get_extend_app_data_params_using_workspace_ldsg_module_1.getExtendAppDataParamsUsingWorkspaceLdsgModule)({
63
- appData,
64
- layout: utils_1.ZipAppDataLayout.NESTED,
65
- outputPath: "../../apps/rrm",
66
- appPackageName: "@ldsg/rrm",
67
- });
68
- const packageJsonFile = res.extraAppData.filesInAppModele.find((file) => file.path === "package.json");
69
- expect(packageJsonFile).toBeDefined();
70
- expect(packageJsonFile.data.name).toBe("@ldsg/rrm");
71
- const handlerRecord = res.appData.resourceRecords.find((record) => record.id === handlerId);
72
- expect(handlerRecord).toBeDefined();
73
- expect(handlerRecord.settings.dependencies).toEqual(expect.arrayContaining([
74
- { name: "@ldsg/application", version: "workspace:*" },
75
- { name: "lodash", version: "^4.17.21" },
76
- { name: "@types/node", version: "^24.1.0" },
77
- { name: "typescript", version: "^5.3.3" },
78
- ]));
79
- });
80
- });
81
- //# sourceMappingURL=get-extend-app-data-params-using-workspace-ldsg-module.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-extend-app-data-params-using-workspace-ldsg-module.test.js","sourceRoot":"","sources":["../../src/__tests__/get-extend-app-data-params-using-workspace-ldsg-module.test.ts"],"names":[],"mappings":"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"}