@openrewrite/rewrite 8.70.0-20251219-180817 → 8.70.0-20251219-215811

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 (94) hide show
  1. package/dist/cli/cli-utils.d.ts +6 -6
  2. package/dist/cli/cli-utils.d.ts.map +1 -1
  3. package/dist/cli/cli-utils.js +50 -228
  4. package/dist/cli/cli-utils.js.map +1 -1
  5. package/dist/javascript/assertions.d.ts.map +1 -1
  6. package/dist/javascript/assertions.js +87 -12
  7. package/dist/javascript/assertions.js.map +1 -1
  8. package/dist/javascript/autodetect.d.ts +11 -11
  9. package/dist/javascript/autodetect.d.ts.map +1 -1
  10. package/dist/javascript/autodetect.js +18 -21
  11. package/dist/javascript/autodetect.js.map +1 -1
  12. package/dist/javascript/format/prettier-config-loader.d.ts.map +1 -1
  13. package/dist/javascript/format/prettier-config-loader.js +1 -1
  14. package/dist/javascript/format/prettier-config-loader.js.map +1 -1
  15. package/dist/javascript/index.d.ts +1 -0
  16. package/dist/javascript/index.d.ts.map +1 -1
  17. package/dist/javascript/index.js +1 -0
  18. package/dist/javascript/index.js.map +1 -1
  19. package/dist/javascript/markers.d.ts.map +1 -1
  20. package/dist/javascript/markers.js +135 -6
  21. package/dist/javascript/markers.js.map +1 -1
  22. package/dist/javascript/node-resolution-result.d.ts +4 -1
  23. package/dist/javascript/node-resolution-result.d.ts.map +1 -1
  24. package/dist/javascript/node-resolution-result.js +22 -1
  25. package/dist/javascript/node-resolution-result.js.map +1 -1
  26. package/dist/javascript/package-json-parser.d.ts +7 -0
  27. package/dist/javascript/package-json-parser.d.ts.map +1 -1
  28. package/dist/javascript/package-json-parser.js +19 -1
  29. package/dist/javascript/package-json-parser.js.map +1 -1
  30. package/dist/javascript/parser.d.ts.map +1 -1
  31. package/dist/javascript/parser.js +1 -13
  32. package/dist/javascript/parser.js.map +1 -1
  33. package/dist/javascript/preconditions.js +4 -4
  34. package/dist/javascript/preconditions.js.map +1 -1
  35. package/dist/javascript/project-parser.d.ts +137 -0
  36. package/dist/javascript/project-parser.d.ts.map +1 -0
  37. package/dist/javascript/project-parser.js +726 -0
  38. package/dist/javascript/project-parser.js.map +1 -0
  39. package/dist/javascript/style.d.ts +9 -26
  40. package/dist/javascript/style.d.ts.map +1 -1
  41. package/dist/javascript/style.js +18 -42
  42. package/dist/javascript/style.js.map +1 -1
  43. package/dist/json/parser.d.ts.map +1 -1
  44. package/dist/json/parser.js +1 -0
  45. package/dist/json/parser.js.map +1 -1
  46. package/dist/markers.d.ts +1 -1
  47. package/dist/markers.js +1 -1
  48. package/dist/markers.js.map +1 -1
  49. package/dist/parser.d.ts +1 -1
  50. package/dist/parser.d.ts.map +1 -1
  51. package/dist/rpc/index.d.ts +0 -1
  52. package/dist/rpc/index.d.ts.map +1 -1
  53. package/dist/rpc/index.js +4 -2
  54. package/dist/rpc/index.js.map +1 -1
  55. package/dist/rpc/request/index.d.ts +1 -0
  56. package/dist/rpc/request/index.d.ts.map +1 -1
  57. package/dist/rpc/request/index.js +1 -0
  58. package/dist/rpc/request/index.js.map +1 -1
  59. package/dist/rpc/request/parse-project.d.ts +25 -0
  60. package/dist/rpc/request/parse-project.d.ts.map +1 -0
  61. package/dist/rpc/request/parse-project.js +304 -0
  62. package/dist/rpc/request/parse-project.js.map +1 -0
  63. package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
  64. package/dist/rpc/rewrite-rpc.js +1 -0
  65. package/dist/rpc/rewrite-rpc.js.map +1 -1
  66. package/dist/text/parser.d.ts.map +1 -1
  67. package/dist/text/parser.js +1 -0
  68. package/dist/text/parser.js.map +1 -1
  69. package/dist/version.txt +1 -1
  70. package/dist/yaml/parser.d.ts.map +1 -1
  71. package/dist/yaml/parser.js +52 -4
  72. package/dist/yaml/parser.js.map +1 -1
  73. package/package.json +1 -1
  74. package/src/cli/cli-utils.ts +46 -237
  75. package/src/javascript/assertions.ts +74 -10
  76. package/src/javascript/autodetect.ts +22 -15
  77. package/src/javascript/format/prettier-config-loader.ts +2 -2
  78. package/src/javascript/index.ts +1 -0
  79. package/src/javascript/markers.ts +157 -7
  80. package/src/javascript/node-resolution-result.ts +23 -2
  81. package/src/javascript/package-json-parser.ts +19 -1
  82. package/src/javascript/parser.ts +1 -16
  83. package/src/javascript/preconditions.ts +1 -1
  84. package/src/javascript/project-parser.ts +657 -0
  85. package/src/javascript/style.ts +43 -28
  86. package/src/json/parser.ts +3 -1
  87. package/src/markers.ts +1 -1
  88. package/src/parser.ts +1 -1
  89. package/src/rpc/index.ts +7 -5
  90. package/src/rpc/request/index.ts +1 -0
  91. package/src/rpc/request/parse-project.ts +283 -0
  92. package/src/rpc/rewrite-rpc.ts +2 -0
  93. package/src/text/parser.ts +3 -1
  94. package/src/yaml/parser.ts +53 -5
