@ldsg/cli 0.3.42 → 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 +46 -0
  5. package/CHANGELOG.md +15 -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
@@ -1,392 +0,0 @@
1
- import axios from "axios";
2
- import fs from "fs-extra";
3
- import { ResourceRecords } from "@ldsg/types";
4
- import {
5
- applyIdMapToRecords,
6
- buildIdMap,
7
- buildMutatePlan,
8
- mutateRecordsDirect,
9
- mutateResourceRecords,
10
- mutateResources,
11
- pullRemoteResourceRecords,
12
- purifyResourceRecord,
13
- } from "../commands/resource/mutate";
14
- import { SourceData } from "../types/resource-record";
15
- import { DEFAULT_RRM_GRAPHQL_ENDPOINT } from "../constants";
16
-
17
- jest.mock("axios");
18
- jest.mock("fs-extra");
19
-
20
- const mockedAxios = axios as jest.Mocked<typeof axios>;
21
- const mockedFs = fs as jest.Mocked<typeof fs>;
22
-
23
- const localRecords: ResourceRecords = [
24
- {
25
- id: "app-temp-1",
26
- kind: "application",
27
- parentId: null,
28
- settings: { slug: "my-app", title: "My App", description: "" },
29
- },
30
- {
31
- id: "form-temp-1",
32
- kind: "form",
33
- parentId: "app-temp-1",
34
- settings: { slug: "login", title: "Login", description: "" },
35
- },
36
- {
37
- id: "existing-app",
38
- kind: "application",
39
- parentId: null,
40
- settings: { slug: "existing-application", title: "Existing App", description: "", extra: true },
41
- },
42
- ];
43
-
44
- const remoteRecords: ResourceRecords = [
45
- {
46
- id: "existing-app",
47
- kind: "application",
48
- parentId: null,
49
- settings: { slug: "existing-application", title: "Existing App", description: "" },
50
- },
51
- {
52
- id: "remote-only-app",
53
- kind: "application",
54
- parentId: null,
55
- settings: { slug: "remote-only-application", title: "Remote Only", description: "" },
56
- },
57
- ];
58
-
59
- const sourceData: SourceData = {
60
- resourceRecords: localRecords,
61
- format: "array",
62
- filePath: "/tmp/resource-records.json",
63
- };
64
-
65
- describe("mutate command", () => {
66
- beforeEach(() => {
67
- jest.resetAllMocks();
68
- });
69
-
70
- describe("purifyResourceRecord", () => {
71
- it("should keep only id, kind, parentId, settings", () => {
72
- const result = purifyResourceRecord({
73
- id: "x",
74
- kind: "table",
75
- parentId: "app1",
76
- settings: { title: "T" },
77
- extraField: "nope",
78
- } as any);
79
-
80
- expect(result).toEqual({
81
- id: "x",
82
- kind: "table",
83
- parentId: "app1",
84
- settings: { title: "T" },
85
- });
86
- expect(result).not.toHaveProperty("extraField");
87
- });
88
- });
89
-
90
- describe("buildMutatePlan", () => {
91
- it("should split create/update/delete like console", () => {
92
- const plan = buildMutatePlan(localRecords, remoteRecords);
93
-
94
- expect(plan.createResourceRecords.map((r) => r.id)).toEqual(["app-temp-1", "form-temp-1"]);
95
- expect(plan.updateResourceRecords.map((r) => r.id)).toEqual(["existing-app"]);
96
- expect(plan.deleteResourceRecords.map((r) => r.id)).toEqual(["remote-only-app"]);
97
- expect(plan.deleteResourceRecords[0].settings.isDeleted).toBe(true);
98
- expect(plan.remoteCount).toBe(2);
99
- expect(plan.localCount).toBe(3);
100
- });
101
-
102
- it("should skip soft-delete when deleteMissing=false", () => {
103
- const plan = buildMutatePlan(localRecords, remoteRecords, { deleteMissing: false });
104
- expect(plan.deleteResourceRecords).toHaveLength(0);
105
- expect(plan.createResourceRecords).toHaveLength(2);
106
- });
107
- });
108
-
109
- describe("replaceIdsDeep / applyIdMapToRecords", () => {
110
- it("should replace id, parentId and settings references", () => {
111
- const idMap = {
112
- "app-temp-1": "6a76d34f09e2c7630c859301",
113
- "form-temp-1": "6a76d34f09e2c7630c859302",
114
- };
115
-
116
- const result = applyIdMapToRecords(localRecords, idMap);
117
-
118
- expect(result[0].id).toBe("6a76d34f09e2c7630c859301");
119
- expect(result[1].parentId).toBe("6a76d34f09e2c7630c859301");
120
- expect(result[1].id).toBe("6a76d34f09e2c7630c859302");
121
- });
122
-
123
- it("should replace exact-string values inside settings", () => {
124
- const record: any = {
125
- id: "obj-temp",
126
- kind: "object",
127
- parentId: "app-temp-1",
128
- settings: {
129
- databaseResourceId: "app-temp-1",
130
- title: "keep app-temp-1 as literal substring?",
131
- },
132
- };
133
- const result = applyIdMapToRecords([record], { "app-temp-1": "SERVER-APP" }) as any;
134
-
135
- expect(result[0].settings.databaseResourceId).toBe("SERVER-APP");
136
- expect(result[0].settings.title).toBe("keep app-temp-1 as literal substring?");
137
- });
138
- });
139
-
140
- describe("buildIdMap", () => {
141
- it("should map by index and skip identity", () => {
142
- const map = buildIdMap(
143
- [
144
- { id: "a", kind: "k", parentId: null, settings: {} },
145
- { id: "b", kind: "k", parentId: null, settings: {} },
146
- ],
147
- [
148
- { id: "server-a", kind: "k", parentId: null, settings: {} },
149
- { id: "b", kind: "k", parentId: null, settings: {} },
150
- ],
151
- );
152
-
153
- expect(map).toEqual({ a: "server-a" });
154
- });
155
-
156
- it("should return empty map on length mismatch", () => {
157
- const map = buildIdMap([{ id: "a", kind: "k", parentId: null, settings: {} }], []);
158
- expect(map).toEqual({});
159
- });
160
- });
161
-
162
- describe("mutateResourceRecords", () => {
163
- it("should POST the exact mutation payload", async () => {
164
- mockedAxios.post.mockResolvedValue({
165
- data: {
166
- data: {
167
- mutateResourceRecords: {
168
- createdResourceRecords: [{ id: "s1" }],
169
- updatedResourceRecords: [{ id: "u1" }],
170
- },
171
- },
172
- },
173
- });
174
-
175
- const res = await mutateResourceRecords({
176
- endpoint: DEFAULT_RRM_GRAPHQL_ENDPOINT,
177
- token: "TOKEN",
178
- createResourceRecords: [{ id: "a", kind: "k", parentId: null, settings: {} }],
179
- updateResourceRecords: [],
180
- });
181
-
182
- const [, body, config] = mockedAxios.post.mock.calls[0];
183
- expect((body as any).variables.createResourceRecords).toEqual([
184
- { id: "a", kind: "k", parentId: null, settings: {} },
185
- ]);
186
- expect((config as any).headers.authorization).toBe("Bearer TOKEN");
187
- expect((body as any).query).toContain("mutateResourceRecords");
188
- expect(res.createdResourceRecords[0].id).toBe("s1");
189
- });
190
-
191
- it("should throw on GraphQL errors", async () => {
192
- mockedAxios.post.mockResolvedValue({
193
- data: { errors: [{ message: "boom" }] },
194
- });
195
-
196
- await expect(
197
- mutateResourceRecords({
198
- endpoint: DEFAULT_RRM_GRAPHQL_ENDPOINT,
199
- createResourceRecords: [],
200
- updateResourceRecords: [],
201
- }),
202
- ).rejects.toThrow("boom");
203
- });
204
- });
205
-
206
- describe("mutateResources (auto mode)", () => {
207
- beforeEach(() => {
208
- mockedAxios.post.mockImplementation(async (url, body: any) => {
209
- const query = String(body.query ?? "");
210
- if (query.includes("resourceRecordConnection")) {
211
- return {
212
- data: {
213
- data: {
214
- resourceRecordConnection: {
215
- pageInfo: { hasNextPage: false },
216
- edges: remoteRecords.map((r) => ({ node: r })),
217
- },
218
- },
219
- },
220
- };
221
- }
222
- if (query.includes("mutateResourceRecords")) {
223
- return {
224
- data: {
225
- data: {
226
- mutateResourceRecords: {
227
- createdResourceRecords: [
228
- { id: "SERVER-APP", kind: "application", parentId: null, settings: {} },
229
- { id: "SERVER-FORM", kind: "form", parentId: "SERVER-APP", settings: {} },
230
- ],
231
- updatedResourceRecords: [],
232
- },
233
- },
234
- },
235
- };
236
- }
237
- return { data: {} };
238
- });
239
- });
240
-
241
- it("should return plan only in dry-run mode without calling mutation", async () => {
242
- const res = await mutateResources({ sourceData, dryRun: true });
243
-
244
- expect(res.dryRun).toBe(true);
245
- expect(res.plan.createResourceRecords).toHaveLength(2);
246
- expect(mockedAxios.post).toHaveBeenCalledTimes(1); // 只拉取了远端
247
- });
248
-
249
- it("should throw when token missing and there are writes", async () => {
250
- await expect(mutateResources({ sourceData })).rejects.toThrow(/token/i);
251
- });
252
-
253
- it("should throw requiring --yes when soft-deleting", async () => {
254
- process.env.RRM_ACCESS_TOKEN = "ENV_TOKEN";
255
- await expect(mutateResources({ sourceData })).rejects.toThrow(/--yes/);
256
- delete process.env.RRM_ACCESS_TOKEN;
257
- });
258
-
259
- it("should mutate, write back ids and confirm deletion with --yes", async () => {
260
- mockedFs.writeJson.mockResolvedValue(undefined as never);
261
-
262
- const res = await mutateResources({ sourceData, token: "TOKEN", yes: true });
263
-
264
- expect(res.idMap).toEqual({ "app-temp-1": "SERVER-APP", "form-temp-1": "SERVER-FORM" });
265
- expect(res.writeBackPath).toBe("/tmp/resource-records.json");
266
- expect(mockedFs.writeJson).toHaveBeenCalledWith(
267
- "/tmp/resource-records.json",
268
- [
269
- {
270
- id: "SERVER-APP",
271
- kind: "application",
272
- parentId: null,
273
- settings: { slug: "my-app", title: "My App", description: "" },
274
- },
275
- {
276
- id: "SERVER-FORM",
277
- kind: "form",
278
- parentId: "SERVER-APP",
279
- settings: { slug: "login", title: "Login", description: "" },
280
- },
281
- {
282
- id: "existing-app",
283
- kind: "application",
284
- parentId: null,
285
- settings: {
286
- slug: "existing-application",
287
- title: "Existing App",
288
- description: "",
289
- extra: true,
290
- },
291
- },
292
- ],
293
- { spaces: 2 },
294
- );
295
- });
296
-
297
- it("should skip write-back when --no-write-back", async () => {
298
- const res = await mutateResources({
299
- sourceData,
300
- token: "TOKEN",
301
- yes: true,
302
- writeBack: false,
303
- });
304
- expect(res.writeBackPath).toBeUndefined();
305
- expect(mockedFs.writeJson).not.toHaveBeenCalled();
306
- });
307
- });
308
-
309
- describe("mutateRecordsDirect (explicit mode)", () => {
310
- it("should POST exactly the given records without fetching remote", async () => {
311
- mockedAxios.post.mockResolvedValue({
312
- data: {
313
- data: {
314
- mutateResourceRecords: {
315
- createdResourceRecords: [{ id: "server-1" }],
316
- updatedResourceRecords: [],
317
- },
318
- },
319
- },
320
- });
321
-
322
- const res = await mutateRecordsDirect({
323
- endpoint: DEFAULT_RRM_GRAPHQL_ENDPOINT,
324
- token: "TOKEN",
325
- createResourceRecords: [{ id: "temp-1", kind: "table", parentId: null, settings: {} }],
326
- updateResourceRecords: [{ id: "u1", kind: "table", parentId: null, settings: {} }],
327
- });
328
-
329
- expect(mockedAxios.post).toHaveBeenCalledTimes(1);
330
- const [, body] = mockedAxios.post.mock.calls[0];
331
- expect((body as any).variables.createResourceRecords).toEqual([
332
- { id: "temp-1", kind: "table", parentId: null, settings: {} },
333
- ]);
334
- expect((body as any).variables.updateResourceRecords).toEqual([
335
- { id: "u1", kind: "table", parentId: null, settings: {} },
336
- ]);
337
- expect(res.createCount).toBe(1);
338
- expect(res.updateCount).toBe(1);
339
- });
340
-
341
- it("should not POST in dry-run mode", async () => {
342
- const res = await mutateRecordsDirect({
343
- endpoint: DEFAULT_RRM_GRAPHQL_ENDPOINT,
344
- token: "TOKEN",
345
- createResourceRecords: [{ id: "a", kind: "k", parentId: null, settings: {} }],
346
- updateResourceRecords: [],
347
- dryRun: true,
348
- });
349
-
350
- expect(res.dryRun).toBe(true);
351
- expect(mockedAxios.post).not.toHaveBeenCalled();
352
- });
353
-
354
- it("should throw when token missing", async () => {
355
- await expect(
356
- mutateRecordsDirect({
357
- endpoint: DEFAULT_RRM_GRAPHQL_ENDPOINT,
358
- createResourceRecords: [{ id: "a", kind: "k", parentId: null, settings: {} }],
359
- updateResourceRecords: [],
360
- }),
361
- ).rejects.toThrow(/token/i);
362
- });
363
- });
364
-
365
- describe("pullRemoteResourceRecords", () => {
366
- it("should fetch remote records and write to output file", async () => {
367
- mockedAxios.post.mockResolvedValue({
368
- data: {
369
- data: {
370
- resourceRecordConnection: {
371
- pageInfo: { hasNextPage: false },
372
- edges: remoteRecords.map((r) => ({ node: r })),
373
- },
374
- },
375
- },
376
- });
377
- mockedFs.writeJson.mockResolvedValue(undefined as never);
378
-
379
- const res = await pullRemoteResourceRecords({
380
- endpoint: DEFAULT_RRM_GRAPHQL_ENDPOINT,
381
- output: "/tmp/pulled.json",
382
- });
383
-
384
- expect(res.count).toBe(2);
385
- expect(res.outputPath).toBe("/tmp/pulled.json");
386
- expect(mockedFs.writeJson).toHaveBeenCalledWith("/tmp/pulled.json", remoteRecords, {
387
- spaces: 2,
388
- });
389
- expect(mockedAxios.post).toHaveBeenCalledTimes(1);
390
- });
391
- });
392
- });
@@ -1,125 +0,0 @@
1
- import fs from "fs-extra";
2
- import path from "path";
3
- import os from "os";
4
- import { resolveSource, isStdinSource, getSourceDescription } from "../utils/source-resolver";
5
-
6
- jest.mock("fs-extra");
7
-
8
- const mockedFs = fs as jest.Mocked<typeof fs> & {
9
- pathExists: jest.Mock;
10
- readJson: jest.Mock;
11
- stat: jest.Mock;
12
- };
13
-
14
- describe("source-resolver", () => {
15
- const tmpDir = os.tmpdir();
16
- const testFilePath = path.join(tmpDir, "test-resources.json");
17
- const testDirPath = path.join(tmpDir, "test-resource-dir");
18
- const defaultFilePath = path.join(process.cwd(), "resource-records.json");
19
-
20
- const arrayData = [
21
- { id: "1", kind: "application", parentId: null, settings: {} },
22
- { id: "2", kind: "form", parentId: "1", settings: {} },
23
- ];
24
-
25
- const objectData = {
26
- resourceRecords: [{ id: "1", kind: "application", parentId: null, settings: {} }],
27
- };
28
-
29
- beforeEach(() => {
30
- jest.resetAllMocks();
31
- });
32
-
33
- describe("resolveSource", () => {
34
- it("should read array format JSON file", async () => {
35
- mockedFs.pathExists.mockResolvedValue(true);
36
- mockedFs.readJson.mockResolvedValue(arrayData);
37
- mockedFs.stat.mockResolvedValue({ isDirectory: () => false } as fs.Stats);
38
-
39
- const result = await resolveSource(testFilePath);
40
- expect(result.resourceRecords).toHaveLength(2);
41
- expect(result.format).toBe("array");
42
- expect(result.filePath).toBe(testFilePath);
43
- });
44
-
45
- it("should read object format JSON file", async () => {
46
- mockedFs.pathExists.mockResolvedValue(true);
47
- mockedFs.readJson.mockResolvedValue(objectData);
48
- mockedFs.stat.mockResolvedValue({ isDirectory: () => false } as fs.Stats);
49
-
50
- const result = await resolveSource(testFilePath);
51
- expect(result.resourceRecords).toHaveLength(1);
52
- expect(result.format).toBe("object");
53
- expect(result.filePath).toBe(testFilePath);
54
- });
55
-
56
- it("should read directory by appending default filename", async () => {
57
- const dirFile = path.join(testDirPath, "resource-records.json");
58
- mockedFs.pathExists.mockResolvedValue(true);
59
- mockedFs.readJson.mockResolvedValue(arrayData);
60
- mockedFs.stat.mockResolvedValue({ isDirectory: () => true } as fs.Stats);
61
-
62
- const result = await resolveSource(testDirPath);
63
- expect(mockedFs.readJson).toHaveBeenCalledWith(dirFile);
64
- expect(result.resourceRecords).toHaveLength(2);
65
- });
66
-
67
- it("should throw on missing default file", async () => {
68
- mockedFs.pathExists.mockResolvedValue(false);
69
-
70
- await expect(resolveSource(undefined)).rejects.toThrow("Default source file not found");
71
- });
72
-
73
- it("should throw on non-existent file", async () => {
74
- mockedFs.pathExists.mockResolvedValue(false);
75
- mockedFs.stat.mockRejectedValue(new Error("ENOENT"));
76
- mockedFs.readJson.mockRejectedValue(new Error("File not found"));
77
-
78
- await expect(resolveSource("/nonexistent/file.json")).rejects.toThrow("Source not found");
79
- });
80
-
81
- it("should throw on invalid JSON format", async () => {
82
- mockedFs.pathExists.mockResolvedValue(true);
83
- mockedFs.readJson.mockResolvedValue("invalid");
84
- mockedFs.stat.mockResolvedValue({ isDirectory: () => false } as fs.Stats);
85
-
86
- await expect(resolveSource(testFilePath)).rejects.toThrow("Invalid resource records format");
87
- });
88
-
89
- it("should throw on valid object without resourceRecords field", async () => {
90
- mockedFs.pathExists.mockResolvedValue(true);
91
- mockedFs.readJson.mockResolvedValue({ foo: "bar" });
92
- mockedFs.stat.mockResolvedValue({ isDirectory: () => false } as fs.Stats);
93
-
94
- await expect(resolveSource(testFilePath)).rejects.toThrow("Invalid resource records format");
95
- });
96
- });
97
-
98
- describe("isStdinSource", () => {
99
- it("should return true for -", () => {
100
- expect(isStdinSource("-")).toBe(true);
101
- });
102
-
103
- it("should return false for file paths", () => {
104
- expect(isStdinSource("./data.json")).toBe(false);
105
- });
106
-
107
- it("should return false for undefined", () => {
108
- expect(isStdinSource(undefined)).toBe(false);
109
- });
110
- });
111
-
112
- describe("getSourceDescription", () => {
113
- it("should return default path for undefined", () => {
114
- expect(getSourceDescription(undefined)).toBe("./resource-records.json");
115
- });
116
-
117
- it('should return "stdin" for -', () => {
118
- expect(getSourceDescription("-")).toBe("stdin");
119
- });
120
-
121
- it("should return the path itself", () => {
122
- expect(getSourceDescription("./data.json")).toBe("./data.json");
123
- });
124
- });
125
- });
@@ -1,13 +0,0 @@
1
- import { AppData } from "@ldsg/types";
2
- import { ExtendAppDataParams, ZipAppDataLayout } from "@ldsg/utils";
3
-
4
- interface GetExtendAppDataParamsParams {
5
- appData: AppData;
6
- layout?: ZipAppDataLayout;
7
- appPackageName?: string;
8
- outputPath?: string;
9
- }
10
-
11
- export type GetExtendAppDataParams = (
12
- params: GetExtendAppDataParamsParams,
13
- ) => Promise<ExtendAppDataParams>;
@@ -1,34 +0,0 @@
1
- import { FILES_IN_APP_TEMPLATE_MODULE } from "@ldsg/constants";
2
- import { ExtendAppDataParams } from "@ldsg/utils";
3
- import _ from "lodash";
4
- import { GetExtendAppDataParams } from "../types/get-extend-app-data-params";
5
- import { addPnpmOverrides } from "./add-pnpm-overrides";
6
-
7
- export const getExtendAppDataParamsUsingNpmLdsgModule: GetExtendAppDataParams = async (params) => {
8
- const { appData } = params;
9
-
10
- const packageJsonFile = FILES_IN_APP_TEMPLATE_MODULE.find((file) => file.path === "package.json");
11
-
12
- /**
13
- * 替换模块版本
14
- */
15
- _.set(packageJsonFile, 'data.dependencies["@ldsg/create-app"]', "latest");
16
- _.set(packageJsonFile, 'data.dependencies["@ldsg/opentelemetry-node"]', "latest");
17
-
18
- /**
19
- * 通过 pnpm-workspace.yaml 的 overrides 统一 graphql 相关依赖版本
20
- * 版本号从 package.json 的 dependencies 中读取
21
- */
22
- const graphqlDeps = ["graphql", "graphql-middleware", "graphql-shield"];
23
- const pnpmWorkspaceFile = addPnpmOverrides(FILES_IN_APP_TEMPLATE_MODULE, graphqlDeps);
24
-
25
- let res: ExtendAppDataParams = {
26
- appData,
27
- extraAppData: {
28
- reuseMainAppDependencies: graphqlDeps,
29
- filesInAppModele: [...FILES_IN_APP_TEMPLATE_MODULE, packageJsonFile, pnpmWorkspaceFile],
30
- },
31
- };
32
-
33
- return res;
34
- };