@salesforce/webapp-template-cli-experimental 1.3.3

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 (71) hide show
  1. package/LICENSE.txt +82 -0
  2. package/README.md +1464 -0
  3. package/dist/commands/apply-patches.d.ts +23 -0
  4. package/dist/commands/apply-patches.d.ts.map +1 -0
  5. package/dist/commands/apply-patches.js +650 -0
  6. package/dist/commands/apply-patches.js.map +1 -0
  7. package/dist/commands/new-app-feature.d.ts +7 -0
  8. package/dist/commands/new-app-feature.d.ts.map +1 -0
  9. package/dist/commands/new-app-feature.js +208 -0
  10. package/dist/commands/new-app-feature.js.map +1 -0
  11. package/dist/commands/new-app.d.ts +6 -0
  12. package/dist/commands/new-app.d.ts.map +1 -0
  13. package/dist/commands/new-app.js +7 -0
  14. package/dist/commands/new-app.js.map +1 -0
  15. package/dist/commands/watch-patches.d.ts +4 -0
  16. package/dist/commands/watch-patches.d.ts.map +1 -0
  17. package/dist/commands/watch-patches.js +128 -0
  18. package/dist/commands/watch-patches.js.map +1 -0
  19. package/dist/core/dependency-resolver.d.ts +40 -0
  20. package/dist/core/dependency-resolver.d.ts.map +1 -0
  21. package/dist/core/dependency-resolver.js +126 -0
  22. package/dist/core/dependency-resolver.js.map +1 -0
  23. package/dist/core/file-operations.d.ts +55 -0
  24. package/dist/core/file-operations.d.ts.map +1 -0
  25. package/dist/core/file-operations.js +350 -0
  26. package/dist/core/file-operations.js.map +1 -0
  27. package/dist/core/package-json-merger.d.ts +31 -0
  28. package/dist/core/package-json-merger.d.ts.map +1 -0
  29. package/dist/core/package-json-merger.js +149 -0
  30. package/dist/core/package-json-merger.js.map +1 -0
  31. package/dist/core/patch-loader.d.ts +18 -0
  32. package/dist/core/patch-loader.d.ts.map +1 -0
  33. package/dist/core/patch-loader.js +115 -0
  34. package/dist/core/patch-loader.js.map +1 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +95 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/types.d.ts +28 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +2 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/utils/debounce.d.ts +9 -0
  44. package/dist/utils/debounce.d.ts.map +1 -0
  45. package/dist/utils/debounce.js +20 -0
  46. package/dist/utils/debounce.js.map +1 -0
  47. package/dist/utils/import-merger.d.ts +17 -0
  48. package/dist/utils/import-merger.d.ts.map +1 -0
  49. package/dist/utils/import-merger.js +244 -0
  50. package/dist/utils/import-merger.js.map +1 -0
  51. package/dist/utils/logger.d.ts +6 -0
  52. package/dist/utils/logger.d.ts.map +1 -0
  53. package/dist/utils/logger.js +22 -0
  54. package/dist/utils/logger.js.map +1 -0
  55. package/dist/utils/path-mappings.d.ts +94 -0
  56. package/dist/utils/path-mappings.d.ts.map +1 -0
  57. package/dist/utils/path-mappings.js +139 -0
  58. package/dist/utils/path-mappings.js.map +1 -0
  59. package/dist/utils/paths.d.ts +61 -0
  60. package/dist/utils/paths.d.ts.map +1 -0
  61. package/dist/utils/paths.js +178 -0
  62. package/dist/utils/paths.js.map +1 -0
  63. package/dist/utils/route-merger.d.ts +107 -0
  64. package/dist/utils/route-merger.d.ts.map +1 -0
  65. package/dist/utils/route-merger.js +358 -0
  66. package/dist/utils/route-merger.js.map +1 -0
  67. package/dist/utils/validation.d.ts +35 -0
  68. package/dist/utils/validation.d.ts.map +1 -0
  69. package/dist/utils/validation.js +137 -0
  70. package/dist/utils/validation.js.map +1 -0
  71. package/package.json +44 -0
