@openrewrite/rewrite 8.68.0-20251202-082117 → 8.68.0-20251202-154952

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 (45) hide show
  1. package/dist/javascript/assertions.d.ts +1 -0
  2. package/dist/javascript/assertions.d.ts.map +1 -1
  3. package/dist/javascript/assertions.js +82 -11
  4. package/dist/javascript/assertions.js.map +1 -1
  5. package/dist/javascript/dependency-workspace.d.ts +46 -5
  6. package/dist/javascript/dependency-workspace.d.ts.map +1 -1
  7. package/dist/javascript/dependency-workspace.js +70 -35
  8. package/dist/javascript/dependency-workspace.js.map +1 -1
  9. package/dist/javascript/index.d.ts +2 -0
  10. package/dist/javascript/index.d.ts.map +1 -1
  11. package/dist/javascript/index.js +2 -0
  12. package/dist/javascript/index.js.map +1 -1
  13. package/dist/javascript/node-resolution-result.d.ts +204 -0
  14. package/dist/javascript/node-resolution-result.d.ts.map +1 -0
  15. package/dist/javascript/node-resolution-result.js +723 -0
  16. package/dist/javascript/node-resolution-result.js.map +1 -0
  17. package/dist/javascript/package-json-parser.d.ts +143 -0
  18. package/dist/javascript/package-json-parser.d.ts.map +1 -0
  19. package/dist/javascript/package-json-parser.js +773 -0
  20. package/dist/javascript/package-json-parser.js.map +1 -0
  21. package/dist/javascript/templating/engine.js +1 -1
  22. package/dist/javascript/templating/engine.js.map +1 -1
  23. package/dist/json/parser.js +10 -1
  24. package/dist/json/parser.js.map +1 -1
  25. package/dist/json/tree.d.ts +1 -1
  26. package/dist/json/tree.js +1 -1
  27. package/dist/json/tree.js.map +1 -1
  28. package/dist/parser.d.ts +1 -1
  29. package/dist/parser.d.ts.map +1 -1
  30. package/dist/rpc/request/parse.d.ts +4 -0
  31. package/dist/rpc/request/parse.d.ts.map +1 -1
  32. package/dist/rpc/request/parse.js +17 -1
  33. package/dist/rpc/request/parse.js.map +1 -1
  34. package/dist/version.txt +1 -1
  35. package/package.json +5 -2
  36. package/src/javascript/assertions.ts +73 -15
  37. package/src/javascript/dependency-workspace.ts +124 -46
  38. package/src/javascript/index.ts +2 -0
  39. package/src/javascript/node-resolution-result.ts +905 -0
  40. package/src/javascript/package-json-parser.ts +845 -0
  41. package/src/javascript/templating/engine.ts +1 -1
  42. package/src/json/parser.ts +18 -1
  43. package/src/json/tree.ts +1 -1
  44. package/src/parser.ts +1 -1
  45. package/src/rpc/request/parse.ts +20 -2
@@ -19,6 +19,44 @@ import * as os from 'os';
19
19
  import * as crypto from 'crypto';
20
20
  import {execSync} from 'child_process';
21
21
 
22
+ interface BaseWorkspaceOptions {
23
+ /**
24
+ * Optional target directory. If provided, creates workspace in this directory
25
+ * instead of a hash-based temp directory. Caller is responsible for directory lifecycle.
26
+ */
27
+ targetDir?: string;
28
+ }
29
+
30
+ interface DependenciesWorkspaceOptions extends BaseWorkspaceOptions {
31
+ /**
32
+ * NPM dependencies (package name to version mapping).
33
+ */
34
+ dependencies: Record<string, string>;
35
+ packageJsonContent?: never;
36
+ packageLockContent?: never;
37
+ }
38
+
39
+ interface PackageJsonWorkspaceOptions extends BaseWorkspaceOptions {
40
+ /**
41
+ * package.json content as a string. Dependencies are extracted from it
42
+ * and the content is written to the workspace.
43
+ */
44
+ packageJsonContent: string;
45
+ dependencies?: never;
46
+ /**
47
+ * Optional package-lock.json content. If provided:
48
+ * - The lock file content is used as the cache key (more precise than dependency hash)
49
+ * - `npm ci` is used instead of `npm install` (faster, deterministic)
50
+ */
51
+ packageLockContent?: string;
52
+ }
53
+
54
+ /**
55
+ * Options for creating a dependency workspace.
56
+ * Provide either `dependencies` or `packageJsonContent`, but not both.
57
+ */
58
+ export type WorkspaceOptions = DependenciesWorkspaceOptions | PackageJsonWorkspaceOptions;
59
+
22
60
  /**
23
61
  * Manages workspace directories for TypeScript compilation with dependencies.
24
62
  * Creates temporary workspaces with package.json and installed node_modules
@@ -30,14 +68,74 @@ export class DependencyWorkspace {
30
68
 
31
69
  /**
32
70
  * Gets or creates a workspace directory for the given dependencies.
33
- * Workspaces are cached by dependency hash to avoid repeated npm installs.
71
+ * Workspaces are cached by dependency hash (or lock file hash if provided) to avoid repeated npm installs.
34
72
  *
35
- * @param dependencies NPM dependencies (package name to version mapping)
36
- * @param targetDir Optional target directory. If provided, creates workspace in this directory
37
- * instead of a hash-based temp directory. Caller is responsible for directory lifecycle.
73
+ * @param options Workspace options including dependencies or package.json content
38
74
  * @returns Path to the workspace directory
39
75
  */
