kubernetes-fluent-client 3.0.3 → 4.0.0-rc-http2-watch
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/.prettierignore +4 -0
- package/README.md +24 -0
- package/dist/cli.js +21 -1
- package/dist/fileSystem.d.ts +11 -0
- package/dist/fileSystem.d.ts.map +1 -0
- package/dist/fileSystem.js +42 -0
- package/dist/fileSystem.test.d.ts +2 -0
- package/dist/fileSystem.test.d.ts.map +1 -0
- package/dist/fileSystem.test.js +75 -0
- package/dist/fluent/watch.d.ts +2 -0
- package/dist/fluent/watch.d.ts.map +1 -1
- package/dist/fluent/watch.js +147 -27
- package/dist/generate.d.ts +71 -11
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +130 -117
- package/dist/generate.test.js +293 -346
- package/dist/postProcessing.d.ts +246 -0
- package/dist/postProcessing.d.ts.map +1 -0
- package/dist/postProcessing.js +497 -0
- package/dist/postProcessing.test.d.ts +2 -0
- package/dist/postProcessing.test.d.ts.map +1 -0
- package/dist/postProcessing.test.js +550 -0
- package/e2e/cli.e2e.test.ts +127 -0
- package/e2e/crds/policyreports.default.expected/policyreport-v1alpha1.ts +332 -0
- package/e2e/crds/policyreports.default.expected/policyreport-v1alpha2.ts +360 -0
- package/e2e/crds/policyreports.default.expected/policyreport-v1beta1.ts +360 -0
- package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha1.ts +331 -0
- package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha2.ts +360 -0
- package/e2e/crds/policyreports.no.post.expected/policyreport-v1beta1.ts +360 -0
- package/e2e/crds/test.yaml/policyreports.test.yaml +1008 -0
- package/e2e/crds/test.yaml/uds-podmonitors.test.yaml +1245 -0
- package/e2e/crds/uds-podmonitors.default.expected/podmonitor-v1.ts +1333 -0
- package/e2e/crds/uds-podmonitors.no.post.expected/podmonitor-v1.ts +1360 -0
- package/package.json +6 -5
- package/src/cli.ts +25 -1
- package/src/fileSystem.test.ts +67 -0
- package/src/fileSystem.ts +25 -0
- package/src/fluent/watch.ts +174 -35
- package/src/generate.test.ts +368 -358
- package/src/generate.ts +173 -154
- package/src/postProcessing.test.ts +742 -0
- package/src/postProcessing.ts +568 -0
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
|
+
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { GenerateOptions } from "./generate";
|
|
7
|
+
import { GenericKind } from "./types";
|
|
8
|
+
import { CustomResourceDefinition } from "./upstream";
|
|
9
|
+
import { FileSystem, NodeFileSystem } from "./fileSystem";
|
|
10
|
+
|
|
11
|
+
type CRDResult = {
|
|
12
|
+
name: string;
|
|
13
|
+
crd: CustomResourceDefinition;
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type CodeLines = string[];
|
|
18
|
+
|
|
19
|
+
type ClassContextResult = { line: string; insideClass: boolean; braceBalance: number };
|
|
20
|
+
|
|
21
|
+
const genericKindProperties = getGenericKindProperties();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Performs post-processing on generated TypeScript files.
|
|
25
|
+
*
|
|
26
|
+
* @param allResults The array of CRD results.
|
|
27
|
+
* @param opts The options for post-processing.
|
|
28
|
+
* @param fileSystem The file system interface for reading and writing files.
|
|
29
|
+
*/
|
|
30
|
+
export async function postProcessing(
|
|
31
|
+
allResults: CRDResult[],
|
|
32
|
+
opts: GenerateOptions,
|
|
33
|
+
fileSystem: FileSystem = new NodeFileSystem(),
|
|
34
|
+
) {
|
|
35
|
+
if (!opts.directory) {
|
|
36
|
+
opts.logFn("⚠️ Error: Directory is not defined.");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const files = fileSystem.readdirSync(opts.directory);
|
|
41
|
+
opts.logFn("\n🔧 Post-processing started...");
|
|
42
|
+
|
|
43
|
+
const fileResultMap = mapFilesToCRD(allResults);
|
|
44
|
+
await processFiles(files, fileResultMap, opts, fileSystem);
|
|
45
|
+
|
|
46
|
+
opts.logFn("🔧 Post-processing completed.\n");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a map linking each file to its corresponding CRD result.
|
|
51
|
+
*
|
|
52
|
+
* @param allResults - The array of CRD results.
|
|
53
|
+
* @returns A map linking file names to their corresponding CRD results.
|
|
54
|
+
*/
|
|
55
|
+
export function mapFilesToCRD(allResults: CRDResult[]): Record<string, CRDResult> {
|
|
56
|
+
const fileResultMap: Record<string, CRDResult> = {};
|
|
57
|
+
|
|
58
|
+
for (const { name, crd, version } of allResults) {
|
|
59
|
+
const expectedFileName = `${name.toLowerCase()}-${version.toLowerCase()}.ts`;
|
|
60
|
+
fileResultMap[expectedFileName] = { name, crd, version };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (Object.keys(fileResultMap).length === 0) {
|
|
64
|
+
console.warn("⚠️ Warning: No CRD results were mapped to files.");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return fileResultMap;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Processes the list of files, applying CRD post-processing to each.
|
|
72
|
+
*
|
|
73
|
+
* @param files - The list of file names to process.
|
|
74
|
+
* @param fileResultMap - A map linking file names to their corresponding CRD results.
|
|
75
|
+
* @param opts - Options for the generation process.
|
|
76
|
+
* @param fileSystem - The file system interface for reading and writing files.
|
|
77
|
+
*/
|
|
78
|
+
export async function processFiles(
|
|
79
|
+
files: string[],
|
|
80
|
+
fileResultMap: Record<string, CRDResult>,
|
|
81
|
+
opts: GenerateOptions,
|
|
82
|
+
fileSystem: FileSystem,
|
|
83
|
+
) {
|
|
84
|
+
for (const file of files) {
|
|
85
|
+
if (!opts.directory) {
|
|
86
|
+
throw new Error("Directory is not defined.");
|
|
87
|
+
}
|
|
88
|
+
const filePath = path.join(opts.directory, file);
|
|
89
|
+
const fileResult = fileResultMap[file];
|
|
90
|
+
|
|
91
|
+
if (!fileResult) {
|
|
92
|
+
opts.logFn(`⚠️ Warning: No matching CRD result found for file: ${filePath}`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
processAndModifySingleFile(filePath, fileResult, opts, fileSystem);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logError(error, filePath, opts.logFn);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Handles the processing of a single file: reading, modifying, and writing back to disk.
|
|
106
|
+
*
|
|
107
|
+
* @param filePath - The path to the file to be processed.
|
|
108
|
+
* @param fileResult - The associated CRD result for this file.
|
|
109
|
+
* @param fileResult.name - The name of the schema.
|
|
110
|
+
* @param fileResult.crd - The CustomResourceDefinition object.
|
|
111
|
+
* @param fileResult.version - The version of the CRD.
|
|
112
|
+
* @param opts - Options for the generation process.
|
|
113
|
+
* @param fileSystem - The file system interface for reading and writing files.
|
|
114
|
+
*/
|
|
115
|
+
export function processAndModifySingleFile(
|
|
116
|
+
filePath: string,
|
|
117
|
+
fileResult: CRDResult,
|
|
118
|
+
opts: GenerateOptions,
|
|
119
|
+
fileSystem: FileSystem,
|
|
120
|
+
) {
|
|
121
|
+
opts.logFn(`🔍 Processing file: ${filePath}`);
|
|
122
|
+
const { name, crd, version } = fileResult;
|
|
123
|
+
|
|
124
|
+
let fileContent;
|
|
125
|
+
try {
|
|
126
|
+
fileContent = fileSystem.readFile(filePath);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
logError(error, filePath, opts.logFn);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let modifiedContent;
|
|
133
|
+
try {
|
|
134
|
+
modifiedContent = applyCRDPostProcessing(fileContent, name, crd, version, opts);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logError(error, filePath, opts.logFn);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
fileSystem.writeFile(filePath, modifiedContent);
|
|
142
|
+
opts.logFn(`✅ Successfully processed and wrote file: ${filePath}`);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
logError(error, filePath, opts.logFn);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Processes the TypeScript file content, applying wrapping and property modifications.
|
|
150
|
+
*
|
|
151
|
+
* @param content The content of the TypeScript file.
|
|
152
|
+
* @param name The name of the schema.
|
|
153
|
+
* @param crd The CustomResourceDefinition object.
|
|
154
|
+
* @param version The version of the CRD.
|
|
155
|
+
* @param opts The options for processing.
|
|
156
|
+
* @returns The processed TypeScript file content.
|
|
157
|
+
*/
|
|
158
|
+
export function applyCRDPostProcessing(
|
|
159
|
+
content: string,
|
|
160
|
+
name: string,
|
|
161
|
+
crd: CustomResourceDefinition,
|
|
162
|
+
version: string,
|
|
163
|
+
opts: GenerateOptions,
|
|
164
|
+
): string {
|
|
165
|
+
try {
|
|
166
|
+
let lines = content.split("\n");
|
|
167
|
+
|
|
168
|
+
// Wraps with the fluent client if needed
|
|
169
|
+
if (shouldWrapWithFluentClient(opts)) {
|
|
170
|
+
lines = wrapWithFluentClient(lines, name, crd, version, opts.npmPackage);
|
|
171
|
+
}
|
|
172
|
+
const foundInterfaces = collectInterfaceNames(lines);
|
|
173
|
+
|
|
174
|
+
// Process the lines, focusing on classes extending `GenericKind`
|
|
175
|
+
const processedLines = processLines(lines, genericKindProperties, foundInterfaces);
|
|
176
|
+
|
|
177
|
+
// Normalize the final output
|
|
178
|
+
const normalizedLines = normalizeIndentationAndSpacing(processedLines, opts);
|
|
179
|
+
|
|
180
|
+
return normalizedLines.join("\n");
|
|
181
|
+
} catch (error) {
|
|
182
|
+
throw new Error(`Error while applying post-processing for ${name}: ${error.message}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Reads the content of a file from disk.
|
|
188
|
+
*
|
|
189
|
+
* @param filePath The path to the file.
|
|
190
|
+
* @returns The file contents as a string.
|
|
191
|
+
*/
|
|
192
|
+
export function readFile(filePath: string): string {
|
|
193
|
+
try {
|
|
194
|
+
return fs.readFileSync(filePath, "utf8");
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw new Error(`Failed to read file at ${filePath}: ${error.message}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Writes the modified content back to the file.
|
|
202
|
+
*
|
|
203
|
+
* @param filePath The path to the file.
|
|
204
|
+
* @param content The modified content to write.
|
|
205
|
+
*/
|
|
206
|
+
export function writeFile(filePath: string, content: string): void {
|
|
207
|
+
try {
|
|
208
|
+
fs.writeFileSync(filePath, content, "utf8");
|
|
209
|
+
} catch (error) {
|
|
210
|
+
throw new Error(`Failed to write file at ${filePath}: ${error.message}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Retrieves the properties of the `GenericKind` class, excluding dynamic properties like `[key: string]: any`.
|
|
216
|
+
*
|
|
217
|
+
* @returns An array of property names that belong to `GenericKind`.
|
|
218
|
+
*/
|
|
219
|
+
export function getGenericKindProperties(): string[] {
|
|
220
|
+
const properties = Object.getOwnPropertyNames(new GenericKind());
|
|
221
|
+
return properties.filter(prop => prop !== "[key: string]");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Collects interface names from TypeScript file lines.
|
|
226
|
+
*
|
|
227
|
+
* @param lines The lines of the file content.
|
|
228
|
+
* @returns A set of found interface names.
|
|
229
|
+
*/
|
|
230
|
+
export function collectInterfaceNames(lines: CodeLines): Set<string> {
|
|
231
|
+
// https://regex101.com/r/S6w8pW/1
|
|
232
|
+
const interfacePattern = /export interface (?<interfaceName>\w+)/;
|
|
233
|
+
const foundInterfaces = new Set<string>();
|
|
234
|
+
|
|
235
|
+
for (const line of lines) {
|
|
236
|
+
const match = line.match(interfacePattern);
|
|
237
|
+
if (match?.groups?.interfaceName) {
|
|
238
|
+
foundInterfaces.add(match.groups.interfaceName);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return foundInterfaces;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Identifies whether a line declares a class that extends `GenericKind`.
|
|
247
|
+
*
|
|
248
|
+
* @param line The current line of code.
|
|
249
|
+
* @returns True if the line defines a class that extends `GenericKind`, false otherwise.
|
|
250
|
+
*/
|
|
251
|
+
export function isClassExtendingGenericKind(line: string): boolean {
|
|
252
|
+
return line.includes("class") && line.includes("extends GenericKind");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Adjusts the brace balance to determine if the parser is within a class definition.
|
|
257
|
+
*
|
|
258
|
+
* @param line The current line of code.
|
|
259
|
+
* @param braceBalance The current balance of curly braces.
|
|
260
|
+
* @returns The updated brace balance.
|
|
261
|
+
*/
|
|
262
|
+
export function updateBraceBalance(line: string, braceBalance: number): number {
|
|
263
|
+
return braceBalance + (line.includes("{") ? 1 : 0) - (line.includes("}") ? 1 : 0);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Generates a regular expression to match a property pattern in TypeScript.
|
|
268
|
+
*
|
|
269
|
+
* @param prop The property name to match.
|
|
270
|
+
* @returns A regular expression to match the property pattern.
|
|
271
|
+
*/
|
|
272
|
+
export function getPropertyPattern(prop: string): RegExp {
|
|
273
|
+
// For prop="kind", the pattern will match "kind ? :" or "kind :"
|
|
274
|
+
// https://regex101.com/r/mF8kXn/1
|
|
275
|
+
return new RegExp(`\\b${prop}\\b\\s*\\?\\s*:|\\b${prop}\\b\\s*:`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Applies ESLint and property modifiers to a line of code.
|
|
280
|
+
*
|
|
281
|
+
* @param line - The current line of code.
|
|
282
|
+
* @param genericKindProperties - The list of properties from `GenericKind`.
|
|
283
|
+
* @param foundInterfaces - The set of found interfaces in the file.
|
|
284
|
+
* @returns The modified line.
|
|
285
|
+
*/
|
|
286
|
+
export function modifyPropertiesAndAddEslintDirective(
|
|
287
|
+
line: string,
|
|
288
|
+
genericKindProperties: string[],
|
|
289
|
+
foundInterfaces: Set<string>,
|
|
290
|
+
): string {
|
|
291
|
+
line = addDeclareAndOptionalModifiersToProperties(line, genericKindProperties, foundInterfaces);
|
|
292
|
+
line = processEslintDisable(line, genericKindProperties);
|
|
293
|
+
return line;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Applies property modifiers to a line of code.
|
|
298
|
+
*
|
|
299
|
+
* @param line The current line of code.
|
|
300
|
+
* @param genericKindProperties The list of properties from `GenericKind`.
|
|
301
|
+
* @param foundInterfaces The set of found interfaces in the file.
|
|
302
|
+
* @returns The modified line.
|
|
303
|
+
*/
|
|
304
|
+
export function addDeclareAndOptionalModifiersToProperties(
|
|
305
|
+
line: string,
|
|
306
|
+
genericKindProperties: string[],
|
|
307
|
+
foundInterfaces: Set<string>,
|
|
308
|
+
): string {
|
|
309
|
+
line = addDeclareToGenericKindProperties(line, genericKindProperties);
|
|
310
|
+
line = makePropertiesOptional(line, foundInterfaces);
|
|
311
|
+
line = normalizeLineIndentation(line);
|
|
312
|
+
return line;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Adds the `declare` keyword to `GenericKind` properties.
|
|
316
|
+
*
|
|
317
|
+
* @param line The current line of code.
|
|
318
|
+
* @param genericKindProperties The list of properties from `GenericKind`.
|
|
319
|
+
* @returns The modified line with the `declare` keyword, if applicable.
|
|
320
|
+
*/
|
|
321
|
+
export function addDeclareToGenericKindProperties(
|
|
322
|
+
line: string,
|
|
323
|
+
genericKindProperties: string[],
|
|
324
|
+
): string {
|
|
325
|
+
for (const prop of genericKindProperties) {
|
|
326
|
+
const propertyPattern = getPropertyPattern(prop);
|
|
327
|
+
if (propertyPattern.test(line)) {
|
|
328
|
+
return line.replace(prop, `declare ${prop}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return line;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Makes a property optional if its type matches one of the found interfaces and it is not already optional.
|
|
336
|
+
*
|
|
337
|
+
* @param line The current line of code.
|
|
338
|
+
* @param foundInterfaces The set of found interfaces in the file.
|
|
339
|
+
* @returns The modified line with the optional `?` symbol.
|
|
340
|
+
*/
|
|
341
|
+
export function makePropertiesOptional(line: string, foundInterfaces: Set<string>): string {
|
|
342
|
+
// https://regex101.com/r/kX8TCj/1
|
|
343
|
+
const propertyTypePattern = /:\s*(?<propertyType>\w+)\s*;/;
|
|
344
|
+
const match = line.match(propertyTypePattern);
|
|
345
|
+
|
|
346
|
+
if (match?.groups?.propertyType) {
|
|
347
|
+
const { propertyType } = match.groups;
|
|
348
|
+
if (foundInterfaces.has(propertyType) && !line.includes("?")) {
|
|
349
|
+
return line.replace(":", "?:");
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return line;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Adds an ESLint disable comment for `[key: string]: any` if it's not part of `GenericKind`.
|
|
357
|
+
*
|
|
358
|
+
* @param line The current line of code.
|
|
359
|
+
* @param genericKindProperties The list of properties from `GenericKind`.
|
|
360
|
+
* @returns The modified line with the ESLint disable comment.
|
|
361
|
+
*/
|
|
362
|
+
export function processEslintDisable(line: string, genericKindProperties: string[]): string {
|
|
363
|
+
if (line.includes("[key: string]: any") && !genericKindProperties.includes("[key: string]")) {
|
|
364
|
+
return ` // eslint-disable-next-line @typescript-eslint/no-explicit-any\n${line}`;
|
|
365
|
+
}
|
|
366
|
+
return line;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Wraps the generated TypeScript file with fluent client elements (`GenericKind` and `RegisterKind`).
|
|
371
|
+
*
|
|
372
|
+
* @param lines The generated TypeScript lines.
|
|
373
|
+
* @param name The name of the schema.
|
|
374
|
+
* @param crd The CustomResourceDefinition object.
|
|
375
|
+
* @param version The version of the CRD.
|
|
376
|
+
* @param npmPackage The NPM package name for the fluent client.
|
|
377
|
+
* @returns The processed TypeScript lines.
|
|
378
|
+
*/
|
|
379
|
+
export function wrapWithFluentClient(
|
|
380
|
+
lines: CodeLines,
|
|
381
|
+
name: string,
|
|
382
|
+
crd: CustomResourceDefinition,
|
|
383
|
+
version: string,
|
|
384
|
+
npmPackage: string = "kubernetes-fluent-client",
|
|
385
|
+
): string[] {
|
|
386
|
+
const autoGenNotice = `// This file is auto-generated by ${npmPackage}, do not edit manually`;
|
|
387
|
+
const imports = `import { GenericKind, RegisterKind } from "${npmPackage}";`;
|
|
388
|
+
|
|
389
|
+
const classIndex = lines.findIndex(line => line.includes(`export interface ${name} {`));
|
|
390
|
+
if (classIndex !== -1) {
|
|
391
|
+
lines[classIndex] = `export class ${name} extends GenericKind {`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
lines.unshift(autoGenNotice, imports);
|
|
395
|
+
lines.push(
|
|
396
|
+
`RegisterKind(${name}, {`,
|
|
397
|
+
` group: "${crd.spec.group}",`,
|
|
398
|
+
` version: "${version}",`,
|
|
399
|
+
` kind: "${name}",`,
|
|
400
|
+
` plural: "${crd.spec.names.plural}",`,
|
|
401
|
+
`});`,
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
return lines;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Normalizes indentation for TypeScript lines to a consistent format.
|
|
409
|
+
*
|
|
410
|
+
* @param lines The generated TypeScript lines.
|
|
411
|
+
* @returns The lines with normalized indentation.
|
|
412
|
+
*/
|
|
413
|
+
export function normalizeIndentation(lines: CodeLines): string[] {
|
|
414
|
+
return lines.map(line => line.replace(/^ {4}/, " "));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Normalizes the indentation of a single line to use two spaces instead of four.
|
|
419
|
+
*
|
|
420
|
+
* @param line The line of code to normalize.
|
|
421
|
+
* @returns The line with normalized indentation.
|
|
422
|
+
*/
|
|
423
|
+
export function normalizeLineIndentation(line: string): string {
|
|
424
|
+
return line.replace(/^ {4}/, " ");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Normalizes spacing between property names and types in TypeScript lines.
|
|
429
|
+
*
|
|
430
|
+
* @param lines The generated TypeScript lines.
|
|
431
|
+
* @returns The lines with normalized property spacing.
|
|
432
|
+
*/
|
|
433
|
+
export function normalizePropertySpacing(lines: CodeLines): string[] {
|
|
434
|
+
// https://regex101.com/r/XEv3pL/1
|
|
435
|
+
return lines.map(line => line.replace(/\s*\?\s*:\s*/, "?: "));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Removes lines containing `[property: string]: any;` from TypeScript files.
|
|
440
|
+
*
|
|
441
|
+
* @param lines The generated TypeScript lines.
|
|
442
|
+
* @param opts The options for processing.
|
|
443
|
+
* @returns The lines with `[property: string]: any;` removed.
|
|
444
|
+
*/
|
|
445
|
+
export function removePropertyStringAny(lines: CodeLines, opts: GenerateOptions): string[] {
|
|
446
|
+
if (opts.language === "ts" || opts.language === "typescript") {
|
|
447
|
+
return lines.filter(line => !line.includes("[property: string]: any;"));
|
|
448
|
+
}
|
|
449
|
+
return lines;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Determines if the content should be wrapped with the fluent client.
|
|
454
|
+
*
|
|
455
|
+
* @param opts The options for generating the content.
|
|
456
|
+
* @returns True if the content should be wrapped with the fluent client, false otherwise.
|
|
457
|
+
*/
|
|
458
|
+
export function shouldWrapWithFluentClient(opts: GenerateOptions): boolean {
|
|
459
|
+
return opts.language === "ts" && !opts.plain;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Processes the lines of the TypeScript file, focusing on classes extending `GenericKind`.
|
|
464
|
+
*
|
|
465
|
+
* @param lines The lines of the file content.
|
|
466
|
+
* @param genericKindProperties The list of properties from `GenericKind`.
|
|
467
|
+
* @param foundInterfaces The set of found interfaces in the file.
|
|
468
|
+
* @returns The processed lines.
|
|
469
|
+
*/
|
|
470
|
+
export function processLines(
|
|
471
|
+
lines: CodeLines,
|
|
472
|
+
genericKindProperties: string[],
|
|
473
|
+
foundInterfaces: Set<string>,
|
|
474
|
+
): string[] {
|
|
475
|
+
let insideClass = false;
|
|
476
|
+
let braceBalance = 0;
|
|
477
|
+
|
|
478
|
+
return lines.map(line => {
|
|
479
|
+
const result = processClassContext(
|
|
480
|
+
line,
|
|
481
|
+
insideClass,
|
|
482
|
+
braceBalance,
|
|
483
|
+
genericKindProperties,
|
|
484
|
+
foundInterfaces,
|
|
485
|
+
);
|
|
486
|
+
insideClass = result.insideClass;
|
|
487
|
+
braceBalance = result.braceBalance;
|
|
488
|
+
|
|
489
|
+
return result.line;
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Processes a single line inside a class extending `GenericKind`.
|
|
495
|
+
*
|
|
496
|
+
* @param line The current line of code.
|
|
497
|
+
* @param insideClass Whether we are inside a class context.
|
|
498
|
+
* @param braceBalance The current brace balance to detect when we exit the class.
|
|
499
|
+
* @param genericKindProperties The list of properties from `GenericKind`.
|
|
500
|
+
* @param foundInterfaces The set of found interfaces in the file.
|
|
501
|
+
* @returns An object containing the updated line, updated insideClass flag, and braceBalance.
|
|
502
|
+
*/
|
|
503
|
+
export function processClassContext(
|
|
504
|
+
line: string,
|
|
505
|
+
insideClass: boolean,
|
|
506
|
+
braceBalance: number,
|
|
507
|
+
genericKindProperties: string[],
|
|
508
|
+
foundInterfaces: Set<string>,
|
|
509
|
+
): ClassContextResult {
|
|
510
|
+
if (isClassExtendingGenericKind(line)) {
|
|
511
|
+
insideClass = true;
|
|
512
|
+
braceBalance = 0;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (!insideClass) return { line, insideClass, braceBalance };
|
|
516
|
+
|
|
517
|
+
braceBalance = updateBraceBalance(line, braceBalance);
|
|
518
|
+
line = modifyAndNormalizeClassProperties(line, genericKindProperties, foundInterfaces);
|
|
519
|
+
|
|
520
|
+
if (braceBalance === 0) {
|
|
521
|
+
insideClass = false;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return { line, insideClass, braceBalance };
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Processes a single line inside a class extending `GenericKind`.
|
|
529
|
+
*
|
|
530
|
+
* @param line The current line of code.
|
|
531
|
+
* @param genericKindProperties The list of properties from `GenericKind`.
|
|
532
|
+
* @param foundInterfaces The set of found interfaces in the file.
|
|
533
|
+
* @returns The modified line.
|
|
534
|
+
*/
|
|
535
|
+
export function modifyAndNormalizeClassProperties(
|
|
536
|
+
line: string,
|
|
537
|
+
genericKindProperties: string[],
|
|
538
|
+
foundInterfaces: Set<string>,
|
|
539
|
+
): string {
|
|
540
|
+
line = modifyPropertiesAndAddEslintDirective(line, genericKindProperties, foundInterfaces);
|
|
541
|
+
line = normalizeLineIndentation(line);
|
|
542
|
+
return line;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Normalizes lines after processing, including indentation, spacing, and removing unnecessary lines.
|
|
547
|
+
*
|
|
548
|
+
* @param lines The lines of the file content.
|
|
549
|
+
* @param opts The options for processing.
|
|
550
|
+
* @returns The normalized lines.
|
|
551
|
+
*/
|
|
552
|
+
export function normalizeIndentationAndSpacing(lines: CodeLines, opts: GenerateOptions): string[] {
|
|
553
|
+
let normalizedLines = normalizeIndentation(lines);
|
|
554
|
+
normalizedLines = normalizePropertySpacing(normalizedLines);
|
|
555
|
+
return removePropertyStringAny(normalizedLines, opts);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Handles logging for errors with stack trace.
|
|
560
|
+
*
|
|
561
|
+
* @param error The error object to log.
|
|
562
|
+
* @param filePath The path of the file being processed.
|
|
563
|
+
* @param logFn The logging function.
|
|
564
|
+
*/
|
|
565
|
+
export function logError(error: Error, filePath: string, logFn: (msg: string) => void) {
|
|
566
|
+
logFn(`❌ Error processing file: ${filePath} - ${error.message}`);
|
|
567
|
+
logFn(`Stack trace: ${error.stack}`);
|
|
568
|
+
}
|