@@ -28,7 +28,8 @@ export const StyleKind = {
28
28
  WrappingAndBracesStyle: "org.openrewrite.javascript.style.WrappingAndBracesStyle",
29
29
  BlankLinesStyle: "org.openrewrite.javascript.style.BlankLinesStyle",
30
30
  TabsAndIndentsStyle: "org.openrewrite.javascript.style.TabsAndIndentsStyle",
31
- PrettierStyle: "org.openrewrite.javascript.style.PrettierStyle"
31
+ PrettierStyle: "org.openrewrite.javascript.style.PrettierStyle",
32
+ Autodetect: "org.openrewrite.javascript.style.Autodetect"
32
33
  } as const;
33
34
 
34
35
  /**
@@ -41,32 +42,46 @@ export const StyleKind = {
41
42
  * When this style is present, AutoformatVisitor will use Prettier for formatting
42
43
  * instead of the built-in formatting visitors.
43
44
  */
44
- export class PrettierStyle implements NamedStyles<typeof StyleKind.PrettierStyle> {
45
- readonly kind = StyleKind.PrettierStyle;
46
- readonly name = "org.openrewrite.javascript.Prettier";
47
- readonly displayName = "Prettier";
48
- readonly description = "Prettier code formatter configuration.";
49
- readonly tags: string[] = [];
50
- readonly styles: Style[] = [];
51
-
52
- constructor(
53
- readonly id: string,
54
- /**
55
- * The resolved Prettier options for this file (with overrides applied).
56
- */
57
- readonly config: Record<string, unknown>,
58
- /**
59
- * The Prettier version from the project's package.json.
60
- * At formatting time, this version of Prettier will be loaded dynamically
61
- * to ensure consistent formatting.
62
- */
63
- readonly prettierVersion?: string,
64
- /**
65
- * Whether this file is ignored by .prettierignore.
66
- * When true, Prettier formatting should be skipped for this file.
67
- */
68
- readonly ignored: boolean = false
69
- ) {}
45
+ export interface PrettierStyle extends NamedStyles<typeof StyleKind.PrettierStyle> {
46
+ readonly kind: typeof StyleKind.PrettierStyle;
47
+ readonly name: "org.openrewrite.javascript.Prettier";
48
+ readonly displayName: "Prettier";
49
+ readonly description: "Prettier code formatter configuration.";
50
+ /**
51
+ * The resolved Prettier options for this file (with overrides applied).
52
+ */
53
+ readonly config: Record<string, unknown>;
54
+ /**
55
+ * The Prettier version from the project's package.json.
56
+ * At formatting time, this version of Prettier will be loaded dynamically
57
+ * to ensure consistent formatting.
58
+ */
59
+ readonly prettierVersion?: string;
60
+ /**
61
+ * Whether this file is ignored by .prettierignore.
62
+ * When true, Prettier formatting should be skipped for this file.
63
+ */
64
+ readonly ignored: boolean;
65
+ }
66
+
67
+ export function prettierStyle(
68
+ id: string,
69
+ config: Record<string, unknown>,
70
+ prettierVersion?: string,
71
+ ignored: boolean = false
72
+ ): PrettierStyle {
73
+ return {
74
+ kind: StyleKind.PrettierStyle,
75
+ id,
76
+ name: "org.openrewrite.javascript.Prettier",
77
+ displayName: "Prettier",
78
+ description: "Prettier code formatter configuration.",
79
+ tags: [],
80
+ styles: [],
81
+ config,
82
+ prettierVersion,
83
+ ignored
84
+ };
70
85
  }
71
86
 
72
87
  export const SpacesStyleDetailKind = {
@@ -187,7 +202,7 @@ export namespace SpacesStyle {
187
202
  }
188
203
 
189
204
  export const WrappingAndBracesStyleDetailKind = {
190
- WrappingAndBracesStyleIfStatement: "org.openrewrite.java.style.WrappingAndBracesStyle$IfStatement",
205
+ WrappingAndBracesStyleIfStatement: "org.openrewrite.javascript.style.WrappingAndBracesStyle$IfStatement",
191
206
  WrappingAndBracesStyleKeepWhenReformatting: "org.openrewrite.javascript.style.WrappingAndBracesStyle$KeepWhenReformatting",
192
207
  } as const;
193
208
 
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import {emptyMarkers, markers, MarkersKind, ParseExceptionResult} from "../markers";
17
- import {Parser, ParserInput, parserInputRead} from "../parser";
17
+ import {Parser, ParserInput, parserInputRead, Parsers} from "../parser";
18
18
  import {randomId} from "../uuid";
19
19
  import {SourceFile} from "../tree";
20
20
  import {emptySpace, Json, space} from "./tree";
@@ -534,3 +534,5 @@ class JsoncParserReader {
534
534
  } satisfies Json.Literal as Json.Literal;
535
535
  }
536
536
  }
