create-esmx 3.0.0-rc.33

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 (40) hide show
  1. package/dist/index.d.ts +8 -0
  2. package/dist/index.mjs +282 -0
  3. package/dist/index.test.d.ts +1 -0
  4. package/dist/index.test.mjs +123 -0
  5. package/dist/integration.test.d.ts +1 -0
  6. package/dist/integration.test.mjs +165 -0
  7. package/dist/utils/index.d.ts +3 -0
  8. package/dist/utils/index.mjs +7 -0
  9. package/dist/utils/package-manager.d.ts +10 -0
  10. package/dist/utils/package-manager.mjs +49 -0
  11. package/dist/utils/package-manager.test.d.ts +4 -0
  12. package/dist/utils/package-manager.test.mjs +275 -0
  13. package/dist/utils/project-name.d.ts +30 -0
  14. package/dist/utils/project-name.mjs +17 -0
  15. package/dist/utils/project-name.test.d.ts +4 -0
  16. package/dist/utils/project-name.test.mjs +186 -0
  17. package/dist/utils/template.d.ts +19 -0
  18. package/dist/utils/template.mjs +8 -0
  19. package/dist/utils/template.test.d.ts +4 -0
  20. package/dist/utils/template.test.mjs +150 -0
  21. package/package.json +71 -0
  22. package/src/index.test.ts +159 -0
  23. package/src/index.ts +391 -0
  24. package/src/integration.test.ts +226 -0
  25. package/src/utils/index.ts +11 -0
  26. package/src/utils/package-manager.test.ts +540 -0
  27. package/src/utils/package-manager.ts +92 -0
  28. package/src/utils/project-name.test.ts +345 -0
  29. package/src/utils/project-name.ts +55 -0
  30. package/src/utils/template.test.ts +234 -0
  31. package/src/utils/template.ts +34 -0
  32. package/template/vue2/README.md +80 -0
  33. package/template/vue2/package.json +27 -0
  34. package/template/vue2/src/app.vue +127 -0
  35. package/template/vue2/src/components/hello-world.vue +79 -0
  36. package/template/vue2/src/create-app.ts +11 -0
  37. package/template/vue2/src/entry.client.ts +5 -0
  38. package/template/vue2/src/entry.node.ts +29 -0
  39. package/template/vue2/src/entry.server.ts +37 -0
  40. package/template/vue2/tsconfig.json +26 -0