@@ -0,0 +1,55 @@
1
+ export declare class FileOperationError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ /**
5
+ * Process webApplication meta.xml file: replace template parameters and rename
6
+ * @param targetFilePath - Full path to the target file
7
+ * @param appName - Application name to use for masterLabel and filename
8
+ * @returns New file path if file was renamed, or original path
9
+ */
10
+ export declare function processWebApplicationMetaFile(targetFilePath: string, appName: string): string;
11
+ /**
12
+ * Copy site-container template into target force-app/main/default, replacing
13
+ * template params (appName, siteName, siteName1, siteNameLower, etc.) and path
14
+ * placeholders (__siteName__, __siteName1__) in directory and file names.
15
+ *
16
+ * @param templateRoot - Path to template-site-container/force-app/main/default
17
+ * @param targetForceAppDefault - Path to target's force-app/main/default
18
+ * @param appName - Application name (used as site name base)
19
+ */
20
+ export declare function copySiteContainerTemplate(templateRoot: string, targetForceAppDefault: string, appName: string): void;
21
+ /**
22
+ * Apply a file from patch to target, optionally merging with base
23
+ *
24
+ * @param patchFilePath - Full path to the patch file from the feature
25
+ * @param baseFilePath - Full path to the original base app file (used for merging)
26
+ * @param targetFilePath - Full path to where the result should be written
27
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/routes.tsx")
28
+ * @param shouldMerge - If true, merges patch with base using route merge strategy
29
+ * @param appName - Application name for template processing (optional)
30
+ */
31
+ export declare function applyFile(patchFilePath: string, baseFilePath: string, targetFilePath: string, relativeTargetPath: string, shouldMerge?: boolean, appName?: string): Promise<void>;
32
+ /**
33
+ * Delete a file or directory from the target app
34
+ *
35
+ * @param targetFilePath - Full path to the file/directory to delete
36
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/routes.tsx")
37
+ */
38
+ export declare function deleteFile(targetFilePath: string, relativeTargetPath: string): Promise<void>;
39
+ /**
40
+ * Prepend content from a feature file to the beginning of a target file
41
+ *
42
+ * @param featureFilePath - Full path to the feature file with content to prepend
43
+ * @param targetFilePath - Full path to the target file to prepend to
44
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/styles/global.css")
45
+ */
46
+ export declare function prependToFile(featureFilePath: string, targetFilePath: string, relativeTargetPath: string): Promise<void>;
47
+ /**
48
+ * Append content from a feature file to the end of a target file
49
+ *
50
+ * @param featureFilePath - Full path to the feature file with content to append
51
+ * @param targetFilePath - Full path to the target file to append to
52
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/styles/global.css")
53
+ */
54
+ export declare function appendToFile(featureFilePath: string, targetFilePath: string, relativeTargetPath: string): Promise<void>;
55
+ //# sourceMappingURL=file-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-operations.d.ts","sourceRoot":"","sources":["../../src/core/file-operations.ts"],"names":[],"mappings":"AAqBA,qBAAa,kBAAmB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI3B;AAgGD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAmC7F;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACxC,YAAY,EAAE,MAAM,EACpB,qBAAqB,EAAE,MAAM,EAC7B,OAAO,EAAE,MAAM,GACb,IAAI,CAyCN;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC9B,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,MAAM,EAC1B,WAAW,UAAQ,EACnB,OAAO,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAiGf;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC/B,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAClC,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CACjC,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { readFileSync, readdirSync, existsSync, mkdirSync, writeFileSync, rmSync, statSync, renameSync, } from "fs";
7
+ import { dirname, extname, basename, join } from "path";
8
+ import * as logger from "../utils/logger.js";
9
+ import { mergeRoutes } from "../utils/route-merger.js";
10
+ const _INHERIT_PREFIX = "__inherit__";
11
+ export class FileOperationError extends Error {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "FileOperationError";
15
+ }
16
+ }
17
+ /**
18
+ * Fix import paths by removing __inherit__ prefix from import/require statements
19
+ *
20
+ * Examples:
21
+ * - import { x } from './__inherit__routes' -> import { x } from './routes'
22
+ * - import x from '../__inherit__routes.tsx' -> import x from '../routes.tsx'
23
+ * - require('./__inherit__file') -> require('./file')
24
+ *
25
+ * @param content - File content to process
26
+ * @returns Content with fixed import paths
27
+ */
28
+ function fixInheritImportPaths(content) {
29
+ // Match import/export statements with __inherit__ in the path
30
+ // Handles: import ... from '...__inherit__...'
31
+ // export ... from '...__inherit__...'
32
+ // import('...__inherit__...')
33
+ // require('...__inherit__...')
34
+ // Pattern explanation:
35
+ // (from\s+|import\(|require\() - matches 'from ', 'import(', or 'require('
36
+ // (['"`]) - captures opening quote
37
+ // ([^'"`]*) - captures path before __inherit__
38
+ // __inherit__ - the prefix to remove
39
+ // ([^'"`]*) - captures rest of path
40
+ // \2 - matches same quote type as opening
41
+ return content.replace(/(from\s+|import\(|require\()(['"`])([^'"`]*)__inherit__([^'"`]*)\2/g, (match, prefix, quote, before, after) => {
42
+ return `${prefix}${quote}${before}${after}${quote}`;
43
+ });
44
+ }
45
+ /**
46
+ * Check if file is a JS/TS file that may contain imports
47
+ */
48
+ function isJavaScriptFile(filePath) {
49
+ const ext = extname(filePath);
50
+ return [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"].includes(ext);
51
+ }
52
+ /**
53
+ * Check if file is a webApplication meta.xml file that needs template processing.
54
+ * Accepts both _webapplication.webapplication-meta.xml and _webapplication.webApplication-meta.xml (case variation).
55
+ */
56
+ function isWebApplicationMetaFile(filePath) {
57
+ const fileName = basename(filePath);
58
+ return fileName.toLowerCase() === "_webapplication.webapplication-meta.xml";
59
+ }
60
+ /**
61
+ * Check if file is a site-container metadata file that needs template parameter replacement
62
+ * (digitalExperienceConfigs, digitalExperiences, networks, sites under force-app/main/default)
63
+ */
64
+ function isSiteContainerMetaFile(filePath) {
65
+ const normalized = filePath.replace(/\\/g, "/");
66
+ return (normalized.includes("/digitalExperienceConfigs/") ||
67
+ normalized.includes("/digitalExperiences/") ||
68
+ normalized.includes("/networks/") ||
69
+ normalized.includes("/sites/"));
70
+ }
71
+ /**
72
+ * Replace site-container template parameters with values derived from app name.
73
+ * Uses <%= appName %>, <%= urlPathPrefixVForceSite %>, <%= appSpace %>,
74
+ * <%= siteName %>, <%= siteName1 %>, <%= siteNameLower %> (siteName = appName, siteName1 = appName + "1", siteNameLower = appName.toLowerCase()).
75
+ */
76
+ function replaceSiteContainerParams(content, appName) {
77
+ const urlPathPrefixVForceSite = `${appName}vforcesite`;
78
+ const appSpace = `c/${appName}`;
79
+ const siteName = appName;
80
+ const siteName1 = `${appName}1`;
81
+ const siteNameLower = appName.toLowerCase();
82
+ return content
83
+ .replace(/<%= appName %>/g, appName)
84
+ .replace(/<%= urlPathPrefixVForceSite %>/g, urlPathPrefixVForceSite)
85
+ .replace(/<%= appSpace %>/g, appSpace)
86
+ .replace(/<%= siteName %>/g, siteName)
87
+ .replace(/<%= siteName1 %>/g, siteName1)
88
+ .replace(/<%= siteNameLower %>/g, siteNameLower);
89
+ }
90
+ /** Translate placeholder path segments to actual site name values (handles dir names and filenames like __siteName1__.digitalExperienceConfig). */
91
+ function translateSiteContainerPathSegment(segment, siteName, siteName1) {
92
+ return segment.replace(/__siteName1__/g, siteName1).replace(/__siteName__/g, siteName);
93
+ }
94
+ /**
95
+ * Process webApplication meta.xml file: replace template parameters and rename
96
+ * @param targetFilePath - Full path to the target file
97
+ * @param appName - Application name to use for masterLabel and filename
98
+ * @returns New file path if file was renamed, or original path
99
+ */
100
+ export function processWebApplicationMetaFile(targetFilePath, appName) {
101
+ if (!isWebApplicationMetaFile(targetFilePath)) {
102
+ return targetFilePath;
103
+ }
104
+ // Read the file content
105
+ let content = readFileSync(targetFilePath, "utf-8");
106
+ // Replace template parameters
107
+ content = content.replace(/<%= masterLabel %>/g, appName);
108
+ // Write the updated content
109
+ writeFileSync(targetFilePath, content, "utf-8");
110
+ // Rename the file from _webapplication.*-meta.xml to <appName>.webapplication-meta.xml
111
+ const targetDir = dirname(targetFilePath);
112
+ const newFileName = `${appName}.webapplication-meta.xml`;
113
+ const newFilePath = join(targetDir, newFileName);
114
+ // If the new file already exists, update it with the new content
115
+ if (existsSync(newFilePath)) {
116
+ const existingContent = readFileSync(newFilePath, "utf-8");
117
+ if (existingContent !== content) {
118
+ // Content is different, update it
119
+ writeFileSync(newFilePath, content, "utf-8");
120
+ }
121
+ // Delete the old file regardless
122
+ rmSync(targetFilePath, { force: true });
123
+ return newFilePath;
124
+ }
125
+ // Rename the file
126
+ renameSync(targetFilePath, newFilePath);
127
+ logger.info(`Renamed ${basename(targetFilePath)} to ${newFileName}`);
128
+ return newFilePath;
129
+ }
130
+ /**
131
+ * Copy site-container template into target force-app/main/default, replacing
132
+ * template params (appName, siteName, siteName1, siteNameLower, etc.) and path
133
+ * placeholders (__siteName__, __siteName1__) in directory and file names.
134
+ *
135
+ * @param templateRoot - Path to template-site-container/force-app/main/default
136
+ * @param targetForceAppDefault - Path to target's force-app/main/default
137
+ * @param appName - Application name (used as site name base)
138
+ */
139
+ export function copySiteContainerTemplate(templateRoot, targetForceAppDefault, appName) {
140
+ if (!existsSync(templateRoot)) {
141
+ return;
142
+ }
143
+ const siteName = appName;
144
+ const siteName1 = `${appName}1`;
145
+ function translateRelativePath(relativePath) {
146
+ return relativePath
147
+ .split("/")
148
+ .map((seg) => translateSiteContainerPathSegment(seg, siteName, siteName1))
149
+ .join("/");
150
+ }
151
+ function walk(dir, base = "") {
152
+ const entries = readdirSync(dir, { withFileTypes: true });
153
+ for (const entry of entries) {
154
+ const relativePath = base ? `${base}/${entry.name}` : entry.name;
155
+ const targetRelativePath = translateRelativePath(relativePath);
156
+ const srcPath = join(dir, entry.name);
157
+ const destPath = join(targetForceAppDefault, targetRelativePath);
158
+ if (entry.isDirectory()) {
159
+ if (!existsSync(destPath)) {
160
+ mkdirSync(destPath, { recursive: true });
161
+ }
162
+ walk(srcPath, relativePath);
163
+ }
164
+ else {
165
+ let content = readFileSync(srcPath, "utf-8");
166
+ content = replaceSiteContainerParams(content, appName);
167
+ if (!existsSync(dirname(destPath))) {
168
+ mkdirSync(dirname(destPath), { recursive: true });
169
+ }
170
+ writeFileSync(destPath, content, "utf-8");
171
+ logger.info(`Site container: ${targetRelativePath}`);
172
+ }
173
+ }
174
+ }
175
+ walk(templateRoot);
176
+ }
177
+ /**
178
+ * Apply a file from patch to target, optionally merging with base
179
+ *
180
+ * @param patchFilePath - Full path to the patch file from the feature
181
+ * @param baseFilePath - Full path to the original base app file (used for merging)
182
+ * @param targetFilePath - Full path to where the result should be written
183
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/routes.tsx")
184
+ * @param shouldMerge - If true, merges patch with base using route merge strategy
185
+ * @param appName - Application name for template processing (optional)
186
+ */
187
+ export async function applyFile(patchFilePath, baseFilePath, targetFilePath, relativeTargetPath, shouldMerge = false, appName) {
188
+ if (!existsSync(patchFilePath)) {
189
+ throw new FileOperationError(`Patch file not found: ${patchFilePath}`);
190
+ }
191
+ // Read the patch content
192
+ let patchContent = readFileSync(patchFilePath, "utf-8");
193
+ // Fix __inherit__ import paths for JS/TS files
194
+ if (isJavaScriptFile(patchFilePath)) {
195
+ patchContent = fixInheritImportPaths(patchContent);
196
+ }
197
+ // Replace site-container template params before merge/write so comparisons use final content
198
+ if (appName && isSiteContainerMetaFile(targetFilePath)) {
199
+ patchContent = replaceSiteContainerParams(patchContent, appName);
200
+ }
201
+ if (shouldMerge) {
202
+ // Merge strategy - merge patch with base, write to target
203
+ if (!existsSync(baseFilePath)) {
204
+ throw new FileOperationError(`Base file not found: ${baseFilePath}. Merge requires base file to exist.`);
205
+ }
206
+ // Merge patch with base (note: mergeRoutes reads files internally, so we write fixed content to temp)
207
+ let mergedContent = mergeRoutes(patchFilePath, baseFilePath);
208
+ // Fix imports in merged content
209
+ if (isJavaScriptFile(targetFilePath)) {
210
+ mergedContent = fixInheritImportPaths(mergedContent);
211
+ }
212
+ // Replace site-container template params in merged output when applicable
213
+ if (appName && isSiteContainerMetaFile(targetFilePath)) {
214
+ mergedContent = replaceSiteContainerParams(mergedContent, appName);
215
+ }
216
+ // Check if target already has this content
217
+ if (existsSync(targetFilePath)) {
218
+ const existingContent = readFileSync(targetFilePath, "utf-8");
219
+ if (existingContent === mergedContent) {
220
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged after merge)`);
221
+ return;
222
+ }
223
+ }
224
+ // Ensure target directory exists
225
+ const targetDirPath = dirname(targetFilePath);
226
+ if (!existsSync(targetDirPath)) {
227
+ mkdirSync(targetDirPath, { recursive: true });
228
+ }
229
+ writeFileSync(targetFilePath, mergedContent, "utf-8");
230
+ logger.success(`Merged ${relativeTargetPath}`);
231
+ }
232
+ else {
233
+ // Add/Update strategy - copy patch to target
234
+ const targetExists = existsSync(targetFilePath);
235
+ if (targetExists) {
236
+ const existingContent = readFileSync(targetFilePath, "utf-8");
237
+ if (existingContent === patchContent) {
238
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged)`);
239
+ return;
240
+ }
241
+ }
242
+ // Ensure target directory exists
243
+ const targetDirPath = dirname(targetFilePath);
244
+ if (!existsSync(targetDirPath)) {
245
+ mkdirSync(targetDirPath, { recursive: true });
246
+ }
247
+ // Write the file
248
+ writeFileSync(targetFilePath, patchContent, "utf-8");
249
+ // Process webApplication meta.xml file if needed
250
+ if (appName && isWebApplicationMetaFile(targetFilePath)) {
251
+ const newFilePath = processWebApplicationMetaFile(targetFilePath, appName);
252
+ // Update relativeTargetPath for logging if file was renamed
253
+ if (newFilePath !== targetFilePath) {
254
+ const newRelativePath = relativeTargetPath.replace(/_webapplication\.webapplication-meta\.xml$/i, `${appName}.webapplication-meta.xml`);
255
+ logger.success(`Added ${newRelativePath}`);
256
+ return;
257
+ }
258
+ }
259
+ if (targetExists) {
260
+ logger.success(`Updated ${relativeTargetPath}`);
261
+ }
262
+ else {
263
+ logger.success(`Added ${relativeTargetPath}`);
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * Delete a file or directory from the target app
269
+ *
270
+ * @param targetFilePath - Full path to the file/directory to delete
271
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/routes.tsx")
272
+ */
273
+ export async function deleteFile(targetFilePath, relativeTargetPath) {
274
+ if (!existsSync(targetFilePath)) {
275
+ logger.info(`Skipped deleting ${relativeTargetPath} (does not exist)`);
276
+ return;
277
+ }
278
+ const stat = statSync(targetFilePath);
279
+ if (stat.isDirectory()) {
280
+ rmSync(targetFilePath, { recursive: true, force: true });
281
+ logger.success(`Deleted directory ${relativeTargetPath}`);
282
+ }
283
+ else {
284
+ rmSync(targetFilePath, { force: true });
285
+ logger.success(`Deleted ${relativeTargetPath}`);
286
+ }
287
+ }
288
+ /**
289
+ * Prepend content from a feature file to the beginning of a target file
290
+ *
291
+ * @param featureFilePath - Full path to the feature file with content to prepend
292
+ * @param targetFilePath - Full path to the target file to prepend to
293
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/styles/global.css")
294
+ */
295
+ export async function prependToFile(featureFilePath, targetFilePath, relativeTargetPath) {
296
+ if (!existsSync(featureFilePath)) {
297
+ throw new FileOperationError(`Feature file not found: ${featureFilePath}`);
298
+ }
299
+ if (!existsSync(targetFilePath)) {
300
+ throw new FileOperationError(`Target file not found: ${targetFilePath}`);
301
+ }
302
+ // Read both files
303
+ let featureContent = readFileSync(featureFilePath, "utf-8");
304
+ const targetContent = readFileSync(targetFilePath, "utf-8");
305
+ // Fix __inherit__ imports in feature content if it's a JS/TS file
306
+ if (isJavaScriptFile(featureFilePath)) {
307
+ featureContent = fixInheritImportPaths(featureContent);
308
+ }
309
+ // Prepend feature content to target content
310
+ const newContent = featureContent + "\n" + targetContent;
311
+ // Check if content would actually change
312
+ if (targetContent === newContent) {
313
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged after prepend)`);
314
+ return;
315
+ }
316
+ writeFileSync(targetFilePath, newContent, "utf-8");
317
+ logger.success(`Prepended to ${relativeTargetPath}`);
318
+ }
319
+ /**
320
+ * Append content from a feature file to the end of a target file
321
+ *
322
+ * @param featureFilePath - Full path to the feature file with content to append
323
+ * @param targetFilePath - Full path to the target file to append to
324
+ * @param relativeTargetPath - Relative path for logging (e.g. "src/styles/global.css")
325
+ */
326
+ export async function appendToFile(featureFilePath, targetFilePath, relativeTargetPath) {
327
+ if (!existsSync(featureFilePath)) {
328
+ throw new FileOperationError(`Feature file not found: ${featureFilePath}`);
329
+ }
330
+ if (!existsSync(targetFilePath)) {
331
+ throw new FileOperationError(`Target file not found: ${targetFilePath}`);
332
+ }
333
+ // Read both files
334
+ const targetContent = readFileSync(targetFilePath, "utf-8");
335
+ let featureContent = readFileSync(featureFilePath, "utf-8");
336
+ // Fix __inherit__ imports in feature content if it's a JS/TS file
337
+ if (isJavaScriptFile(featureFilePath)) {
338
+ featureContent = fixInheritImportPaths(featureContent);
339
+ }
340
+ // Append feature content to target content
341
+ const newContent = targetContent + "\n" + featureContent;
342
+ // Check if content would actually change
343
+ if (targetContent === newContent) {
344
+ logger.info(`Skipped ${relativeTargetPath} (content unchanged after append)`);
345
+ return;
346
+ }
347
+ writeFileSync(targetFilePath, newContent, "utf-8");
348
+ logger.success(`Appended to ${relativeTargetPath}`);
349
+ }
350
+ //# sourceMappingURL=file-operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-operations.js","sourceRoot":"","sources":["../../src/core/file-operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { PackageJsonDependencies } from "../types.js";
2
+ export declare class PackageJsonMergeError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Build package specs array from dependencies object
7
+ * @param dependencies - Object mapping package names to versions
8
+ * @returns Array of package specs in format "package@version"
9
+ */
10
+ export declare function buildPackageSpecs(dependencies: Record<string, string>): string[];
11
+ /**
12
+ * Build npm install command for package specs
13
+ * @param packageSpecs - Array of package specs
14
+ * @param isDev - Whether these are dev dependencies
15
+ * @returns npm install command string
16
+ */
17
+ export declare function buildInstallCommand(packageSpecs: string[], isDev: boolean): string;
18
+ /**
19
+ * Execute npm install command (extracted for testability)
20
+ * @param command - npm install command to execute
21
+ * @param cwd - Working directory
22
+ */
23
+ export declare function executeNpmInstall(command: string, cwd: string): void;
24
+ /**
25
+ * Install dependencies using npm
26
+ * @param targetDir - Base directory containing webapplications/<app-name>, or direct path to web app directory if webAppDirPath is provided
27
+ * @param patchDependencies - Dependencies to install from feature patches
28
+ * @param webAppDirPath - Optional direct path to the web application directory
29
+ */
30
+ export declare function mergePackageJson(targetDir: string, patchDependencies: PackageJsonDependencies, webAppDirPath?: string): Promise<string[]>;
31
+ //# sourceMappingURL=package-json-merger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-json-merger.d.ts","sourceRoot":"","sources":["../../src/core/package-json-merger.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAI3D,qBAAa,qBAAsB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAOhF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAIlF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CASpE;AAmCD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,uBAAuB,EAC1C,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAwEnB"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { execSync } from "child_process";
7
+ import { existsSync, readFileSync, writeFileSync } from "fs";
8
+ import { join } from "path";
9
+ import * as logger from "../utils/logger.js";
10
+ import { getWebApplicationPath } from "../utils/validation.js";
11
+ export class PackageJsonMergeError extends Error {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "PackageJsonMergeError";
15
+ }
16
+ }
17
+ /**
18
+ * Build package specs array from dependencies object
19
+ * @param dependencies - Object mapping package names to versions
20
+ * @returns Array of package specs in format "package@version"
21
+ */
22
+ export function buildPackageSpecs(dependencies) {
23
+ return Object.entries(dependencies)
24
+ .filter(([, version]) => {
25
+ // Filter out wildcard versions and workspace protocol (npm doesn't support workspace:)
26
+ return version !== "*" && !version.startsWith("workspace:");
27
+ })
28
+ .map(([name, version]) => `${name}@${version}`);
29
+ }
30
+ /**
31
+ * Build npm install command for package specs
32
+ * @param packageSpecs - Array of package specs
33
+ * @param isDev - Whether these are dev dependencies
34
+ * @returns npm install command string
35
+ */
36
+ export function buildInstallCommand(packageSpecs, isDev) {
37
+ const devFlag = isDev ? "--save-dev" : "--save";
38
+ // Use --no-workspaces to avoid workspace protocol issues when installing in dist directories
39
+ return `npm install ${devFlag} ${packageSpecs.join(" ")} --prefer-dedupe --no-workspaces`;
40
+ }
41
+ /**
42
+ * Execute npm install command (extracted for testability)
43
+ * @param command - npm install command to execute
44
+ * @param cwd - Working directory
45
+ */
46
+ export function executeNpmInstall(command, cwd) {
47
+ execSync(command, {
48
+ cwd,
49
+ stdio: "inherit",
50
+ env: {
51
+ ...process.env,
52
+ ESBUILD_BINARY_PATH: "", // Force esbuild to use the version from package-lock.json
53
+ },
54
+ });
55
+ }
56
+ /**
57
+ * Replace workspace:* dependencies with * to avoid npm workspace protocol errors
58
+ * npm doesn't support workspace: protocol, so we replace it with * which we filter out
59
+ */
60
+ function replaceWorkspaceDependencies(packageJsonPath) {
61
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
62
+ let modified = false;
63
+ // Replace workspace:* in dependencies
64
+ if (packageJson.dependencies) {
65
+ for (const [key, value] of Object.entries(packageJson.dependencies)) {
66
+ if (typeof value === "string" && value.startsWith("workspace:")) {
67
+ packageJson.dependencies[key] = "*";
68
+ modified = true;
69
+ }
70
+ }
71
+ }
72
+ // Replace workspace:* in devDependencies
73
+ if (packageJson.devDependencies) {
74
+ for (const [key, value] of Object.entries(packageJson.devDependencies)) {
75
+ if (typeof value === "string" && value.startsWith("workspace:")) {
76
+ packageJson.devDependencies[key] = "*";
77
+ modified = true;
78
+ }
79
+ }
80
+ }
81
+ if (modified) {
82
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
83
+ }
84
+ }
85
+ /**
86
+ * Install dependencies using npm
87
+ * @param targetDir - Base directory containing webapplications/<app-name>, or direct path to web app directory if webAppDirPath is provided
88
+ * @param patchDependencies - Dependencies to install from feature patches
89
+ * @param webAppDirPath - Optional direct path to the web application directory
90
+ */
91
+ export async function mergePackageJson(targetDir, patchDependencies, webAppDirPath) {
92
+ // Get the web application directory where package.json is located
93
+ const webAppDir = webAppDirPath || getWebApplicationPath(targetDir);
94
+ const packageJsonPath = join(webAppDir, "package.json");
95
+ if (!existsSync(packageJsonPath)) {
96
+ throw new PackageJsonMergeError(`package.json not found at '${packageJsonPath}'. Expected in web application directory.`);
97
+ }
98
+ // Replace workspace:* dependencies before installing to avoid npm errors
99
+ replaceWorkspaceDependencies(packageJsonPath);
100
+ try {
101
+ const changes = [];
102
+ // Install dependencies
103
+ if (patchDependencies.dependencies) {
104
+ const packageSpecs = buildPackageSpecs(patchDependencies.dependencies);
105
+ if (packageSpecs.length > 0) {
106
+ logger.info(`Installing ${packageSpecs.length} dependency/dependencies...`);
107
+ packageSpecs.forEach((spec) => logger.info(` ${spec}`));
108
+ try {
109
+ const command = buildInstallCommand(packageSpecs, false);
110
+ executeNpmInstall(command, webAppDir);
111
+ changes.push(...packageSpecs);
112
+ }
113
+ catch (err) {
114
+ throw new PackageJsonMergeError(`Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`);
115
+ }
116
+ }
117
+ }
118
+ // Install devDependencies
119
+ if (patchDependencies.devDependencies) {
120
+ const packageSpecs = buildPackageSpecs(patchDependencies.devDependencies);
121
+ if (packageSpecs.length > 0) {
122
+ logger.info(`Installing ${packageSpecs.length} dev dependency/dependencies...`);
123
+ packageSpecs.forEach((spec) => logger.info(` ${spec}`));
124
+ try {
125
+ const command = buildInstallCommand(packageSpecs, true);
126
+ executeNpmInstall(command, webAppDir);
127
+ changes.push(...packageSpecs.map((spec) => `${spec} (dev)`));
128
+ }
129
+ catch (err) {
130
+ throw new PackageJsonMergeError(`Failed to install dev dependencies: ${err instanceof Error ? err.message : String(err)}`);
131
+ }
132
+ }
133
+ }
134
+ if (changes.length > 0) {
135
+ logger.success(`Installed ${changes.length} dependency change(s)`);
136
+ }
137
+ else {
138
+ logger.info("No new dependencies to install");
139
+ }
140
+ return changes;
141
+ }
142
+ catch (err) {
143
+ if (err instanceof PackageJsonMergeError) {
144
+ throw err;
145
+ }
146
+ throw new PackageJsonMergeError(`Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`);
147
+ }
148
+ }
149
+ //# sourceMappingURL=package-json-merger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-json-merger.js","sourceRoot":"","sources":["../../src/core/package-json-merger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Feature, PathMappings } from "../types.js";
2
+ export declare class FeatureLoadError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export interface FeatureConfig {
6
+ features: Feature[];
7
+ templateDir: string;
8
+ webAppName: string;
9
+ routeFilePath: string;
10
+ dependencies: string[];
11
+ pathMappings: PathMappings;
12
+ siteContainer: boolean;
13
+ }
14
+ /**
15
+ * Load features from a feature's feature.ts file
16
+ */
17
+ export declare function loadFeature(featurePath: string): Promise<FeatureConfig>;
18
+ //# sourceMappingURL=patch-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-loader.d.ts","sourceRoot":"","sources":["../../src/core/patch-loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzD,qBAAa,gBAAiB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI3B;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;CACvB;AAcD;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmG7E"}