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.
Files changed (42) hide show
  1. package/.prettierignore +4 -0
  2. package/README.md +24 -0
  3. package/dist/cli.js +21 -1
  4. package/dist/fileSystem.d.ts +11 -0
  5. package/dist/fileSystem.d.ts.map +1 -0
  6. package/dist/fileSystem.js +42 -0
  7. package/dist/fileSystem.test.d.ts +2 -0
  8. package/dist/fileSystem.test.d.ts.map +1 -0
  9. package/dist/fileSystem.test.js +75 -0
  10. package/dist/fluent/watch.d.ts +2 -0
  11. package/dist/fluent/watch.d.ts.map +1 -1
  12. package/dist/fluent/watch.js +147 -27
  13. package/dist/generate.d.ts +71 -11
  14. package/dist/generate.d.ts.map +1 -1
  15. package/dist/generate.js +130 -117
  16. package/dist/generate.test.js +293 -346
  17. package/dist/postProcessing.d.ts +246 -0
  18. package/dist/postProcessing.d.ts.map +1 -0
  19. package/dist/postProcessing.js +497 -0
  20. package/dist/postProcessing.test.d.ts +2 -0
  21. package/dist/postProcessing.test.d.ts.map +1 -0
  22. package/dist/postProcessing.test.js +550 -0
  23. package/e2e/cli.e2e.test.ts +127 -0
  24. package/e2e/crds/policyreports.default.expected/policyreport-v1alpha1.ts +332 -0
  25. package/e2e/crds/policyreports.default.expected/policyreport-v1alpha2.ts +360 -0
  26. package/e2e/crds/policyreports.default.expected/policyreport-v1beta1.ts +360 -0
  27. package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha1.ts +331 -0
  28. package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha2.ts +360 -0
  29. package/e2e/crds/policyreports.no.post.expected/policyreport-v1beta1.ts +360 -0
  30. package/e2e/crds/test.yaml/policyreports.test.yaml +1008 -0
  31. package/e2e/crds/test.yaml/uds-podmonitors.test.yaml +1245 -0
  32. package/e2e/crds/uds-podmonitors.default.expected/podmonitor-v1.ts +1333 -0
  33. package/e2e/crds/uds-podmonitors.no.post.expected/podmonitor-v1.ts +1360 -0
  34. package/package.json +6 -5
  35. package/src/cli.ts +25 -1
  36. package/src/fileSystem.test.ts +67 -0
  37. package/src/fileSystem.ts +25 -0
  38. package/src/fluent/watch.ts +174 -35
  39. package/src/generate.test.ts +368 -358
  40. package/src/generate.ts +173 -154
  41. package/src/postProcessing.test.ts +742 -0
  42. package/src/postProcessing.ts +568 -0
package/dist/generate.js CHANGED
@@ -25,6 +25,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  return result;
26
26
  };
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.convertCRDtoTS = convertCRDtoTS;
29
+ exports.prepareInputData = prepareInputData;
30
+ exports.generateTypes = generateTypes;
31
+ exports.writeGeneratedFile = writeGeneratedFile;
32
+ exports.readOrFetchCrd = readOrFetchCrd;
33
+ exports.resolveFilePath = resolveFilePath;
34
+ exports.tryParseUrl = tryParseUrl;
28
35
  exports.generate = generate;
29
36
  const client_node_1 = require("@kubernetes/client-node");
30
37
  const fs = __importStar(require("fs"));
@@ -36,144 +43,150 @@ const upstream_1 = require("./upstream");
36
43
  /**
37
44
  * Converts a CustomResourceDefinition to TypeScript types
38
45
  *
39
- * @param crd The CustomResourceDefinition to convert
40
- * @param opts The options to use when converting
41
- * @returns A promise that resolves when the CustomResourceDefinition has been converted
46
+ * @param crd - The CustomResourceDefinition object to convert.
47
+ * @param opts - The options for generating the TypeScript types.
48
+ * @returns A promise that resolves to a record of generated TypeScript types.
42
49
  */
