@openrewrite/rewrite 8.63.3 → 8.63.4
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.
- package/dist/java/rpc.d.ts +2 -2
- package/dist/java/rpc.d.ts.map +1 -1
- package/dist/java/rpc.js +10 -4
- package/dist/java/rpc.js.map +1 -1
- package/dist/java/type.d.ts +1 -1
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +3 -3
- package/dist/java/type.js.map +1 -1
- package/dist/javascript/assertions.d.ts +1 -1
- package/dist/javascript/assertions.d.ts.map +1 -1
- package/dist/javascript/assertions.js +35 -65
- package/dist/javascript/assertions.js.map +1 -1
- package/dist/javascript/comparator.d.ts +2 -2
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/dependency-workspace.d.ts +44 -0
- package/dist/javascript/dependency-workspace.d.ts.map +1 -0
- package/dist/javascript/dependency-workspace.js +335 -0
- package/dist/javascript/dependency-workspace.js.map +1 -0
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +5 -2
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/preconditions.js +2 -2
- package/dist/javascript/preconditions.js.map +1 -1
- package/dist/javascript/templating.d.ts +110 -5
- package/dist/javascript/templating.d.ts.map +1 -1
- package/dist/javascript/templating.js +412 -38
- package/dist/javascript/templating.js.map +1 -1
- package/dist/javascript/type-mapping.js +2 -2
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/rpc/queue.d.ts +1 -0
- package/dist/rpc/queue.d.ts.map +1 -1
- package/dist/rpc/queue.js +11 -1
- package/dist/rpc/queue.js.map +1 -1
- package/dist/rpc/server.d.ts.map +1 -1
- package/dist/rpc/server.js +5 -0
- package/dist/rpc/server.js.map +1 -1
- package/dist/test/rewrite-test.d.ts +1 -1
- package/dist/test/rewrite-test.d.ts.map +1 -1
- package/dist/test/rewrite-test.js +27 -5
- package/dist/test/rewrite-test.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +1 -1
- package/src/java/rpc.ts +4 -4
- package/src/java/type.ts +3 -3
- package/src/javascript/assertions.ts +14 -21
- package/src/javascript/comparator.ts +2 -2
- package/src/javascript/dependency-workspace.ts +317 -0
- package/src/javascript/parser.ts +6 -3
- package/src/javascript/preconditions.ts +2 -2
- package/src/javascript/templating.ts +535 -44
- package/src/javascript/type-mapping.ts +2 -2
- package/src/rpc/queue.ts +11 -1
- package/src/rpc/server.ts +5 -0
- package/src/test/rewrite-test.ts +11 -3
|
@@ -20,33 +20,26 @@ import ts from 'typescript';
|
|
|
20
20
|
import {json, Json} from "../json";
|
|
21
21
|
import * as fs from "fs";
|
|
22
22
|
import * as path from "path";
|
|
23
|
-
import {
|
|
23
|
+
import {DependencyWorkspace} from "./dependency-workspace";
|
|
24
24
|
|
|
25
25
|
const sourceFileCache: Map<string, ts.SourceFile> = new Map();
|
|
26
26
|
|
|
27
|
-
export function* npm(relativeTo: string, ...sourceSpecs: SourceSpec<any>[]):
|
|
27
|
+
export async function* npm(relativeTo: string, ...sourceSpecs: SourceSpec<any>[]): AsyncGenerator<SourceSpec<any>, void, unknown> {
|
|
28
28
|
for (const spec of sourceSpecs) {
|
|
29
29
|
if (spec.path === 'package.json') {
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (needsInstall) {
|
|
44
|
-
fs.writeFileSync(packageJsonPath, spec.before!);
|
|
45
|
-
execSync('npm install', {
|
|
46
|
-
cwd: relativeTo,
|
|
47
|
-
stdio: 'inherit' // Show npm output for debugging
|
|
48
|
-
});
|
|
30
|
+
// Parse package.json to extract dependencies
|
|
31
|
+
const packageJsonContent = JSON.parse(spec.before!);
|
|
32
|
+
const dependencies = {
|
|
33
|
+
...packageJsonContent.dependencies,
|
|
34
|
+
...packageJsonContent.devDependencies
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Use DependencyWorkspace to create workspace in relativeTo directory
|
|
38
|
+
// This will check if it's already valid and skip npm install if so
|
|
39
|
+
if (Object.keys(dependencies).length > 0) {
|
|
40
|
+
await DependencyWorkspace.getOrCreateWorkspace(dependencies, relativeTo);
|
|
49
41
|
}
|
|
42
|
+
|
|
50
43
|
yield spec;
|
|
51
44
|
}
|
|
52
45
|
}
|
|
@@ -27,7 +27,7 @@ export class JavaScriptComparatorVisitor extends JavaScriptVisitor<J> {
|
|
|
27
27
|
/**
|
|
28
28
|
* Flag indicating whether the trees match so far
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
protected match: boolean = true;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Creates a new comparator visitor.
|
|
@@ -63,7 +63,7 @@ export class JavaScriptComparatorVisitor extends JavaScriptVisitor<J> {
|
|
|
63
63
|
/**
|
|
64
64
|
* Aborts the visit operation by setting the match flag to false.
|
|
65
65
|
*/
|
|
66
|
-
|
|
66
|
+
protected abort(): void {
|
|
67
67
|
this.match = false;
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 the original author or authors.
|
|
3
|
+
* <p>
|
|
4
|
+
* Licensed under the Moderne Source Available License (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
* <p>
|
|
8
|
+
* https://docs.moderne.io/licensing/moderne-source-available-license
|
|
9
|
+
* <p>
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from 'fs';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
import * as os from 'os';
|
|
19
|
+
import * as crypto from 'crypto';
|
|
20
|
+
import {execSync} from 'child_process';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Manages workspace directories for TypeScript compilation with dependencies.
|
|
24
|
+
* Creates temporary workspaces with package.json and installed node_modules
|
|
25
|
+
* to enable proper type attribution for templates.
|
|
26
|
+
*/
|
|
27
|
+
export class DependencyWorkspace {
|
|
28
|
+
private static readonly WORKSPACE_BASE = path.join(os.tmpdir(), 'openrewrite-js-workspaces');
|
|
29
|
+
private static readonly cache = new Map<string, string>();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets or creates a workspace directory for the given dependencies.
|
|
33
|
+
* Workspaces are cached by dependency hash to avoid repeated npm installs.
|
|
34
|
+
*
|
|
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.
|
|
38
|
+
* @returns Path to the workspace directory
|
|
39
|
+
*/
|
|
40
|
+
static async getOrCreateWorkspace(dependencies: Record<string, string>, targetDir?: string): Promise<string> {
|
|
41
|
+
if (targetDir) {
|
|
42
|
+
// Use provided directory - check if it's already valid
|
|
43
|
+
if (this.isWorkspaceValid(targetDir, dependencies)) {
|
|
44
|
+
return targetDir;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Create/update workspace in target directory
|
|
48
|
+
fs.mkdirSync(targetDir, {recursive: true});
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const packageJson = {
|
|
52
|
+
name: "openrewrite-template-workspace",
|
|
53
|
+
version: "1.0.0",
|
|
54
|
+
private: true,
|
|
55
|
+
dependencies: dependencies
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
fs.writeFileSync(
|
|
59
|
+
path.join(targetDir, 'package.json'),
|
|
60
|
+
JSON.stringify(packageJson, null, 2)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Run npm install
|
|
64
|
+
execSync('npm install --silent', {
|
|
65
|
+
cwd: targetDir,
|
|
66
|
+
stdio: 'pipe' // Suppress output
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return targetDir;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new Error(`Failed to create dependency workspace: ${error}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Use hash-based cached workspace
|
|
76
|
+
const hash = this.hashDependencies(dependencies);
|
|
77
|
+
|
|
78
|
+
// Check cache
|
|
79
|
+
const cached = this.cache.get(hash);
|
|
80
|
+
if (cached && fs.existsSync(cached) && this.isWorkspaceValid(cached, dependencies)) {
|
|
81
|
+
return cached;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Final workspace location
|
|
85
|
+
const workspaceDir = path.join(this.WORKSPACE_BASE, hash);
|
|
86
|
+
|
|
87
|
+
// Check if valid workspace already exists on disk (cross-VM reuse)
|
|
88
|
+
if (fs.existsSync(workspaceDir) && this.isWorkspaceValid(workspaceDir, dependencies)) {
|
|
89
|
+
this.cache.set(hash, workspaceDir);
|
|
90
|
+
return workspaceDir;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Ensure base directory exists
|
|
94
|
+
if (!fs.existsSync(this.WORKSPACE_BASE)) {
|
|
95
|
+
fs.mkdirSync(this.WORKSPACE_BASE, {recursive: true});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Create workspace in temporary location to ensure atomicity
|
|
99
|
+
// This prevents reusing partially created workspaces from crashes
|
|
100
|
+
// and handles concurrency with other Node processes
|
|
101
|
+
const tempSuffix = `.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
102
|
+
const tempWorkspaceDir = path.join(this.WORKSPACE_BASE, hash + tempSuffix);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// Create temporary workspace directory
|
|
106
|
+
fs.mkdirSync(tempWorkspaceDir, {recursive: true});
|
|
107
|
+
|
|
108
|
+
// Create package.json
|
|
109
|
+
const packageJson = {
|
|
110
|
+
name: "openrewrite-template-workspace",
|
|
111
|
+
version: "1.0.0",
|
|
112
|
+
private: true,
|
|
113
|
+
dependencies: dependencies
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
fs.writeFileSync(
|
|
117
|
+
path.join(tempWorkspaceDir, 'package.json'),
|
|
118
|
+
JSON.stringify(packageJson, null, 2)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Run npm install
|
|
122
|
+
execSync('npm install --silent', {
|
|
123
|
+
cwd: tempWorkspaceDir,
|
|
124
|
+
stdio: 'pipe' // Suppress output
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Atomically move to final location with retry logic for concurrency
|
|
128
|
+
let moved = false;
|
|
129
|
+
let retries = 3;
|
|
130
|
+
|
|
131
|
+
while (!moved && retries > 0) {
|
|
132
|
+
try {
|
|
133
|
+
// Attempt atomic rename (works on POSIX, fails on Windows if target exists)
|
|
134
|
+
fs.renameSync(tempWorkspaceDir, workspaceDir);
|
|
135
|
+
moved = true;
|
|
136
|
+
} catch (error: any) {
|
|
137
|
+
// Handle concurrent creation by another process
|
|
138
|
+
if (error.code === 'EEXIST' || error.code === 'ENOTEMPTY' || error.code === 'EISDIR' ||
|
|
139
|
+
(error.code === 'EPERM' && fs.existsSync(workspaceDir))) {
|
|
140
|
+
// Target exists - check if it's valid
|
|
141
|
+
if (this.isWorkspaceValid(workspaceDir, dependencies)) {
|
|
142
|
+
// Another process created a valid workspace - use theirs
|
|
143
|
+
moved = true; // Don't try again
|
|
144
|
+
} else {
|
|
145
|
+
// Invalid workspace exists - try to remove and retry
|
|
146
|
+
try {
|
|
147
|
+
fs.rmSync(workspaceDir, {recursive: true, force: true});
|
|
148
|
+
retries--;
|
|
149
|
+
} catch (removeError) {
|
|
150
|
+
// Another process might be using it, give up
|
|
151
|
+
retries = 0;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} else if (error.code === 'EXDEV') {
|
|
155
|
+
// Cross-device link - fallback to copy+remove (not atomic, but rare)
|
|
156
|
+
try {
|
|
157
|
+
fs.cpSync(tempWorkspaceDir, workspaceDir, {recursive: true});
|
|
158
|
+
moved = true;
|
|
159
|
+
} catch (copyError) {
|
|
160
|
+
// Check if another process created it while we were copying
|
|
161
|
+
if (this.isWorkspaceValid(workspaceDir, dependencies)) {
|
|
162
|
+
moved = true;
|
|
163
|
+
} else {
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
// Unexpected error
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Clean up temp directory
|
|
175
|
+
try {
|
|
176
|
+
if (fs.existsSync(tempWorkspaceDir)) {
|
|
177
|
+
fs.rmSync(tempWorkspaceDir, {recursive: true, force: true});
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
// Ignore cleanup errors
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Verify final workspace is valid (might be from another process)
|
|
184
|
+
if (!this.isWorkspaceValid(workspaceDir, dependencies)) {
|
|
185
|
+
throw new Error('Failed to create valid workspace due to concurrent modifications');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Cache the workspace
|
|
189
|
+
this.cache.set(hash, workspaceDir);
|
|
190
|
+
|
|
191
|
+
return workspaceDir;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
// Clean up temporary workspace on failure
|
|
194
|
+
try {
|
|
195
|
+
if (fs.existsSync(tempWorkspaceDir)) {
|
|
196
|
+
fs.rmSync(tempWorkspaceDir, {recursive: true, force: true});
|
|
197
|
+
}
|
|
198
|
+
} catch {
|
|
199
|
+
// Ignore cleanup errors
|
|
200
|
+
}
|
|
201
|
+
throw new Error(`Failed to create dependency workspace: ${error}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Generates a hash from dependencies for caching.
|
|
207
|
+
*/
|
|
208
|
+
private static hashDependencies(dependencies: Record<string, string>): string {
|
|
209
|
+
// Sort keys for consistent hashing
|
|
210
|
+
const sorted = Object.keys(dependencies).sort();
|
|
211
|
+
const content = sorted.map(key => `${key}:${dependencies[key]}`).join(',');
|
|
212
|
+
return crypto.createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Checks if a workspace is valid (has node_modules and matching package.json).
|
|
217
|
+
*
|
|
218
|
+
* @param workspaceDir Directory to check
|
|
219
|
+
* @param expectedDependencies Optional dependencies to check against package.json
|
|
220
|
+
*/
|
|
221
|
+
private static isWorkspaceValid(workspaceDir: string, expectedDependencies?: Record<string, string>): boolean {
|
|
222
|
+
const nodeModules = path.join(workspaceDir, 'node_modules');
|
|
223
|
+
const packageJsonPath = path.join(workspaceDir, 'package.json');
|
|
224
|
+
|
|
225
|
+
if (!fs.existsSync(nodeModules) || !fs.existsSync(packageJsonPath)) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// If dependencies provided, check if they match
|
|
230
|
+
if (expectedDependencies) {
|
|
231
|
+
try {
|
|
232
|
+
const packageJsonContent = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
233
|
+
const existingDeps = packageJsonContent.dependencies || {};
|
|
234
|
+
|
|
235
|
+
// Check if all expected dependencies match
|
|
236
|
+
const expectedKeys = Object.keys(expectedDependencies).sort();
|
|
237
|
+
const existingKeys = Object.keys(existingDeps).sort();
|
|
238
|
+
|
|
239
|
+
if (expectedKeys.length !== existingKeys.length) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
for (let i = 0; i < expectedKeys.length; i++) {
|
|
244
|
+
if (expectedKeys[i] !== existingKeys[i] ||
|
|
245
|
+
expectedDependencies[expectedKeys[i]] !== existingDeps[existingKeys[i]]) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Cleans up old workspace directories.
|
|
259
|
+
* Removes workspaces older than the specified age.
|
|
260
|
+
* Also removes all temporary directories (*.tmp-*) regardless of age,
|
|
261
|
+
* as these indicate incomplete/crashed operations.
|
|
262
|
+
*
|
|
263
|
+
* @param maxAgeMs Maximum age in milliseconds (default: 24 hours)
|
|
264
|
+
*/
|
|
265
|
+
static cleanupOldWorkspaces(maxAgeMs: number = 24 * 60 * 60 * 1000): void {
|
|
266
|
+
if (!fs.existsSync(this.WORKSPACE_BASE)) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const now = Date.now();
|
|
271
|
+
const entries = fs.readdirSync(this.WORKSPACE_BASE, {withFileTypes: true});
|
|
272
|
+
|
|
273
|
+
for (const entry of entries) {
|
|
274
|
+
if (!entry.isDirectory()) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const workspaceDir = path.join(this.WORKSPACE_BASE, entry.name);
|
|
279
|
+
|
|
280
|
+
// Always clean up temporary directories (incomplete operations)
|
|
281
|
+
if (entry.name.includes('.tmp-')) {
|
|
282
|
+
try {
|
|
283
|
+
fs.rmSync(workspaceDir, {recursive: true, force: true});
|
|
284
|
+
} catch (error) {
|
|
285
|
+
// Ignore errors, might be in use by another process
|
|
286
|
+
}
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Clean up old regular workspaces
|
|
291
|
+
try {
|
|
292
|
+
const stats = fs.statSync(workspaceDir);
|
|
293
|
+
const age = now - stats.mtimeMs;
|
|
294
|
+
|
|
295
|
+
if (age > maxAgeMs) {
|
|
296
|
+
fs.rmSync(workspaceDir, {recursive: true, force: true});
|
|
297
|
+
// Remove from cache
|
|
298
|
+
for (const [hash, dir] of this.cache.entries()) {
|
|
299
|
+
if (dir === workspaceDir) {
|
|
300
|
+
this.cache.delete(hash);
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch (error) {
|
|
306
|
+
// Ignore errors, workspace might be in use
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Clears all cached workspaces.
|
|
313
|
+
*/
|
|
314
|
+
static clearCache(): void {
|
|
315
|
+
this.cache.clear();
|
|
316
|
+
}
|
|
317
|
+
}
|
package/src/javascript/parser.ts
CHANGED
|
@@ -609,11 +609,12 @@ export class JavaScriptParserVisitor {
|
|
|
609
609
|
visitNumericLiteral(node: ts.NumericLiteral): J.Literal {
|
|
610
610
|
// Parse the numeric value from the text
|
|
611
611
|
const text = node.text;
|
|
612
|
-
let value: number | bigint;
|
|
612
|
+
let value: number | bigint | string;
|
|
613
613
|
|
|
614
614
|
// Check if it's a BigInt literal (ends with 'n')
|
|
615
615
|
if (text.endsWith('n')) {
|
|
616
|
-
|
|
616
|
+
// TODO consider adding `JS.Literal`
|
|
617
|
+
value = text.slice(0, -1);
|
|
617
618
|
} else if (text.includes('.') || text.toLowerCase().includes('e')) {
|
|
618
619
|
// Floating point number
|
|
619
620
|
value = parseFloat(text);
|
|
@@ -708,7 +709,8 @@ export class JavaScriptParserVisitor {
|
|
|
708
709
|
visitBigIntLiteral(node: ts.BigIntLiteral): J.Literal {
|
|
709
710
|
// Parse BigInt value, removing the 'n' suffix
|
|
710
711
|
const text = node.text;
|
|
711
|
-
|
|
712
|
+
// TODO consider adding `JS.Literal`
|
|
713
|
+
const value = text.slice(0, -1);
|
|
712
714
|
return this.mapLiteral(node, value);
|
|
713
715
|
}
|
|
714
716
|
|
|
@@ -717,6 +719,7 @@ export class JavaScriptParserVisitor {
|
|
|
717
719
|
}
|
|
718
720
|
|
|
719
721
|
visitRegularExpressionLiteral(node: ts.RegularExpressionLiteral): J.Literal {
|
|
722
|
+
// TODO consider adding `JS.Literal`
|
|
720
723
|
return this.mapLiteral(node, node.text); // FIXME value not in AST
|
|
721
724
|
}
|
|
722
725
|
|
|
@@ -27,14 +27,14 @@ export function hasSourcePath(filePattern: string): Promise<RpcRecipe> | TreeVis
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function usesMethod(methodPattern: string, matchOverrides: boolean = false): Promise<RpcRecipe> | TreeVisitor<any, ExecutionContext> {
|
|
30
|
-
return RewriteRpc.get() ? RewriteRpc.get()!.prepareRecipe("org.openrewrite.java.search.
|
|
30
|
+
return RewriteRpc.get() ? RewriteRpc.get()!.prepareRecipe("org.openrewrite.java.search.HasMethod", {
|
|
31
31
|
methodPattern,
|
|
32
32
|
matchOverrides
|
|
33
33
|
}) : new UsesMethod(methodPattern);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function usesType(fullyQualifiedType: string): Promise<RpcRecipe> | TreeVisitor<any, ExecutionContext> {
|
|
37
|
-
return RewriteRpc.get() ? RewriteRpc.get()!.prepareRecipe("org.openrewrite.java.search.
|
|
37
|
+
return RewriteRpc.get() ? RewriteRpc.get()!.prepareRecipe("org.openrewrite.java.search.HasType", {
|
|
38
38
|
fullyQualifiedType,
|
|
39
39
|
checkAssignability: false
|
|
40
40
|
}) : new UsesType(fullyQualifiedType);
|