40
- static async getOrCreateWorkspace(dependencies: Record<string, string>, targetDir?: string): Promise<string> {
76
+ static async getOrCreateWorkspace(options: WorkspaceOptions): Promise<string> {
77
+ // Extract dependencies from package.json content if provided
78
+ let dependencies: Record<string, string> | undefined = options.dependencies;
79
+ let parsedPackageJson: Record<string, any> | undefined;
80
+ if (options.packageJsonContent) {
81
+ parsedPackageJson = JSON.parse(options.packageJsonContent);
82
+ dependencies = {
83
+ ...parsedPackageJson?.dependencies,
84
+ ...parsedPackageJson?.devDependencies
85
+ };
86
+ }
87
+
88
+ if (!dependencies || Object.keys(dependencies).length === 0) {
89
+ throw new Error('No dependencies provided');
90
+ }
91
+
92
+ // Use the refactored internal method
93
+ return this.createWorkspace(dependencies, parsedPackageJson, options.packageJsonContent, options.packageLockContent, options.targetDir);
94
+ }
95
+
96
+ /**
97
+ * Internal method that handles workspace creation.
98
+ */
99
+ private static async createWorkspace(
100
+ dependencies: Record<string, string>,
101
+ parsedPackageJson: Record<string, any> | undefined,
102
+ packageJsonContent: string | undefined,
103
+ packageLockContent: string | undefined,
104
+ targetDir: string | undefined
105
+ ): Promise<string> {
106
+ // Determine hash based on lock file (most precise) or dependencies
107
+ // Note: We always hash dependencies (not packageJsonContent) because whitespace/formatting
108
+ // differences in package.json shouldn't create different workspaces
109
+ const hash = packageLockContent
110
+ ? this.hashContent(packageLockContent)
111
+ : this.hashDependencies(dependencies);
112
+
113
+ // Determine npm command: use `npm ci` when lock file is provided (faster, deterministic)
114
+ const npmCommand = packageLockContent ? 'npm ci --silent' : 'npm install --silent';
115
+
116
+ // Helper to write package files to a directory
117
+ const writePackageFiles = (dir: string) => {
118
+ // Write package.json (use provided content or generate from parsed/dependencies)
119
+ if (packageJsonContent) {
120
+ fs.writeFileSync(path.join(dir, 'package.json'), packageJsonContent);
121
+ } else if (parsedPackageJson) {
122
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(parsedPackageJson, null, 2));
123
+ } else {
124
+ const packageJson = {
125
+ name: "openrewrite-template-workspace",
126
+ version: "1.0.0",
127
+ private: true,
128
+ dependencies: dependencies
129
+ };
130
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(packageJson, null, 2));
131
+ }
132
+
133
+ // Write package-lock.json if provided
134
+ if (packageLockContent) {
135
+ fs.writeFileSync(path.join(dir, 'package-lock.json'), packageLockContent);
136
+ }
137
+ };
138
+
41
139
  if (targetDir) {
42
140
  // Use provided directory - check if it's already valid
43
141
  if (this.isWorkspaceValid(targetDir, dependencies)) {
@@ -48,7 +146,6 @@ export class DependencyWorkspace {
48
146
  fs.mkdirSync(targetDir, {recursive: true});
49
147
 
50
148
  // Check if we can reuse a cached workspace by symlinking node_modules
51
- const hash = this.hashDependencies(dependencies);
52
149
  const cachedWorkspaceDir = path.join(this.WORKSPACE_BASE, hash);
53
150
  const cachedNodeModules = path.join(cachedWorkspaceDir, 'node_modules');
54
151
 
@@ -65,17 +162,8 @@ export class DependencyWorkspace {
65
162
  // Create symlink to cached node_modules
66
163
  fs.symlinkSync(cachedNodeModules, targetNodeModules, 'dir');
67
164
 
68
- // Write package.json
69
- const packageJson = {
70
- name: "openrewrite-template-workspace",
71
- version: "1.0.0",
72
- private: true,
73
- dependencies: dependencies
74
- };
75
- fs.writeFileSync(
76
- path.join(targetDir, 'package.json'),
77
- JSON.stringify(packageJson, null, 2)
78
- );
165
+ // Write package files
166
+ writePackageFiles(targetDir);
79
167
 
80
168
  return targetDir;
81
169
  } catch (symlinkError) {
@@ -84,20 +172,10 @@ export class DependencyWorkspace {
84
172
  }
85
173
 
86
174
  try {
87
- const packageJson = {
88
- name: "openrewrite-template-workspace",
89
- version: "1.0.0",
90
- private: true,
91
- dependencies: dependencies
92
- };
93
-
94
- fs.writeFileSync(
95
- path.join(targetDir, 'package.json'),
96
- JSON.stringify(packageJson, null, 2)
97
- );
175
+ writePackageFiles(targetDir);
98
176
 
99
- // Run npm install
100
- execSync('npm install --silent', {
177
+ // Run npm install or npm ci
178
+ execSync(npmCommand, {
101
179
  cwd: targetDir,
102
180
  stdio: 'pipe' // Suppress output
103
181
  });
@@ -109,7 +187,6 @@ export class DependencyWorkspace {
109
187
  }
110
188
 
111
189
  // Use hash-based cached workspace
112
- const hash = this.hashDependencies(dependencies);
113
190
 
114
191
  // Check cache
115
192
  const cached = this.cache.get(hash);
@@ -141,21 +218,11 @@ export class DependencyWorkspace {
141
218
  // Create temporary workspace directory
142
219
  fs.mkdirSync(tempWorkspaceDir, {recursive: true});
143
220
 
144
- // Create package.json
145
- const packageJson = {
146
- name: "openrewrite-template-workspace",
147
- version: "1.0.0",
148
- private: true,
149
- dependencies: dependencies
150
- };
151
-
152
- fs.writeFileSync(
153
- path.join(tempWorkspaceDir, 'package.json'),
154
- JSON.stringify(packageJson, null, 2)
155
- );
221
+ // Write package files
222
+ writePackageFiles(tempWorkspaceDir);
156
223
 
157
- // Run npm install
158
- execSync('npm install --silent', {
224
+ // Run npm install or npm ci
225
+ execSync(npmCommand, {
159
226
  cwd: tempWorkspaceDir,
160
227
  stdio: 'pipe' // Suppress output
161
228
  });
@@ -245,6 +312,13 @@ export class DependencyWorkspace {
245
312
  // Sort keys for consistent hashing
246
313
  const sorted = Object.keys(dependencies).sort();
247
314
  const content = sorted.map(key => `${key}:${dependencies[key]}`).join(',');
315
+ return this.hashContent(content);
316
+ }
317
+
318
+ /**
319
+ * Generates a hash from arbitrary content for caching.
320
+ */
321
+ private static hashContent(content: string): string {
248
322
  return crypto.createHash('sha256').update(content).digest('hex').substring(0, 16);
249
323
  }
250
324
 
@@ -282,7 +356,11 @@ export class DependencyWorkspace {
282
356
  if (expectedDependencies) {
283
357
  try {
284
358
  const packageJsonContent = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
285
- const existingDeps = packageJsonContent.dependencies || {};
359
+ // Merge dependencies and devDependencies (same as getOrCreateWorkspace)
360
+ const existingDeps = {
361
+ ...packageJsonContent.dependencies,
362
+ ...packageJsonContent.devDependencies
363
+ };
286
364
 
287
365
  // Check if all expected dependencies match
288
366
  const expectedKeys = Object.keys(expectedDependencies).sort();
@@ -19,6 +19,8 @@ export * from "./assertions";
19
19
  export * from "./parser";
20
20
  export * from "./style";
21
21
  export * from "./markers";
22
+ export * from "./node-resolution-result";
23
+ export * from "./package-json-parser";
22
24
  export * from "./preconditions";
23
25
  export * from "./templating/index";
24
26
  export * from "./method-matcher";