43
50
  async function convertCRDtoTS(crd, opts) {
44
- // Get the name of the kind
45
51
  const name = crd.spec.names.kind;
46
52
  const results = {};
53
+ const output = [];
54
+ // Check for missing versions or empty schema
55
+ if (!crd.spec.versions || crd.spec.versions.length === 0) {
56
+ opts.logFn(`Skipping ${crd.metadata?.name}, it does not appear to be a CRD`);
57
+ return [];
58
+ }
59
+ // Iterate through each version of the CRD
47
60
  for (const match of crd.spec.versions) {
48
- const version = match.name;
49
- // Get the schema from the matched version
50
- const schema = JSON.stringify(match?.schema?.openAPIV3Schema);
51
- // Create a new JSONSchemaInput
52
- const schemaInput = new quicktype_core_1.JSONSchemaInput(new quicktype_core_1.FetchingJSONSchemaStore());
53
- opts.logFn(`- Generating ${crd.spec.group}/${version} types for ${name}`);
54
- // Add the schema to the input
55
- await schemaInput.addSource({ name, schema });
56
- // Create a new InputData object
57
- const inputData = new quicktype_core_1.InputData();
58
- inputData.addInput(schemaInput);
59
- // If the language is not specified, default to TypeScript
60
- if (!opts.language) {
61
- opts.language = "ts";
62
- }
63
- // Generate the types
64
- const out = await (0, quicktype_core_1.quicktype)({
65
- inputData,
66
- lang: opts.language,
67
- rendererOptions: { "just-types": "true" },
68
- });
69
- let processedLines = out.lines;
70
- // If using typescript, remove the line containing `[property: string]: any;`
71
- if (opts.language === "ts" || opts.language === "typescript") {
72
- processedLines = out.lines.filter(line => !line.includes("[property: string]: any;"));
73
- }
74
- // If the language is TypeScript and plain is not specified, wire up the fluent client
75
- if (opts.language === "ts" && !opts.plain) {
76
- if (!opts.npmPackage) {
77
- opts.npmPackage = "kubernetes-fluent-client";
78
- }
79
- processedLines.unshift(
80
- // Add warning that the file is auto-generated
81
- `// This file is auto-generated by ${opts.npmPackage}, do not edit manually\n`,
82
- // Add the imports before any other lines
83
- `import { GenericKind, RegisterKind } from "${opts.npmPackage}";\n`);
84
- // Replace the interface with a named class that extends GenericKind
85
- const entryIdx = processedLines.findIndex(line => line.includes(`export interface ${name} {`));
86
- // Replace the interface with a named class that extends GenericKind
87
- processedLines[entryIdx] = `export class ${name} extends GenericKind {`;
88
- // Add the RegisterKind call
89
- processedLines.push(`RegisterKind(${name}, {`);
90
- processedLines.push(` group: "${crd.spec.group}",`);
91
- processedLines.push(` version: "${version}",`);
92
- processedLines.push(` kind: "${name}",`);
93
- processedLines.push(` plural: "${crd.spec.names.plural}",`);
94
- processedLines.push(`});`);
95
- }
96
- const finalContents = processedLines.join("\n");
97
- const fileName = `${name.toLowerCase()}-${version.toLowerCase()}`;
98
- // If an output file is specified, write the output to the file
99
- if (opts.directory) {
100
- // Create the directory if it doesn't exist
101
- fs.mkdirSync(opts.directory, { recursive: true });
102
- // Write the file
103
- const filePath = path.join(opts.directory, `${fileName}.${opts.language}`);
104
- fs.writeFileSync(filePath, finalContents);
61
+ if (!match.schema?.openAPIV3Schema) {
62
+ opts.logFn(`Skipping ${crd.metadata?.name ?? "unknown"}, it does not appear to have a valid schema`);
63
+ continue;
105
64
  }
106
- // Add the results to the array
107
- results[fileName] = processedLines;
65
+ const schema = JSON.stringify(match.schema.openAPIV3Schema);
66
+ opts.logFn(`- Generating ${crd.spec.group}/${match.name} types for ${name}`);
67
+ const inputData = await prepareInputData(name, schema);
68
+ const generatedTypes = await generateTypes(inputData, opts);
69
+ const fileName = `${name.toLowerCase()}-${match.name.toLowerCase()}`;
70
+ writeGeneratedFile(fileName, opts.directory || "", generatedTypes, opts.language || "ts");
71
+ results[fileName] = generatedTypes;
72
+ output.push({ results, name, crd, version: match.name });
108
73
  }
109
- return results;
74
+ return output;
75
+ }
76
+ /**
77
+ * Prepares the input data for quicktype from the provided schema.
78
+ *
79
+ * @param name - The name of the schema.
80
+ * @param schema - The JSON schema as a string.
81
+ * @returns A promise that resolves to the input data for quicktype.
82
+ */
83
+ async function prepareInputData(name, schema) {
84
+ // Create a new JSONSchemaInput
85
+ const schemaInput = new quicktype_core_1.JSONSchemaInput(new quicktype_core_1.FetchingJSONSchemaStore());
86
+ // Add the schema to the input
87
+ await schemaInput.addSource({ name, schema });
88
+ // Create a new InputData object
89
+ const inputData = new quicktype_core_1.InputData();
90
+ inputData.addInput(schemaInput);
91
+ return inputData;
110
92
  }
111
93
  /**
112
- * Reads a CustomResourceDefinition from a file, the cluster or the internet
94
+ * Generates TypeScript types using quicktype.
113
95
  *
114
- * @param opts The options to use when reading
115
- * @returns A promise that resolves when the CustomResourceDefinition has been read
96
+ * @param inputData - The input data for quicktype.
97
+ * @param opts - The options for generating the TypeScript types.
98
+ * @returns A promise that resolves to an array of generated TypeScript type lines.
99
+ */
100
+ async function generateTypes(inputData, opts) {
101
+ // If the language is not specified, default to TypeScript
102
+ const language = opts.language || "ts";
103
+ // Generate the types
104
+ const out = await (0, quicktype_core_1.quicktype)({
105
+ inputData,
106
+ lang: language,
107
+ rendererOptions: { "just-types": "true" },
108
+ });
109
+ return out.lines;
110
+ }
111
+ /**
112
+ * Writes the processed lines to the output file.
113
+ *
114
+ * @param fileName - The name of the file to write.
115
+ * @param directory - The directory where the file will be written.
116
+ * @param content - The content to write to the file.
117
+ * @param language - The programming language of the file.
118
+ */
119
+ function writeGeneratedFile(fileName, directory, content, language) {
120
+ language = language || "ts";
121
+ if (!directory)
122
+ return;
123
+ const filePath = path.join(directory, `${fileName}.${language}`);
124
+ fs.mkdirSync(directory, { recursive: true });
125
+ fs.writeFileSync(filePath, content.join("\n"));
126
+ }
127
+ /**
128
+ * Reads or fetches a CustomResourceDefinition from a file, URL, or the cluster.
129
+ *
130
+ * @param opts - The options for generating the TypeScript types.
131
+ * @returns A promise that resolves to an array of CustomResourceDefinition objects.
116
132
  */
117
133
  async function readOrFetchCrd(opts) {
118
- const { source, logFn } = opts;
119
- let filePath;
120
- if (source[0] === "/") {
121
- // If source is an absolute path
122
- filePath = source;
123
- }
124
- else {
125
- // If source is a relative path
126
- filePath = path.join(process.cwd(), source);
127
- }
128
- // First try to read the source as a file
129
134
  try {
135
+ const filePath = resolveFilePath(opts.source);
130
136
  if (fs.existsSync(filePath)) {
131
- logFn(`Attempting to load ${source} as a local file`);
132
- const payload = fs.readFileSync(filePath, "utf8");
133
- return (0, client_node_1.loadAllYaml)(payload);
137
+ opts.logFn(`Attempting to load ${opts.source} as a local file`);
138
+ const content = fs.readFileSync(filePath, "utf8");
139
+ return (0, client_node_1.loadAllYaml)(content);
134
140
  }
135
- }
136
- catch {
137
- // Ignore errors
138
- }
139
- // Next try to parse the source as a URL
140
- try {
141
- const url = new URL(source);
142
- // If the source is a URL, fetch it
143
- if (url.protocol === "http:" || url.protocol === "https:") {
144
- logFn(`Attempting to load ${source} as a URL`);
145
- const { ok, data } = await (0, fetch_1.fetch)(source);
146
- // If the request failed, throw an error
147
- if (!ok) {
148
- throw new Error(`Failed to fetch ${source}: ${data}`);
141
+ const url = tryParseUrl(opts.source);
142
+ if (url) {
143
+ opts.logFn(`Attempting to load ${opts.source} as a URL`);
144
+ const { ok, data } = await (0, fetch_1.fetch)(url.href);
145
+ if (ok) {
146
+ return (0, client_node_1.loadAllYaml)(data);
149
147
  }
150
- return (0, client_node_1.loadAllYaml)(data);
151
148
  }
149
+ // Fallback to Kubernetes cluster
150
+ opts.logFn(`Attempting to read ${opts.source} from the Kubernetes cluster`);
151
+ return [await (0, fluent_1.K8s)(upstream_1.CustomResourceDefinition).Get(opts.source)];
152
152
  }
153
- catch (e) {
154
- // If invalid, ignore the error
155
- if (e.code !== "ERR_INVALID_URL") {
156
- throw new Error(`Error parsing URL ${source}`);
157
- }
153
+ catch (error) {
154
+ opts.logFn(`Error loading CRD: ${error.message}`);
155
+ throw new Error(`Failed to read ${opts.source} as a file, URL, or Kubernetes CRD`);
158
156
  }
159
- // Finally, if the source is not a file or URL, try to read it as a CustomResourceDefinition from the cluster
157
+ }
158
+ /**
159
+ * Resolves the source file path, treating relative paths as local files.
160
+ *
161
+ * @param source - The source path to resolve.
162
+ * @returns The resolved file path.
163
+ */
164
+ function resolveFilePath(source) {
165
+ return source.startsWith("/") ? source : path.join(process.cwd(), source);
166
+ }
167
+ /**
168
+ * Tries to parse the source as a URL.
169
+ *
170
+ * @param source - The source string to parse as a URL.
171
+ * @returns The parsed URL object or null if parsing fails.
172
+ */
173
+ function tryParseUrl(source) {
160
174
  try {
161
- logFn(`Attempting to read ${source} from the current Kubernetes context`);
162
- return [await (0, fluent_1.K8s)(upstream_1.CustomResourceDefinition).Get(source)];
175
+ return new URL(source);
163
176
  }
164
- catch (e) {
165
- throw new Error(`Failed to read ${source} as a file, url or K8s CRD: ${e.data?.message || "Cluster not available"}`);
177
+ catch {
178
+ return null;
166
179
  }
167
180
  }
168
181
  /**
169
- * Generate TypeScript types from a K8s CRD
182
+ * Main generate function to convert CRDs to TypeScript types.
170
183
  *
171
- * @param opts The options to use when generating
172
- * @returns A promise that resolves when the TypeScript types have been generated
184
+ * @param opts - The options for generating the TypeScript types.
185
+ * @returns A promise that resolves to a record of generated TypeScript types.
173
186
  */
174
187
  async function generate(opts) {
175
188
  const crds = (await readOrFetchCrd(opts)).filter(crd => !!crd);
176
- const results = {};
189
+ const allResults = [];
177
190
  opts.logFn("");
178
191
  for (const crd of crds) {
179
192
  if (crd.kind !== "CustomResourceDefinition" || !crd.spec?.versions?.length) {
@@ -181,15 +194,15 @@ async function generate(opts) {
181
194
  // Ignore empty and non-CRD objects
182
195
  continue;
183
196
  }
184
- // Add the results to the record
185
- const out = await convertCRDtoTS(crd, opts);
186
- for (const key of Object.keys(out)) {
187
- results[key] = out[key];
188
- }
197
+ allResults.push(...(await convertCRDtoTS(crd, opts)));
189
198
  }
190
199
  if (opts.directory) {
191
200
  // Notify the user that the files have been generated
192
- opts.logFn(`\n✅ Generated ${Object.keys(results).length} files in the ${opts.directory} directory`);
201
+ opts.logFn(`\n✅ Generated ${allResults.length} files in the ${opts.directory} directory`);
202
+ }
203
+ else {
204
+ // Log a message about the number of generated files even when no directory is provided
205
+ opts.logFn(`\n✅ Generated ${allResults.length} files`);
193
206
  }
194
- return results;
207
+ return allResults;
195
208
  }