@@ -0,0 +1,275 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { getCommand } from "./package-manager.mjs";
3
+ describe("package-manager utilities", () => {
4
+ let originalUserAgent;
5
+ beforeEach(() => {
6
+ originalUserAgent = process.env.npm_config_user_agent;
7
+ });
8
+ afterEach(() => {
9
+ if (originalUserAgent !== void 0) {
10
+ process.env.npm_config_user_agent = originalUserAgent;
11
+ } else {
12
+ process.env.npm_config_user_agent = void 0;
13
+ }
14
+ });
15
+ describe("getCommand", () => {
16
+ describe("when using npm", () => {
17
+ beforeEach(() => {
18
+ process.env.npm_config_user_agent = "npm/8.19.2 node/v18.12.0 darwin x64 workspaces/false";
19
+ });
20
+ it("should return npm install command", () => {
21
+ const commandType = "install";
22
+ const result = getCommand(commandType);
23
+ expect(result).toBe("npm install");
24
+ });
25
+ it("should return npm dev command", () => {
26
+ const commandType = "dev";
27
+ const result = getCommand(commandType);
28
+ expect(result).toBe("npm run dev");
29
+ });
30
+ it("should return npm build command", () => {
31
+ const commandType = "build";
32
+ const result = getCommand(commandType);
33
+ expect(result).toBe("npm run build");
34
+ });
35
+ it("should return npm start command", () => {
36
+ const commandType = "start";
37
+ const result = getCommand(commandType);
38
+ expect(result).toBe("npm start");
39
+ });
40
+ it("should return npm create command", () => {
41
+ const commandType = "create";
42
+ const result = getCommand(commandType);
43
+ expect(result).toBe("npm create esmx@latest");
44
+ });
45
+ it("should return npm build:type command", () => {
46
+ const commandType = "build:type";
47
+ const result = getCommand(commandType);
48
+ expect(result).toBe("npm run build:type");
49
+ });
50
+ it("should return npm lint:type command", () => {
51
+ const commandType = "lint:type";
52
+ const result = getCommand(commandType);
53
+ expect(result).toBe("npm run lint:type");
54
+ });
55
+ });
56
+ describe("when using yarn", () => {
57
+ beforeEach(() => {
58
+ process.env.npm_config_user_agent = "yarn/1.22.19 npm/? node/v18.12.0 darwin x64";
59
+ });
60
+ it("should return yarn install command", () => {
61
+ const commandType = "install";
62
+ const result = getCommand(commandType);
63
+ expect(result).toBe("yarn install");
64
+ });
65
+ it("should return yarn dev command", () => {
66
+ const commandType = "dev";
67
+ const result = getCommand(commandType);
68
+ expect(result).toBe("yarn dev");
69
+ });
70
+ it("should return yarn build command", () => {
71
+ const commandType = "build";
72
+ const result = getCommand(commandType);
73
+ expect(result).toBe("yarn build");
74
+ });
75
+ it("should return yarn start command", () => {
76
+ const commandType = "start";
77
+ const result = getCommand(commandType);
78
+ expect(result).toBe("yarn start");
79
+ });
80
+ it("should return yarn create command", () => {
81
+ const commandType = "create";
82
+ const result = getCommand(commandType);
83
+ expect(result).toBe("yarn create esmx");
84
+ });
85
+ it("should return yarn build:type command", () => {
86
+ const commandType = "build:type";
87
+ const result = getCommand(commandType);
88
+ expect(result).toBe("yarn build:type");
89
+ });
90
+ it("should return yarn lint:type command", () => {
91
+ const commandType = "lint:type";
92
+ const result = getCommand(commandType);
93
+ expect(result).toBe("yarn lint:type");
94
+ });
95
+ });
96
+ describe("when using pnpm", () => {
97
+ beforeEach(() => {
98
+ process.env.npm_config_user_agent = "pnpm/7.14.0 npm/? node/v18.12.0 darwin x64";
99
+ });
100
+ it("should return pnpm install command", () => {
101
+ const commandType = "install";
102
+ const result = getCommand(commandType);
103
+ expect(result).toBe("pnpm install");
104
+ });
105
+ it("should return pnpm dev command", () => {
106
+ const commandType = "dev";
107
+ const result = getCommand(commandType);
108
+ expect(result).toBe("pnpm dev");
109
+ });
110
+ it("should return pnpm build command", () => {
111
+ const commandType = "build";
112
+ const result = getCommand(commandType);
113
+ expect(result).toBe("pnpm build");
114
+ });
115
+ it("should return pnpm start command", () => {
116
+ const commandType = "start";
117
+ const result = getCommand(commandType);
118
+ expect(result).toBe("pnpm start");
119
+ });
120
+ it("should return pnpm create command", () => {
121
+ const commandType = "create";
122
+ const result = getCommand(commandType);
123
+ expect(result).toBe("pnpm create esmx");
124
+ });
125
+ it("should return pnpm build:type command", () => {
126
+ const commandType = "build:type";
127
+ const result = getCommand(commandType);
128
+ expect(result).toBe("pnpm build:type");
129
+ });
130
+ it("should return pnpm lint:type command", () => {
131
+ const commandType = "lint:type";
132
+ const result = getCommand(commandType);
133
+ expect(result).toBe("pnpm lint:type");
134
+ });
135
+ });
136
+ describe("when using bun", () => {
137
+ beforeEach(() => {
138
+ process.env.npm_config_user_agent = "bun/0.6.0 bun/0.6.0 darwin x64";
139
+ });
140
+ it("should return bun install command", () => {
141
+ const commandType = "install";
142
+ const result = getCommand(commandType);
143
+ expect(result).toBe("bun install");
144
+ });
145
+ it("should return bun dev command", () => {
146
+ const commandType = "dev";
147
+ const result = getCommand(commandType);
148
+ expect(result).toBe("bun dev");
149
+ });
150
+ it("should return bun build command", () => {
151
+ const commandType = "build";
152
+ const result = getCommand(commandType);
153
+ expect(result).toBe("bun run build");
154
+ });
155
+ it("should return bun start command", () => {
156
+ const commandType = "start";
157
+ const result = getCommand(commandType);
158
+ expect(result).toBe("bun start");
159
+ });
160
+ it("should return bun create command", () => {
161
+ const commandType = "create";
162
+ const result = getCommand(commandType);
163
+ expect(result).toBe("bun create esmx");
164
+ });
165
+ it("should return bun build:type command", () => {
166
+ const commandType = "build:type";
167
+ const result = getCommand(commandType);
168
+ expect(result).toBe("bun run build:type");
169
+ });
170
+ it("should return bun lint:type command", () => {
171
+ const commandType = "lint:type";
172
+ const result = getCommand(commandType);
173
+ expect(result).toBe("bun run lint:type");
174
+ });
175
+ });
176
+ describe("when user agent is not set", () => {
177
+ beforeEach(() => {
178
+ process.env.npm_config_user_agent = void 0;
179
+ });
180
+ it("should default to npm commands", () => {
181
+ const commandType = "install";
182
+ const result = getCommand(commandType);
183
+ expect(result).toBe("npm install");
184
+ });
185
+ });
186
+ describe("when user agent is empty string", () => {
187
+ beforeEach(() => {
188
+ process.env.npm_config_user_agent = "";
189
+ });
190
+ it("should default to npm commands", () => {
191
+ const commandType = "dev";
192
+ const result = getCommand(commandType);
193
+ expect(result).toBe("npm run dev");
194
+ });
195
+ });
196
+ describe("when user agent contains unknown package manager", () => {
197
+ beforeEach(() => {
198
+ process.env.npm_config_user_agent = "unknown-pm/1.0.0 node/v18.12.0";
199
+ });
200
+ it("should default to npm commands", () => {
201
+ const commandType = "build";
202
+ const result = getCommand(commandType);
203
+ expect(result).toBe("npm run build");
204
+ });
205
+ });
206
+ });
207
+ describe("getCommand with userAgent parameter", () => {
208
+ beforeEach(() => {
209
+ process.env.npm_config_user_agent = void 0;
210
+ });
211
+ it("should use provided userAgent over environment variable", () => {
212
+ process.env.npm_config_user_agent = "npm/8.19.2 node/v18.12.0";
213
+ const customUserAgent = "pnpm/7.14.0 npm/? node/v18.12.0 darwin x64";
214
+ const result = getCommand("install", customUserAgent);
215
+ expect(result).toBe("pnpm install");
216
+ });
217
+ it("should detect pnpm from custom userAgent", () => {
218
+ const userAgent = "pnpm/7.14.0 npm/? node/v18.12.0 darwin x64";
219
+ const installResult = getCommand("install", userAgent);
220
+ const devResult = getCommand("dev", userAgent);
221
+ const buildResult = getCommand("build", userAgent);
222
+ expect(installResult).toBe("pnpm install");
223
+ expect(devResult).toBe("pnpm dev");
224
+ expect(buildResult).toBe("pnpm build");
225
+ });
226
+ it("should detect yarn from custom userAgent", () => {
227
+ const userAgent = "yarn/1.22.19 npm/? node/v18.12.0 darwin x64";
228
+ const installResult = getCommand("install", userAgent);
229
+ const devResult = getCommand("dev", userAgent);
230
+ const buildResult = getCommand("build", userAgent);
231
+ expect(installResult).toBe("yarn install");
232
+ expect(devResult).toBe("yarn dev");
233
+ expect(buildResult).toBe("yarn build");
234
+ });
235
+ it("should detect bun from custom userAgent", () => {
236
+ const userAgent = "bun/0.6.0 bun/0.6.0 darwin x64";
237
+ const installResult = getCommand("install", userAgent);
238
+ const buildResult = getCommand("build", userAgent);
239
+ const buildTypeResult = getCommand("build:type", userAgent);
240
+ expect(installResult).toBe("bun install");
241
+ expect(buildResult).toBe("bun run build");
242
+ expect(buildTypeResult).toBe("bun run build:type");
243
+ });
244
+ it("should default to npm when userAgent does not match known patterns", () => {
245
+ const userAgent = "unknown-package-manager/1.0.0";
246
+ const result = getCommand("install", userAgent);
247
+ expect(result).toBe("npm install");
248
+ });
249
+ it("should handle empty userAgent string", () => {
250
+ const userAgent = "";
251
+ const result = getCommand("install", userAgent);
252
+ expect(result).toBe("npm install");
253
+ });
254
+ it("should fallback to environment variable when userAgent is undefined", () => {
255
+ process.env.npm_config_user_agent = "yarn/1.22.19 npm/? node/v18.12.0";
256
+ const result = getCommand("install", void 0);
257
+ expect(result).toBe("yarn install");
258
+ });
259
+ it("should handle case-sensitive package manager detection", () => {
260
+ const userAgent = "PNPM/7.14.0 npm/? node/v18.12.0";
261
+ const result = getCommand("install", userAgent);
262
+ expect(result).toBe("npm install");
263
+ });
264
+ it("should test all command types with custom userAgent", () => {
265
+ const userAgent = "pnpm/7.14.0 npm/? node/v18.12.0";
266
+ expect(getCommand("install", userAgent)).toBe("pnpm install");
267
+ expect(getCommand("dev", userAgent)).toBe("pnpm dev");
268
+ expect(getCommand("build", userAgent)).toBe("pnpm build");
269
+ expect(getCommand("start", userAgent)).toBe("pnpm start");
270
+ expect(getCommand("create", userAgent)).toBe("pnpm create esmx");
271
+ expect(getCommand("build:type", userAgent)).toBe("pnpm build:type");
272
+ expect(getCommand("lint:type", userAgent)).toBe("pnpm lint:type");
273
+ });
274
+ });
275
+ });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Project name utilities
3
+ */
4
+ export interface ProjectNameResult {
5
+ packageName: string;
6
+ targetDir: string;
7
+ }
8
+ /**
9
+ * Format project name and determine target directory
10
+ *
11
+ * Examples:
12
+ * 1. Input: 'foo'
13
+ * Output: folder `<cwd>/foo`, `package.json#name` -> `foo`
14
+ *
15
+ * 2. Input: 'foo/bar'
16
+ * Output: folder -> `<cwd>/foo/bar` folder, `package.json#name` -> `bar`
17
+ *
18
+ * 3. Input: '@scope/foo'
19
+ * Output: folder -> `<cwd>/@scope/foo` folder, `package.json#name` -> `@scope/foo`
20
+ *
21
+ * 4. Input: './foo/bar'
22
+ * Output: folder -> `<cwd>/foo/bar` folder, `package.json#name` -> `bar`
23
+ *
24
+ * 5. Input: '/root/path/to/foo'
25
+ * Output: folder -> `'/root/path/to/foo'` folder, `package.json#name` -> `foo`
26
+ *
27
+ * 6. Input: '.'
28
+ * Output: folder -> `<cwd>` folder, `package.json#name` -> `<current-dir-name>`
29
+ */
30
+ export declare function formatProjectName(input: string, cwd?: string): ProjectNameResult;
@@ -0,0 +1,17 @@
1
+ import { basename } from "node:path";
2
+ export function formatProjectName(input, cwd) {
3
+ const targetDir = input.replace(/\/+$/g, "");
4
+ let packageName;
5
+ if (targetDir === ".") {
6
+ const workingDir = cwd || process.cwd();
7
+ packageName = basename(workingDir);
8
+ } else if (targetDir.startsWith("@")) {
9
+ packageName = targetDir;
10
+ } else {
11
+ packageName = targetDir.split("/").pop() || "esmx-project";
12
+ }
13
+ return {
14
+ packageName,
15
+ targetDir
16
+ };
17
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for project-name utilities
3
+ */
4
+ export {};
@@ -0,0 +1,186 @@
1
+ import { basename } from "node:path";
2
+ import { describe, expect, it } from "vitest";
3
+ import { formatProjectName } from "./project-name.mjs";
4
+ describe("project-name utilities", () => {
5
+ describe("formatProjectName", () => {
6
+ it("should handle simple project name", () => {
7
+ const input = "foo";
8
+ const result = formatProjectName(input);
9
+ expect(result.targetDir).toBe("foo");
10
+ expect(result.packageName).toBe("foo");
11
+ });
12
+ it("should handle nested path project name", () => {
13
+ const input = "foo/bar";
14
+ const result = formatProjectName(input);
15
+ expect(result.targetDir).toBe("foo/bar");
16
+ expect(result.packageName).toBe("bar");
17
+ });
18
+ it("should handle scoped package name", () => {
19
+ const input = "@scope/foo";
20
+ const result = formatProjectName(input);
21
+ expect(result.targetDir).toBe("@scope/foo");
22
+ expect(result.packageName).toBe("@scope/foo");
23
+ });
24
+ it("should handle relative path project name", () => {
25
+ const input = "./foo/bar";
26
+ const result = formatProjectName(input);
27
+ expect(result.targetDir).toBe("./foo/bar");
28
+ expect(result.packageName).toBe("bar");
29
+ });
30
+ it("should handle absolute path project name", () => {
31
+ const input = "/root/path/to/foo";
32
+ const result = formatProjectName(input);
33
+ expect(result.targetDir).toBe("/root/path/to/foo");
34
+ expect(result.packageName).toBe("foo");
35
+ });
36
+ it("should handle current directory", () => {
37
+ const input = ".";
38
+ const expectedPackageName = basename(process.cwd());
39
+ const result = formatProjectName(input);
40
+ expect(result.targetDir).toBe(".");
41
+ expect(result.packageName).toBe(expectedPackageName);
42
+ });
43
+ it("should handle project name with trailing slashes", () => {
44
+ const input = "foo/bar///";
45
+ const result = formatProjectName(input);
46
+ expect(result.targetDir).toBe("foo/bar");
47
+ expect(result.packageName).toBe("bar");
48
+ });
49
+ it("should handle project name with multiple trailing slashes", () => {
50
+ const input = "my-project/////";
51
+ const result = formatProjectName(input);
52
+ expect(result.targetDir).toBe("my-project");
53
+ expect(result.packageName).toBe("my-project");
54
+ });
55
+ it("should handle deep nested path", () => {
56
+ const input = "projects/web/frontend/my-app";
57
+ const result = formatProjectName(input);
58
+ expect(result.targetDir).toBe("projects/web/frontend/my-app");
59
+ expect(result.packageName).toBe("my-app");
60
+ });
61
+ it("should handle scoped package with nested path", () => {
62
+ const input = "org/@scope/package-name";
63
+ const result = formatProjectName(input);
64
+ expect(result.targetDir).toBe("org/@scope/package-name");
65
+ expect(result.packageName).toBe("package-name");
66
+ });
67
+ it("should handle scoped package starting with @", () => {
68
+ const input = "@company/ui-library";
69
+ const result = formatProjectName(input);
70
+ expect(result.targetDir).toBe("@company/ui-library");
71
+ expect(result.packageName).toBe("@company/ui-library");
72
+ });
73
+ it("should handle empty path segment", () => {
74
+ const input = "foo//bar";
75
+ const result = formatProjectName(input);
76
+ expect(result.targetDir).toBe("foo//bar");
77
+ expect(result.packageName).toBe("bar");
78
+ });
79
+ it("should handle single character project name", () => {
80
+ const input = "a";
81
+ const result = formatProjectName(input);
82
+ expect(result.targetDir).toBe("a");
83
+ expect(result.packageName).toBe("a");
84
+ });
85
+ it("should handle project name with numbers and hyphens", () => {
86
+ const input = "my-project-v2";
87
+ const result = formatProjectName(input);
88
+ expect(result.targetDir).toBe("my-project-v2");
89
+ expect(result.packageName).toBe("my-project-v2");
90
+ });
91
+ it("should handle project name ending with slash", () => {
92
+ const input = "path/to/project/";
93
+ const result = formatProjectName(input);
94
+ expect(result.targetDir).toBe("path/to/project");
95
+ expect(result.packageName).toBe("project");
96
+ });
97
+ it("should fall back to default name when path ends with slash and no name", () => {
98
+ const input = "/";
99
+ const result = formatProjectName(input);
100
+ expect(result.targetDir).toBe("");
101
+ expect(result.packageName).toBe("esmx-project");
102
+ });
103
+ it("should handle Windows-style paths", () => {
104
+ const input = "C:\\projects\\my-app";
105
+ const result = formatProjectName(input);
106
+ expect(result.targetDir).toBe("C:\\projects\\my-app");
107
+ expect(result.packageName).toBe("C:\\projects\\my-app");
108
+ });
109
+ it("should handle mixed path separators", () => {
110
+ const input = "path\\to/project";
111
+ const result = formatProjectName(input);
112
+ expect(result.targetDir).toBe("path\\to/project");
113
+ expect(result.packageName).toBe("project");
114
+ });
115
+ });
116
+ describe("formatProjectName with cwd parameter", () => {
117
+ it('should use custom cwd when input is "."', () => {
118
+ const input = ".";
119
+ const customCwd = "/custom/working/directory";
120
+ const result = formatProjectName(
121
+ input,
122
+ customCwd
123
+ );
124
+ expect(result.targetDir).toBe(".");
125
+ expect(result.packageName).toBe("directory");
126
+ });
127
+ it("should fallback to process.cwd() when cwd is not provided", () => {
128
+ const input = ".";
129
+ const expectedPackageName = basename(process.cwd());
130
+ const result = formatProjectName(input);
131
+ expect(result.targetDir).toBe(".");
132
+ expect(result.packageName).toBe(expectedPackageName);
133
+ });
134
+ it('should ignore cwd parameter when input is not "."', () => {
135
+ const input = "my-project";
136
+ const customCwd = "/custom/working/directory";
137
+ const result = formatProjectName(
138
+ input,
139
+ customCwd
140
+ );
141
+ expect(result.targetDir).toBe("my-project");
142
+ expect(result.packageName).toBe("my-project");
143
+ });
144
+ it("should handle scoped packages with custom cwd", () => {
145
+ const input = "@scope/package";
146
+ const customCwd = "/any/directory";
147
+ const result = formatProjectName(
148
+ input,
149
+ customCwd
150
+ );
151
+ expect(result.targetDir).toBe("@scope/package");
152
+ expect(result.packageName).toBe("@scope/package");
153
+ });
154
+ it("should handle nested paths with custom cwd", () => {
155
+ const input = "org/team/project";
156
+ const customCwd = "/any/directory";
157
+ const result = formatProjectName(
158
+ input,
159
+ customCwd
160
+ );
161
+ expect(result.targetDir).toBe("org/team/project");
162
+ expect(result.packageName).toBe("project");
163
+ });
164
+ it("should handle Unix-style absolute paths in cwd", () => {
165
+ const input = ".";
166
+ const customCwd = "/home/user/projects/my-awesome-app";
167
+ const result = formatProjectName(
168
+ input,
169
+ customCwd
170
+ );
171
+ expect(result.targetDir).toBe(".");
172
+ expect(result.packageName).toBe("my-awesome-app");
173
+ });
174
+ it("should handle Windows-style absolute paths in cwd", () => {
175
+ const input = ".";
176
+ const customCwd = "C:\\Users\\Developer\\Projects\\WindowsApp";
177
+ const result = formatProjectName(
178
+ input,
179
+ customCwd
180
+ );
181
+ expect(result.targetDir).toBe(".");
182
+ const expectedPackageName = basename(customCwd);
183
+ expect(result.packageName).toBe(expectedPackageName);
184
+ });
185
+ });
186
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Template variable replacement utilities
3
+ */
4
+ /**
5
+ * Replace template variables in content using mustache-style syntax {{variableName}}
6
+ *
7
+ * @param content - The content string containing template variables
8
+ * @param variables - Object containing variable names and their replacement values
9
+ * @returns Content with all template variables replaced
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const content = "Hello {{name}}, version {{version}}!";
14
+ * const variables = { name: "World", version: "1.0.0" };
15
+ * const result = replaceTemplateVariables(content, variables);
16
+ * // Result: "Hello World, version 1.0.0!"
17
+ * ```
18
+ */
19
+ export declare function replaceTemplateVariables(content: string, variables: Record<string, string>): string;
@@ -0,0 +1,8 @@
1
+ export function replaceTemplateVariables(content, variables) {
2
+ let result = content;
3
+ for (const [key, value] of Object.entries(variables)) {
4
+ const pattern = new RegExp(`\\{\\{${key}\\}\\}`, "g");
5
+ result = result.replace(pattern, value);
6
+ }
7
+ return result;
8
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for template variable replacement utilities
3
+ */
4
+ export {};