@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
@@ -1,151 +0,0 @@
1
- import {
2
- formatSuccess,
3
- formatError,
4
- formatJson,
5
- formatPrettyList,
6
- formatPrettyTree,
7
- formatPrettyDiff,
8
- } from "../utils/formatter";
9
-
10
- describe("formatter", () => {
11
- describe("formatSuccess", () => {
12
- it("should format success response", () => {
13
- const result = formatSuccess({ id: "1" });
14
- expect(result).toEqual({ success: true, data: { id: "1" } });
15
- });
16
- });
17
-
18
- describe("formatError", () => {
19
- it("should format error response", () => {
20
- const result = formatError("NOT_FOUND", "Resource not found");
21
- expect(result).toEqual({
22
- success: false,
23
- error: { code: "NOT_FOUND", message: "Resource not found" },
24
- });
25
- });
26
- });
27
-
28
- describe("formatJson", () => {
29
- it("should format JSON with 2-space indent", () => {
30
- const result = formatJson({ a: 1, b: "test" });
31
- expect(result).toBe('{\n "a": 1,\n "b": "test"\n}');
32
- });
33
- });
34
-
35
- describe("formatPrettyList", () => {
36
- it("should return message for empty list", () => {
37
- expect(formatPrettyList([])).toBe("No resources found.");
38
- });
39
-
40
- it("should format list with header and rows", () => {
41
- const resources = [
42
- { id: "1", kind: "application", parentId: null, title: "App1" },
43
- { id: "2", kind: "form", parentId: "1", title: "Form1" },
44
- ];
45
- const result = formatPrettyList(resources);
46
- expect(result).toContain("ID");
47
- expect(result).toContain("KIND");
48
- expect(result).toContain("PARENT ID");
49
- expect(result).toContain("Total: 2 resource(s)");
50
- });
51
- });
52
-
53
- describe("formatPrettyTree", () => {
54
- it("should format a tree with root and children", () => {
55
- const tree = {
56
- resource: {
57
- id: "1",
58
- kind: "application",
59
- parentId: null,
60
- settings: { slug: "app1", title: "App1", description: "" },
61
- },
62
- children: [
63
- {
64
- resource: {
65
- id: "2",
66
- kind: "form",
67
- parentId: "1",
68
- settings: { slug: "form1", title: "Form1", description: "" },
69
- },
70
- children: [],
71
- },
72
- ],
73
- };
74
-
75
- const result = formatPrettyTree(tree, false);
76
- expect(result).toContain("1");
77
- expect(result).toContain("2");
78
- expect(result).toContain("└──");
79
- });
80
-
81
- it("should show kind prefix with showKind option", () => {
82
- const tree = {
83
- resource: {
84
- id: "1",
85
- kind: "application",
86
- parentId: null,
87
- settings: { slug: "app1", title: "App1", description: "" },
88
- },
89
- children: [],
90
- };
91
-
92
- const result = formatPrettyTree(tree, true);
93
- expect(result).toContain("[application]");
94
- });
95
- });
96
-
97
- describe("formatPrettyDiff", () => {
98
- it("should show no differences message", () => {
99
- const diff = {
100
- id: "1",
101
- kind: "application",
102
- sourceA: "a.json",
103
- sourceB: "b.json",
104
- changed: [],
105
- added: [],
106
- removed: [],
107
- sideA: { id: "1", kind: "application", parentId: null, settings: {} },
108
- sideB: { id: "1", kind: "application", parentId: null, settings: {} },
109
- } as any;
110
-
111
- const result = formatPrettyDiff(diff);
112
- expect(result).toContain("No differences found.");
113
- });
114
-
115
- it("should show changed fields", () => {
116
- const diff = {
117
- id: "1",
118
- kind: "application",
119
- sourceA: "a.json",
120
- sourceB: "b.json",
121
- changed: [{ path: "settings.title", from: "Old", to: "New" }],
122
- added: [],
123
- removed: [],
124
- sideA: { id: "1", kind: "application", parentId: null, settings: {} },
125
- sideB: { id: "1", kind: "application", parentId: null, settings: {} },
126
- } as any;
127
-
128
- const result = formatPrettyDiff(diff);
129
- expect(result).toContain("settings.title");
130
- expect(result).toContain("Old");
131
- expect(result).toContain("New");
132
- });
133
-
134
- it("should show side-only existence", () => {
135
- const diffA: any = {
136
- id: "1",
137
- kind: "application",
138
- sourceA: "a.json",
139
- sourceB: "b.json",
140
- changed: [],
141
- added: [],
142
- removed: [],
143
- sideA: null,
144
- sideB: { id: "1", kind: "application", parentId: null, settings: {} },
145
- };
146
-
147
- const result = formatPrettyDiff(diffA);
148
- expect(result).toContain("only exists in source B");
149
- });
150
- });
151
- });
@@ -1,141 +0,0 @@
1
- import { createRequire } from "module";
2
- import { generateAppIndexTs, ZipAppDataLayout, zipAppData } from "@ldsg/utils";
3
-
4
- /**
5
- * jszip 是 @ldsg/utils 的依赖,不在 @ldsg/cli 的依赖里;
6
- * 这里直接复用 utils 的 node_modules,避免为测试引入额外依赖。
7
- */
8
- const nodeRequire = createRequire(__filename);
9
- const JSZip = nodeRequire("../../../../libs/utils/node_modules/jszip");
10
-
11
- const sampleHandlerRecords = [
12
- {
13
- id: "application-resource-handler",
14
- kind: "handler",
15
- parentId: null,
16
- settings: {
17
- code: 'export * from "@ldsg/application";',
18
- dependencies: [{ name: "@ldsg/application" }],
19
- },
20
- },
21
- {
22
- id: "my-handler-1",
23
- kind: "handler",
24
- parentId: null,
25
- settings: {
26
- code: 'export * from "@ldsg/handler";',
27
- dependencies: [{ name: "@ldsg/handler" }],
28
- },
29
- },
30
- ];
31
-
32
- const sampleResourceRecords = [
33
- {
34
- id: "application-resource-definition",
35
- kind: "resource_definition",
36
- parentId: "root",
37
- settings: {
38
- title: "应用资源定义",
39
- kind: "application",
40
- handlerResourceId: "application-resource-handler",
41
- },
42
- },
43
- ...sampleHandlerRecords,
44
- {
45
- id: "main-app",
46
- kind: "application",
47
- parentId: "root",
48
- settings: { title: "主要应用" },
49
- },
50
- ];
51
-
52
- describe("generateAppIndexTs", () => {
53
- it("should generate NESTED handler import paths", () => {
54
- const content = generateAppIndexTs({
55
- handlerResourceRecords: sampleHandlerRecords as never,
56
- getHandlerImportPath: (id) => `./handlers/${id}`,
57
- });
58
-
59
- expect(content).toContain(
60
- 'import * as handlerModule_application_resource_handler from "./handlers/application-resource-handler";',
61
- );
62
- expect(content).toContain(
63
- 'import * as handlerModule_my_handler_1 from "./handlers/my-handler-1";',
64
- );
65
- });
66
-
67
- it("should generate FLAT handler import paths", () => {
68
- const content = generateAppIndexTs({
69
- handlerResourceRecords: sampleHandlerRecords as never,
70
- getHandlerImportPath: (id) => `../${id}`,
71
- });
72
-
73
- expect(content).toContain(
74
- 'import * as handlerModule_application_resource_handler from "../application-resource-handler";',
75
- );
76
- });
77
-
78
- it("should inject handler into the corresponding handler resource", () => {
79
- const content = generateAppIndexTs({
80
- handlerResourceRecords: sampleHandlerRecords as never,
81
- getHandlerImportPath: (id) => `./handlers/${id}`,
82
- });
83
-
84
- expect(content).toContain(
85
- '"application-resource-handler": handlerModule_application_resource_handler',
86
- );
87
- expect(content).toContain('"my-handler-1": handlerModule_my_handler_1');
88
- expect(content).toContain('if (kind === "handler" && handlerModules[id])');
89
- expect(content).toContain("handler: handlerModules[id].handler");
90
- expect(content).toContain("resourceRecords: wiredResourceRecords");
91
- });
92
-
93
- it("should generate a valid base app when there are no handlers", () => {
94
- const content = generateAppIndexTs({
95
- handlerResourceRecords: [],
96
- getHandlerImportPath: (id) => `./handlers/${id}`,
97
- });
98
-
99
- expect(content).not.toContain("import * as handlerModule_");
100
- expect(content).toContain("const handlerModules: Record<string, any> = {");
101
- expect(content).toContain("resourceRecords: wiredResourceRecords");
102
- });
103
- });
104
-
105
- describe("zipAppData", () => {
106
- it("should write a handler-aware app index.ts for NESTED layout", async () => {
107
- const { archive } = await zipAppData({
108
- resourceRecords: sampleResourceRecords as never,
109
- type: "nodebuffer",
110
- layout: ZipAppDataLayout.NESTED,
111
- });
112
-
113
- const zip = await JSZip.loadAsync(archive);
114
-
115
- const indexTs = await zip.file("index.ts")?.async("string");
116
-
117
- expect(indexTs).toBeTruthy();
118
- expect(indexTs).toContain(
119
- 'import * as handlerModule_application_resource_handler from "./handlers/application-resource-handler";',
120
- );
121
- expect(indexTs).toContain("handler: handlerModules[id].handler");
122
- });
123
-
124
- it("should write a handler-aware app index.ts for FLAT layout", async () => {
125
- const { archive } = await zipAppData({
126
- resourceRecords: sampleResourceRecords as never,
127
- type: "nodebuffer",
128
- layout: ZipAppDataLayout.FLAT,
129
- });
130
-
131
- const zip = await JSZip.loadAsync(archive);
132
-
133
- const indexTs = await zip.file("app/index.ts")?.async("string");
134
-
135
- expect(indexTs).toBeTruthy();
136
- expect(indexTs).toContain(
137
- 'import * as handlerModule_application_resource_handler from "../application-resource-handler";',
138
- );
139
- expect(indexTs).toContain("handler: handlerModules[id].handler");
140
- });
141
- });
@@ -1,109 +0,0 @@
1
- import { AppData } from "@ldsg/types";
2
- import { getExtendAppDataParamsUsingWorkspaceLdsgModule } from "../utils/get-extend-app-data-params-using-workspace-ldsg-module";
3
-
4
- /**
5
- * 拦截 syncRushProjects,避免测试写入真实 rush.json
6
- */
7
- jest.mock("@ldsg/utils", () => {
8
- const actual = jest.requireActual("@ldsg/utils");
9
-
10
- return {
11
- ...actual,
12
- RUSH_JSON_PATH: "/mock/rush.json",
13
- syncRushProjects: jest.fn(),
14
- };
15
- });
16
-
17
- import { syncRushProjects, ZipAppDataLayout } from "@ldsg/utils";
18
-
19
- const mockedSyncRushProjects = syncRushProjects as jest.Mock;
20
-
21
- const handlerId = "handler-1";
22
-
23
- const appData: AppData = {
24
- resourceRecords: [
25
- {
26
- id: handlerId,
27
- kind: "handler",
28
- parentId: "root",
29
- settings: {
30
- slug: "handler-1",
31
- title: "应用实例化资源处理程序",
32
- description: "",
33
- code: 'export * from "@ldsg/application";',
34
- dependencies: [
35
- { name: "@ldsg/application", version: "^1.0.0" },
36
- { name: "lodash", version: "^4.17.21" },
37
- ],
38
- },
39
- },
40
- ],
41
- };
42
-
43
- describe("getExtendAppDataParamsUsingWorkspaceLdsgModule", () => {
44
- beforeEach(() => {
45
- mockedSyncRushProjects.mockClear();
46
- });
47
-
48
- it("NESTED 布局:app 与 handler 项目文件夹按嵌套结构计算", async () => {
49
- const res = await getExtendAppDataParamsUsingWorkspaceLdsgModule({
50
- appData,
51
- layout: ZipAppDataLayout.NESTED,
52
- outputPath: "../../apps/rrm",
53
- });
54
-
55
- expect(mockedSyncRushProjects).toHaveBeenCalledWith("/mock/rush.json", [
56
- { packageName: "@ldsg/app", projectFolder: "apps/rrm" },
57
- { packageName: handlerId, projectFolder: "apps/rrm/handlers/handler-1" },
58
- ]);
59
-
60
- const packageJsonFile = res.extraAppData.filesInAppModele.find(
61
- (file) => file.path === "package.json",
62
- );
63
- expect(packageJsonFile).toBeDefined();
64
- });
65
-
66
- it("FLAT 布局(默认):app 在输出根目录 app/ 下,handler 平铺", async () => {
67
- await getExtendAppDataParamsUsingWorkspaceLdsgModule({
68
- appData,
69
- outputPath: "../../generated",
70
- });
71
-
72
- expect(mockedSyncRushProjects).toHaveBeenCalledWith("/mock/rush.json", [
73
- { packageName: "@ldsg/app", projectFolder: "generated/app" },
74
- { packageName: handlerId, projectFolder: "generated/handler-1" },
75
- ]);
76
- });
77
-
78
- it("NESTED 布局:app 包名使用传入的 appPackageName,且 @ldsg 依赖改为 workspace:*", async () => {
79
- const res = await getExtendAppDataParamsUsingWorkspaceLdsgModule({
80
- appData,
81
- layout: ZipAppDataLayout.NESTED,
82
- outputPath: "../../apps/rrm",
83
- appPackageName: "@ldsg/rrm",
84
- });
85
-
86
- const packageJsonFile = res.extraAppData.filesInAppModele.find(
87
- (file) => file.path === "package.json",
88
- );
89
- expect(packageJsonFile).toBeDefined();
90
- expect((packageJsonFile as { data: { name: string } }).data.name).toBe("@ldsg/rrm");
91
-
92
- const handlerRecord = res.appData.resourceRecords.find((record) => record.id === handlerId);
93
- expect(handlerRecord).toBeDefined();
94
- expect(
95
- (
96
- handlerRecord as unknown as {
97
- settings: { dependencies: { name: string; version: string }[] };
98
- }
99
- ).settings.dependencies,
100
- ).toEqual(
101
- expect.arrayContaining([
102
- { name: "@ldsg/application", version: "workspace:*" },
103
- { name: "lodash", version: "^4.17.21" },
104
- { name: "@types/node", version: "^24.1.0" },
105
- { name: "typescript", version: "^5.3.3" },
106
- ]),
107
- );
108
- });
109
- });
@@ -1,186 +0,0 @@
1
- import fs from "fs-extra";
2
- import { appendRecord, updateRecord, removeRecord, generateId } from "../utils/json-file-mutator";
3
- import { SourceData } from "../types/resource-record";
4
- import { ResourceRecords } from "@ldsg/types";
5
-
6
- jest.mock("fs-extra");
7
-
8
- const mockedFs = fs as jest.Mocked<typeof fs>;
9
-
10
- describe("json-file-mutator", () => {
11
- const arrayRecords: ResourceRecords = [
12
- {
13
- id: "1",
14
- kind: "application",
15
- parentId: null,
16
- settings: { slug: "app1", title: "App1", description: "" },
17
- },
18
- {
19
- id: "2",
20
- kind: "form",
21
- parentId: "1",
22
- settings: { slug: "form1", title: "Form1", description: "" },
23
- },
24
- {
25
- id: "3",
26
- kind: "table",
27
- parentId: "1",
28
- settings: { slug: "table1", title: "Table1", description: "" },
29
- },
30
- {
31
- id: "4",
32
- kind: "field",
33
- parentId: "3",
34
- settings: { slug: "field1", title: "Field1", description: "" },
35
- },
36
- ];
37
-
38
- const arraySourceData: SourceData = {
39
- resourceRecords: arrayRecords,
40
- format: "array",
41
- filePath: "/test/data.json",
42
- };
43
-
44
- const objectSourceData: SourceData = {
45
- resourceRecords: arrayRecords,
46
- format: "object",
47
- filePath: "/test/data.json",
48
- };
49
-
50
- beforeEach(() => {
51
- jest.resetAllMocks();
52
- mockedFs.readJson.mockResolvedValue([...arrayRecords]);
53
- });
54
-
55
- describe("generateId", () => {
56
- it("should generate a string id", () => {
57
- const id = generateId();
58
- expect(typeof id).toBe("string");
59
- expect(id.length).toBeGreaterThan(5);
60
- });
61
-
62
- it("should generate unique ids", () => {
63
- const ids = new Set(Array.from({ length: 10 }, () => generateId()));
64
- expect(ids.size).toBe(10);
65
- });
66
- });
67
-
68
- describe("appendRecord", () => {
69
- it("should append a new record to array format", async () => {
70
- mockedFs.readJson.mockResolvedValue([...arrayRecords]);
71
-
72
- const newRecord = {
73
- id: "5",
74
- kind: "form",
75
- parentId: "1",
76
- settings: { slug: "form2", title: "Form2", description: "" },
77
- };
78
- const result = await appendRecord(arraySourceData, newRecord);
79
-
80
- expect(result.record.id).toBe("5");
81
- expect(result.allRecords).toHaveLength(5);
82
- expect(mockedFs.writeJson).toHaveBeenCalledWith(
83
- "/test/data.json",
84
- expect.arrayContaining([expect.objectContaining({ id: "5" })]),
85
- { spaces: 2 },
86
- );
87
- });
88
-
89
- it("should append to object format preserving structure", async () => {
90
- mockedFs.readJson.mockResolvedValue({ resourceRecords: [...arrayRecords] });
91
-
92
- const newRecord = {
93
- id: "5",
94
- kind: "form",
95
- parentId: "1",
96
- settings: { slug: "form2", title: "Form2", description: "" },
97
- };
98
- await appendRecord(objectSourceData, newRecord);
99
-
100
- expect(mockedFs.writeJson).toHaveBeenCalledWith(
101
- "/test/data.json",
102
- expect.objectContaining({
103
- resourceRecords: expect.arrayContaining([expect.objectContaining({ id: "5" })]),
104
- }),
105
- { spaces: 2 },
106
- );
107
- });
108
-
109
- it("should throw on duplicate id", async () => {
110
- const dupRecord = {
111
- id: "1",
112
- kind: "application",
113
- parentId: null,
114
- settings: { slug: "app1", title: "App1", description: "" },
115
- };
116
- await expect(appendRecord(arraySourceData, dupRecord)).rejects.toThrow("already exists");
117
- });
118
-
119
- it("should not write file in dry-run mode", async () => {
120
- const newRecord = {
121
- id: "5",
122
- kind: "form",
123
- parentId: "1",
124
- settings: { slug: "form2", title: "Form2", description: "" },
125
- };
126
- await appendRecord(arraySourceData, newRecord, true);
127
-
128
- expect(mockedFs.writeJson).not.toHaveBeenCalled();
129
- });
130
- });
131
-
132
- describe("updateRecord", () => {
133
- it("should update settings and merge", async () => {
134
- mockedFs.readJson.mockResolvedValue([...arrayRecords]);
135
-
136
- const result = await updateRecord(arraySourceData, "1", {
137
- title: "Updated App",
138
- newField: "value",
139
- });
140
-
141
- expect(result.record.settings).toEqual({
142
- slug: "app1",
143
- title: "Updated App",
144
- description: "",
145
- newField: "value",
146
- });
147
- expect(mockedFs.writeJson).toHaveBeenCalled();
148
- });
149
-
150
- it("should throw on non-existent id", async () => {
151
- await expect(updateRecord(arraySourceData, "nonexistent", { title: "x" })).rejects.toThrow(
152
- "not found",
153
- );
154
- });
155
-
156
- it("should not write file in dry-run mode", async () => {
157
- await updateRecord(arraySourceData, "1", { title: "Dry Run" }, true);
158
-
159
- expect(mockedFs.writeJson).not.toHaveBeenCalled();
160
- });
161
- });
162
-
163
- describe("removeRecord", () => {
164
- it("should remove record and its children", async () => {
165
- mockedFs.readJson.mockResolvedValue([...arrayRecords]);
166
-
167
- const result = await removeRecord(arraySourceData, "3");
168
-
169
- expect(result.removed).toHaveLength(2);
170
- expect(result.removed.map((r) => r.id)).toEqual(["3", "4"]);
171
- expect(result.allRecords).toHaveLength(2);
172
- expect(result.allRecords.map((r) => r.id)).toEqual(["1", "2"]);
173
- });
174
-
175
- it("should throw on non-existent id", async () => {
176
- await expect(removeRecord(arraySourceData, "nonexistent")).rejects.toThrow("not found");
177
- });
178
-
179
- it("should not write file in dry-run mode", async () => {
180
- const result = await removeRecord(arraySourceData, "3", true);
181
-
182
- expect(result.removed).toHaveLength(2);
183
- expect(mockedFs.writeJson).not.toHaveBeenCalled();
184
- });
185
- });
186
- });