537
+
538
+ Parsers.registerParser("json", JsonParser);
package/src/markers.ts CHANGED
@@ -18,7 +18,7 @@ import {asRef} from "./reference";
18
18
 
19
19
  export const MarkersKind = {
20
20
  Markers: "org.openrewrite.marker.Markers",
21
- NamedStyles: "org.openrewrite.marker.NamedStyles",
21
+ NamedStyles: "org.openrewrite.style.NamedStyles",
22
22
  SearchResult: "org.openrewrite.marker.SearchResult",
23
23
  ParseExceptionResult: "org.openrewrite.ParseExceptionResult",
24
24
 
package/src/parser.ts CHANGED
@@ -148,7 +148,7 @@ export function readSourceSync(sourcePath: ParserInput) {
148
148
 
149
149
  type ParserConstructor<T extends Parser> = new (options?: ParserOptions) => T;
150
150
 
151
- export type ParserType = "javascript" | "packageJson";
151
+ export type ParserType = "javascript" | "packageJson" | "json" | "yaml" | "plainText";
152
152
 
153
153
  export class Parsers {
154
154
  private static registry = new Map<ParserType, ParserConstructor<Parser>>();
package/src/rpc/index.ts CHANGED
@@ -16,11 +16,13 @@
16
16
  import {Checksum, FileAttributes, TreeKind} from "../tree";
17
17
  import {RpcCodecs, RpcReceiveQueue, RpcSendQueue} from "./queue";
18
18
  import {createDraft, finishDraft} from "immer";
19
- import {Markers, MarkersKind, SearchResult, MarkupError, MarkupWarn, MarkupInfo, MarkupDebug} from "../markers";
19
+ import {Markers, MarkersKind, MarkupDebug, MarkupError, MarkupInfo, MarkupWarn, SearchResult} from "../markers";
20
+ import {asRef} from "../reference";
20
21
 
21
- export * from "./queue"
22
- export * from "../reference"
23
- export * from "./rewrite-rpc"
22
+ export * from "./queue";
23
+ export * from "../reference";
24
+ // rewrite-rpc is not exported here to avoid circular dependency
25
+ // Import directly from "./rewrite-rpc" if needed
24
26
 
25
27
  RpcCodecs.registerCodec(TreeKind.Checksum, {
26
28
  async rpcReceive(before: Checksum, q: RpcReceiveQueue): Promise<Checksum> {
@@ -70,7 +72,7 @@ RpcCodecs.registerCodec(MarkersKind.Markers, {
70
72
 
71
73
  async rpcSend(after: Markers, q: RpcSendQueue): Promise<void> {
72
74
  await q.getAndSend(after, m => m.id);
73
- await q.getAndSendList(after, m => m.markers, m => m.id);
75
+ await q.getAndSendList(after, m => m.markers.map(marker => asRef(marker)), m => m.id);
74
76
  }
75
77
  });
76
78
 
@@ -17,6 +17,7 @@ export * from "./generate";
17
17
  export * from "./get-object";
18
18
  export * from "./get-recipes";
19
19
  export * from "./parse";
20
+ export * from "./parse-project";
20
21
  export * from "./prepare-recipe";
21
22
  export * from "./print";
22
23
  export * from "./visit";
@@ -0,0 +1,283 @@
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 rpc from "vscode-jsonrpc/node";
17
+ import * as path from "path";
18
+ import {ExecutionContext} from "../../execution";
19
+ import {randomId, UUID} from "../../uuid";
20
+ import {produce} from "immer";
21
+ import {SourceFile} from "../../tree";
22
+ import {Parsers} from "../../parser";
23
+ import {withMetrics} from "./metrics";
24
+ import {DEFAULT_EXCLUSIONS, ProjectParser} from "../../javascript";
25
+
26
+ /**
27
+ * Response item with object ID and source file type for proper deserialization.
28
+ */
29
+ export interface ParseProjectResponseItem {
30
+ id: UUID;
31
+ sourceFileType: string;
32
+ }
33
+
34
+ /**
35
+ * RPC request to parse an entire project directory.
36
+ * Discovers and parses:
37
+ * - JavaScript/TypeScript source files
38
+ * - package.json files (with NodeResolutionResult markers)
39
+ * - Lock files (package-lock.json as JSON, yarn.lock/pnpm-lock.yaml as YAML)
40
+ *
41
+ * Uses ProjectParser for file discovery and Prettier detection.
42
+ */
43
+ export class ParseProject {
44
+ constructor(
45
+ private readonly projectPath: string,
46
+ private readonly exclusions?: string[]
47
+ ) {}
48
+
49
+ static handle(
50
+ connection: rpc.MessageConnection,
51
+ localObjects: Map<string, ((input: string) => any) | any>,
52
+ metricsCsv?: string
53
+ ): void {
54
+ connection.onRequest(
55
+ new rpc.RequestType<ParseProject, ParseProjectResponseItem[], Error>("ParseProject"),
56
+ withMetrics<ParseProject, ParseProjectResponseItem[]>(
57
+ "ParseProject",
58
+ metricsCsv,
59
+ (context) => async (request) => {
60
+ context.target = request.projectPath;
61
+
62
+ const projectPath = path.resolve(request.projectPath);
63
+ const exclusions = request.exclusions ?? DEFAULT_EXCLUSIONS;
64
+
65
+ // Use ProjectParser for file discovery and Prettier detection
66
+ const projectParser = new ProjectParser(projectPath, {exclusions});
67
+ const discovered = await projectParser.discoverFiles();
68
+ const prettierLoader = await projectParser.createPrettierLoader();
69
+
70
+ const resultItems: ParseProjectResponseItem[] = [];
71
+ const ctx = new ExecutionContext();
72
+
73
+ // Parse package.json files (these get NodeResolutionResult markers)
74
+ if (discovered.packageJsonFiles.length > 0) {
75
+ const parser = Parsers.createParser("packageJson", {
76
+ ctx,
77
+ relativeTo: projectPath
78
+ });
79
+ const generator = parser.parse(...discovered.packageJsonFiles);
80
+
81
+ for (const _ of discovered.packageJsonFiles) {
82
+ const id = randomId();
83
+ localObjects.set(id, async (id: string) => {
84
+ const sourceFile: SourceFile = (await generator.next()).value;
85
+ return produce(sourceFile, (draft) => {
86
+ draft.id = id;
87
+ });
88
+ });
89
+ resultItems.push({
90
+ id,
91
+ sourceFileType: "org.openrewrite.json.tree.Json$Document" // break cycle
92
+ });
93
+ }
94
+ }
95
+
96
+ // Parse JSON lock files
97
+ if (discovered.lockFiles.json.length > 0) {
98
+ const parser = Parsers.createParser("json", {ctx, relativeTo: projectPath});
99
+ const generator = parser.parse(...discovered.lockFiles.json);
100
+
101
+ for (const _ of discovered.lockFiles.json) {
102
+ const id = randomId();
103
+ localObjects.set(id, async (id: string) => {
104
+ const sourceFile: SourceFile = (await generator.next()).value;
105
+ return produce(sourceFile, (draft) => {
106
+ draft.id = id;
107
+ });
108
+ });
109
+ resultItems.push({
110
+ id,
111
+ sourceFileType: "org.openrewrite.json.tree.Json$Document" // break cycle
112
+ });
113
+ }
114
+ }
115
+
116
+ // Parse YAML lock files
117
+ if (discovered.lockFiles.yaml.length > 0) {
118
+ const parser = Parsers.createParser("yaml", {ctx, relativeTo: projectPath});
119
+ const generator = parser.parse(...discovered.lockFiles.yaml);
120
+
121
+ for (const _ of discovered.lockFiles.yaml) {
122
+ const id = randomId();
123
+ localObjects.set(id, async (id: string) => {
124
+ const sourceFile: SourceFile = (await generator.next()).value;
125
+ return produce(sourceFile, (draft) => {
126
+ draft.id = id;
127
+ });
128
+ });
129
+ resultItems.push({
130
+ id,
131
+ sourceFileType: "org.openrewrite.yaml.tree.Yaml$Documents" // break cycle
132
+ });
133
+ }
134
+ }
135
+
136
+ // Parse text lock files (yarn.lock Classic)
137
+ if (discovered.lockFiles.text.length > 0) {
138
+ const parser = Parsers.createParser("plainText", {ctx, relativeTo: projectPath});
139
+ const generator = parser.parse(...discovered.lockFiles.text);
140
+
141
+ for (const _ of discovered.lockFiles.text) {
142
+ const id = randomId();
143
+ localObjects.set(id, async (id: string) => {
144
+ const sourceFile: SourceFile = (await generator.next()).value;
145
+ return produce(sourceFile, (draft) => {
146
+ draft.id = id;
147
+ });
148
+ });
149
+ resultItems.push({
150
+ id,
151
+ sourceFileType: "org.openrewrite.text.PlainText" // break cycle
152
+ });
153
+ }
154
+ }
155
+
156
+ // Parse JavaScript/TypeScript source files
157
+ if (discovered.jsFiles.length > 0) {
158
+ const parser = Parsers.createParser("javascript", {
159
+ ctx,
160
+ relativeTo: projectPath
161
+ });
162
+
163
+ // Check if Prettier is available
164
+ const detection = await prettierLoader.detectPrettier();
165
+
166
+ if (detection.available) {
167
+ // Prettier is available: add per-file PrettierStyle markers
168
+ const generator = parser.parse(...discovered.jsFiles);
169
+
170
+ for (const filePath of discovered.jsFiles) {
171
+ const id = randomId();
172
+ localObjects.set(id, async (id: string) => {
173
+ const sourceFile: SourceFile = (await generator.next()).value;
174
+ // Add PrettierStyle marker if Prettier is available
175
+ const prettierMarker = await prettierLoader.getConfigMarker(filePath);
176
+ return produce(sourceFile, (draft) => {
177
+ draft.id = id;
178
+ if (prettierMarker) {
179
+ draft.markers.markers = draft.markers.markers.concat([prettierMarker]);
180
+ }
181
+ });
182
+ });
183
+ resultItems.push({
184
+ id,
185
+ sourceFileType: "org.openrewrite.javascript.tree.JS$CompilationUnit" // break cycle
186
+ });
187
+ }
188
+ } else {
189
+ // Prettier is NOT available: auto-detect styles from parsed files
190
+ // Parse all files first to sample them
191
+ const parsedFiles: {id: string, sourceFile: SourceFile}[] = [];
192
+ for await (const sourceFile of parser.parse(...discovered.jsFiles)) {
193
+ const id = randomId();
194
+ parsedFiles.push({id, sourceFile});
195
+ }
196
+
197
+ // Sample all parsed files and build Autodetect marker using ProjectParser helper
198
+ const autodetectMarker = await projectParser.buildAutodetectMarker(
199
+ parsedFiles.map(p => p.sourceFile)
200
+ );
201
+
202
+ // Store thunks that add the Autodetect marker
203
+ for (const {id, sourceFile} of parsedFiles) {
204
+ localObjects.set(id, async (newId: string) => {
205
+ return produce(sourceFile, (draft) => {
206
+ draft.id = newId;
207
+ draft.markers.markers = draft.markers.markers.concat([autodetectMarker]);
208
+ });
209
+ });
210
+ resultItems.push({
211
+ id,
212
+ sourceFileType: "org.openrewrite.javascript.tree.JS$CompilationUnit" // break cycle
213
+ });
214
+ }
215
+ }
216
+ }
217
+
218
+ // Parse other YAML files
219
+ if (discovered.yamlFiles.length > 0) {
220
+ const parser = Parsers.createParser("yaml", {ctx, relativeTo: projectPath});
221
+ const generator = parser.parse(...discovered.yamlFiles);
222
+
223
+ for (const _ of discovered.yamlFiles) {
224
+ const id = randomId();
225
+ localObjects.set(id, async (id: string) => {
226
+ const sourceFile: SourceFile = (await generator.next()).value;
227
+ return produce(sourceFile, (draft) => {
228
+ draft.id = id;
229
+ });
230
+ });
231
+ resultItems.push({
232
+ id,
233
+ sourceFileType: "org.openrewrite.yaml.tree.Yaml$Documents" // break cycle
234
+ });
235
+ }
236
+ }
237
+
238
+ // Parse other JSON files
239
+ if (discovered.jsonFiles.length > 0) {
240
+ const parser = Parsers.createParser("json", {ctx, relativeTo: projectPath});
241
+ const generator = parser.parse(...discovered.jsonFiles);
242
+
243
+ for (const _ of discovered.jsonFiles) {
244
+ const id = randomId();
245
+ localObjects.set(id, async (id: string) => {
246
+ const sourceFile: SourceFile = (await generator.next()).value;
247
+ return produce(sourceFile, (draft) => {
248
+ draft.id = id;
249
+ });
250
+ });
251
+ resultItems.push({
252
+ id,
253
+ sourceFileType: "org.openrewrite.json.tree.Json$Document" // break cycle
254
+ });
255
+ }
256
+ }
257
+
258
+ // Parse text config files (.prettierignore, .gitignore, etc.)
259
+ if (discovered.textFiles.length > 0) {
260
+ const parser = Parsers.createParser("plainText", {ctx, relativeTo: projectPath});
261
+ const generator = parser.parse(...discovered.textFiles);
262
+
263
+ for (const _ of discovered.textFiles) {
264
+ const id = randomId();
265
+ localObjects.set(id, async (id: string) => {
266
+ const sourceFile: SourceFile = (await generator.next()).value;
267
+ return produce(sourceFile, (draft) => {
268
+ draft.id = id;
269
+ });
270
+ });
271
+ resultItems.push({
272
+ id,
273
+ sourceFileType: "org.openrewrite.text.PlainText" // break cycle
274
+ });
275
+ }
276
+ }
277
+
278
+ return resultItems;
279
+ }
280
+ )
281
+ );
282
+ }
283
+ }
@@ -24,6 +24,7 @@ import {
24
24
  GetObject,
25
25
  GetRecipes,
26
26
  Parse,
27
+ ParseProject,
27
28
  PrepareRecipe,
28
29
  PrepareRecipeResponse,
29
30
  Print,
@@ -90,6 +91,7 @@ export class RewriteRpc {
90
91
  GetLanguages.handle(this.connection, options.metricsCsv);
91
92
  PrepareRecipe.handle(this.connection, registry, preparedRecipes, options.metricsCsv);
92
93
  Parse.handle(this.connection, this.localObjects, options.metricsCsv);
94
+ ParseProject.handle(this.connection, this.localObjects, options.metricsCsv);
93
95
  Print.handle(this.connection, getObject, options.logger, options.metricsCsv);
94
96
  InstallRecipes.handle(this.connection, options.recipeInstallDir ?? ".rewrite", registry, options.logger, options.metricsCsv);
95
97
 
@@ -13,7 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import {Parser, ParserInput, readSourceSync} from "../parser";
16
+ import {Parser, ParserInput, readSourceSync, Parsers} from "../parser";
17
17
  import {PlainText} from "./tree";
18
18
  import {randomId} from "../uuid";
19
19
  import {emptyMarkers} from "../markers";
@@ -32,3 +32,5 @@ export class PlainTextParser extends Parser {
32
32
  }
33
33
  }
34
34
  }
35
+
36
+ Parsers.registerParser("plainText", PlainTextParser);
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import {emptyMarkers, markers, MarkersKind, ParseExceptionResult} from "../markers";
17
- import {Parser, ParserInput, parserInputRead} from "../parser";
17
+ import {Parser, ParserInput, parserInputRead, Parsers} from "../parser";
18
18
  import {randomId} from "../uuid";
19
19
  import {SourceFile} from "../tree";
20
20
  import {Yaml} from "./tree";
@@ -389,15 +389,49 @@ class YamlCstReader {
389
389
 
390
390
  private convertSequenceEntry(item: CstCollectionItem, dash: boolean, pendingPrefix: string = ""): {entry: Yaml.SequenceEntry, trailingContent: string} {
391
391
  // Build prefix from start tokens, but exclude the dash indicator itself
392
+ // Also extract anchor and tag if present
392
393
  let prefix = pendingPrefix;
393
394
  let afterDashSpace = "";
394
395
  let seenDash = false;
396
+ let anchorForValue: Yaml.Anchor | undefined;
397
+ let tagForValue: Yaml.Tag | undefined;
395
398
 
396
- for (const token of item.start || []) {
399
+ const startTokens = item.start || [];
400
+ for (let i = 0; i < startTokens.length; i++) {
401
+ const token = startTokens[i];
397
402
  if (token.type === 'seq-item-ind') {
398
403
  seenDash = true;
399
404
  } else if (seenDash) {
400
- afterDashSpace += token.source;
405
+ if (token.type === 'anchor') {
406
+ // Collect all remaining tokens after anchor as postfix
407
+ let postfix = "";
408
+ for (let j = i + 1; j < startTokens.length; j++) {
409
+ const nextToken = startTokens[j];
410
+ if (nextToken.type === 'tag') {
411
+ tagForValue = this.parseTagTokenWithSuffix(nextToken.source, postfix, startTokens, j + 1);
412
+ postfix = "";
413
+ break;
414
+ } else {
415
+ postfix += nextToken.source;
416
+ }
417
+ }
418
+ anchorForValue = {
419
+ kind: Yaml.Kind.Anchor,
420
+ id: randomId(),
421
+ prefix: afterDashSpace,
422
+ markers: emptyMarkers,
423
+ postfix,
424
+ key: token.source.substring(1) // Remove &
425
+ };
426
+ afterDashSpace = "";
427
+ break; // We've consumed all remaining tokens
428
+ } else if (token.type === 'tag') {
429
+ tagForValue = this.parseTagTokenWithSuffix(token.source, afterDashSpace, startTokens, i + 1);
430
+ afterDashSpace = "";
431
+ break; // Tag handler consumed remaining tokens
432
+ } else {
433
+ afterDashSpace += token.source;
434
+ }
401
435
  } else {
402
436
  prefix += token.source;
403
437
  }
@@ -410,8 +444,20 @@ class YamlCstReader {
410
444
  const valueResult = this.convertTokenWithTrailing(item.value);
411
445
  block = valueResult.node as Yaml.Block;
412
446
  trailing = valueResult.trailing;
413
- // Prepend the space after dash to the block's prefix
414
- block = {...block, prefix: afterDashSpace + block.prefix} as Yaml.Block;
447
+
448
+ // Apply anchor and tag if found in start tokens
449
+ if (anchorForValue && 'anchor' in block) {
450
+ block = {...block, anchor: anchorForValue} as Yaml.Block;
451
+ }
452
+ if (tagForValue && 'tag' in block) {
453
+ block = {...block, tag: tagForValue} as Yaml.Block;
454
+ }
455
+
456
+ // Prepend the space after dash to the block
457
+ // Use prependWhitespaceToValue to ensure Mapping/Sequence keep empty prefix
458
+ if (afterDashSpace) {
459
+ block = this.prependWhitespaceToValue(block, afterDashSpace);
460
+ }
415
461
  } else {
416
462
  block = this.createEmptyScalar(afterDashSpace);
417
463
  }
@@ -848,3 +894,5 @@ class YamlCstReader {
848
894
  return tokens.map(t => t.source).join('');
849
895
  }
850
896
  }
897
+
898
+ Parsers.registerParser("yaml", YamlParser);