kubernetes-fluent-client 3.0.5 → 3.1.1

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 (78) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +68 -0
  4. package/dist/fetch.d.ts +22 -0
  5. package/dist/fetch.d.ts.map +1 -0
  6. package/dist/fetch.js +82 -0
  7. package/dist/fetch.test.d.ts +2 -0
  8. package/dist/fetch.test.d.ts.map +1 -0
  9. package/dist/fetch.test.js +97 -0
  10. package/dist/fileSystem.d.ts +11 -0
  11. package/dist/fileSystem.d.ts.map +1 -0
  12. package/dist/fileSystem.js +42 -0
  13. package/dist/fileSystem.test.d.ts +2 -0
  14. package/dist/fileSystem.test.d.ts.map +1 -0
  15. package/dist/fileSystem.test.js +75 -0
  16. package/dist/fluent/http2-watch.spec.d.ts +2 -0
  17. package/dist/fluent/http2-watch.spec.d.ts.map +1 -0
  18. package/dist/fluent/http2-watch.spec.js +284 -0
  19. package/dist/fluent/index.d.ts +12 -0
  20. package/dist/fluent/index.d.ts.map +1 -0
  21. package/dist/fluent/index.js +228 -0
  22. package/dist/fluent/index.test.d.ts +2 -0
  23. package/dist/fluent/index.test.d.ts.map +1 -0
  24. package/dist/fluent/index.test.js +193 -0
  25. package/dist/fluent/types.d.ts +187 -0
  26. package/dist/fluent/types.d.ts.map +1 -0
  27. package/dist/fluent/types.js +16 -0
  28. package/dist/fluent/utils.d.ts +41 -0
  29. package/dist/fluent/utils.d.ts.map +1 -0
  30. package/dist/fluent/utils.js +153 -0
  31. package/dist/fluent/utils.test.d.ts +2 -0
  32. package/dist/fluent/utils.test.d.ts.map +1 -0
  33. package/dist/fluent/utils.test.js +215 -0
  34. package/dist/fluent/watch.d.ts +88 -0
  35. package/dist/fluent/watch.d.ts.map +1 -0
  36. package/dist/fluent/watch.js +546 -0
  37. package/dist/fluent/watch.spec.d.ts +2 -0
  38. package/dist/fluent/watch.spec.d.ts.map +1 -0
  39. package/dist/fluent/watch.spec.js +261 -0
  40. package/dist/generate.d.ts +84 -0
  41. package/dist/generate.d.ts.map +1 -0
  42. package/dist/generate.js +208 -0
  43. package/dist/generate.test.d.ts +2 -0
  44. package/dist/generate.test.d.ts.map +1 -0
  45. package/dist/generate.test.js +320 -0
  46. package/dist/helpers.d.ts +33 -0
  47. package/dist/helpers.d.ts.map +1 -0
  48. package/dist/helpers.js +103 -0
  49. package/dist/helpers.test.d.ts +2 -0
  50. package/dist/helpers.test.d.ts.map +1 -0
  51. package/dist/helpers.test.js +37 -0
  52. package/dist/index.d.ts +14 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +60 -0
  55. package/dist/kinds.d.ts +16 -0
  56. package/dist/kinds.d.ts.map +1 -0
  57. package/dist/kinds.js +570 -0
  58. package/dist/kinds.test.d.ts +2 -0
  59. package/dist/kinds.test.d.ts.map +1 -0
  60. package/dist/kinds.test.js +155 -0
  61. package/dist/patch.d.ts +7 -0
  62. package/dist/patch.d.ts.map +1 -0
  63. package/dist/patch.js +2 -0
  64. package/dist/postProcessing.d.ts +246 -0
  65. package/dist/postProcessing.d.ts.map +1 -0
  66. package/dist/postProcessing.js +497 -0
  67. package/dist/postProcessing.test.d.ts +2 -0
  68. package/dist/postProcessing.test.d.ts.map +1 -0
  69. package/dist/postProcessing.test.js +550 -0
  70. package/dist/types.d.ts +32 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +16 -0
  73. package/dist/upstream.d.ts +4 -0
  74. package/dist/upstream.d.ts.map +1 -0
  75. package/dist/upstream.js +56 -0
  76. package/package.json +1 -1
  77. package/src/fluent/http2-watch.spec.ts +335 -0
  78. package/src/fluent/watch.ts +174 -35
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const globals_1 = require("@jest/globals");
8
+ const nock_1 = __importDefault(require("nock"));
9
+ const readable_stream_1 = require("readable-stream");
10
+ const _1 = require(".");
11
+ const __1 = require("..");
12
+ const types_1 = require("./types");
13
+ (0, globals_1.describe)("Watcher", () => {
14
+ const evtMock = globals_1.jest.fn();
15
+ const errMock = globals_1.jest.fn();
16
+ const setupAndStartWatcher = (eventType, handler) => {
17
+ watcher.events.on(eventType, handler);
18
+ watcher.start().catch(errMock);
19
+ };
20
+ let watcher;
21
+ (0, globals_1.beforeEach)(() => {
22
+ globals_1.jest.resetAllMocks();
23
+ (0, nock_1.default)("http://jest-test:8080")
24
+ .get("/api/v1/pods")
25
+ .reply(200, {
26
+ kind: "PodList",
27
+ apiVersion: "v1",
28
+ metadata: {
29
+ resourceVersion: "10",
30
+ },
31
+ items: [createMockPod(`pod-0`, `1`)],
32
+ });
33
+ (0, nock_1.default)("http://jest-test:8080")
34
+ .get("/api/v1/pods")
35
+ .query({ watch: "true", resourceVersion: "10" })
36
+ .reply(200, () => {
37
+ const stream = new readable_stream_1.PassThrough();
38
+ const resources = [
39
+ { type: "ADDED", object: createMockPod(`pod-0`, `1`) },
40
+ { type: "MODIFIED", object: createMockPod(`pod-0`, `2`) },
41
+ ];
42
+ resources.forEach(resource => {
43
+ stream.write(JSON.stringify(resource) + "\n");
44
+ });
45
+ stream.end();
46
+ return stream;
47
+ });
48
+ });
49
+ (0, globals_1.afterEach)(() => {
50
+ watcher.close();
51
+ });
52
+ (0, globals_1.it)("should watch named resources", done => {
53
+ nock_1.default.cleanAll();
54
+ (0, nock_1.default)("http://jest-test:8080")
55
+ .get("/api/v1/namespaces/tester/pods")
56
+ .query({ fieldSelector: "metadata.name=demo" })
57
+ .reply(200, createMockPod(`demo`, `15`));
58
+ (0, nock_1.default)("http://jest-test:8080")
59
+ .get("/api/v1/namespaces/tester/pods")
60
+ .query({
61
+ watch: "true",
62
+ fieldSelector: "metadata.name=demo",
63
+ resourceVersion: "15",
64
+ })
65
+ .reply(200);
66
+ watcher = (0, _1.K8s)(__1.kind.Pod, { name: "demo" }).InNamespace("tester").Watch(evtMock);
67
+ setupAndStartWatcher(__1.WatchEvent.CONNECT, () => {
68
+ done();
69
+ });
70
+ });
71
+ (0, globals_1.it)("should handle resource version is too old", done => {
72
+ nock_1.default.cleanAll();
73
+ (0, nock_1.default)("http://jest-test:8080")
74
+ .get("/api/v1/pods")
75
+ .reply(200, {
76
+ kind: "PodList",
77
+ apiVersion: "v1",
78
+ metadata: {
79
+ resourceVersion: "25",
80
+ },
81
+ items: [createMockPod(`pod-0`, `1`)],
82
+ });
83
+ (0, nock_1.default)("http://jest-test:8080")
84
+ .get("/api/v1/pods")
85
+ .query({ watch: "true", resourceVersion: "25" })
86
+ .reply(200, () => {
87
+ const stream = new readable_stream_1.PassThrough();
88
+ stream.write(JSON.stringify({
89
+ type: "ERROR",
90
+ object: {
91
+ kind: "Status",
92
+ apiVersion: "v1",
93
+ metadata: {},
94
+ status: "Failure",
95
+ message: "too old resource version: 123 (391079)",
96
+ reason: "Gone",
97
+ code: 410,
98
+ },
99
+ }) + "\n");
100
+ stream.end();
101
+ return stream;
102
+ });
103
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock);
104
+ setupAndStartWatcher(__1.WatchEvent.OLD_RESOURCE_VERSION, res => {
105
+ (0, globals_1.expect)(res).toEqual("25");
106
+ done();
107
+ });
108
+ });
109
+ (0, globals_1.it)("should call the event handler for each event", done => {
110
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch((evt, phase) => {
111
+ (0, globals_1.expect)(evt.metadata?.name).toEqual(`pod-0`);
112
+ (0, globals_1.expect)(phase).toEqual(types_1.WatchPhase.Added);
113
+ done();
114
+ });
115
+ watcher.start().catch(errMock);
116
+ });
117
+ (0, globals_1.it)("should return the cache id", () => {
118
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
119
+ resyncDelaySec: 1,
120
+ });
121
+ (0, globals_1.expect)(watcher.getCacheID()).toEqual("d69b75a611");
122
+ });
123
+ (0, globals_1.it)("should handle the CONNECT event", done => {
124
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
125
+ resyncDelaySec: 1,
126
+ });
127
+ setupAndStartWatcher(__1.WatchEvent.CONNECT, () => {
128
+ done();
129
+ });
130
+ });
131
+ (0, globals_1.it)("should handle the DATA event", done => {
132
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
133
+ resyncDelaySec: 1,
134
+ });
135
+ setupAndStartWatcher(__1.WatchEvent.DATA, (pod, phase) => {
136
+ (0, globals_1.expect)(pod.metadata?.name).toEqual(`pod-0`);
137
+ (0, globals_1.expect)(phase).toEqual(types_1.WatchPhase.Added);
138
+ done();
139
+ });
140
+ });
141
+ (0, globals_1.it)("should handle the NETWORK_ERROR event", done => {
142
+ nock_1.default.cleanAll();
143
+ (0, nock_1.default)("http://jest-test:8080")
144
+ .get("/api/v1/pods")
145
+ .reply(200, {
146
+ kind: "PodList",
147
+ apiVersion: "v1",
148
+ metadata: {
149
+ resourceVersion: "45",
150
+ },
151
+ items: [createMockPod(`pod-0`, `1`)],
152
+ });
153
+ (0, nock_1.default)("http://jest-test:8080")
154
+ .get("/api/v1/pods")
155
+ .query({ watch: "true", resourceVersion: "45" })
156
+ .replyWithError("Something bad happened");
157
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
158
+ resyncDelaySec: 1,
159
+ });
160
+ setupAndStartWatcher(__1.WatchEvent.NETWORK_ERROR, error => {
161
+ (0, globals_1.expect)(error.message).toEqual("request to http://jest-test:8080/api/v1/pods?watch=true&resourceVersion=45 failed, reason: Something bad happened");
162
+ done();
163
+ });
164
+ });
165
+ (0, globals_1.it)("should handle the RECONNECT event on an error", done => {
166
+ nock_1.default.cleanAll();
167
+ (0, nock_1.default)("http://jest-test:8080")
168
+ .get("/api/v1/pods")
169
+ .reply(200, {
170
+ kind: "PodList",
171
+ apiVersion: "v1",
172
+ metadata: {
173
+ resourceVersion: "65",
174
+ },
175
+ items: [createMockPod(`pod-0`, `1`)],
176
+ });
177
+ (0, nock_1.default)("http://jest-test:8080")
178
+ .get("/api/v1/pods")
179
+ .query({ watch: "true", resourceVersion: "65" })
180
+ .replyWithError("Something bad happened");
181
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
182
+ resyncDelaySec: 0.01,
183
+ });
184
+ setupAndStartWatcher(__1.WatchEvent.RECONNECT, count => {
185
+ (0, globals_1.expect)(count).toEqual(1);
186
+ done();
187
+ });
188
+ });
189
+ (0, globals_1.it)("should perform a resync after the resync interval", done => {
190
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
191
+ resyncDelaySec: 0.01,
192
+ lastSeenLimitSeconds: 0.01,
193
+ });
194
+ setupAndStartWatcher(__1.WatchEvent.RECONNECT, count => {
195
+ (0, globals_1.expect)(count).toEqual(1);
196
+ done();
197
+ });
198
+ });
199
+ (0, globals_1.it)("should handle the GIVE_UP event", done => {
200
+ nock_1.default.cleanAll();
201
+ (0, nock_1.default)("http://jest-test:8080")
202
+ .get("/api/v1/pods")
203
+ .reply(200, {
204
+ kind: "PodList",
205
+ apiVersion: "v1",
206
+ metadata: {
207
+ resourceVersion: "75",
208
+ },
209
+ items: [createMockPod(`pod-0`, `1`)],
210
+ });
211
+ (0, nock_1.default)("http://jest-test:8080")
212
+ .get("/api/v1/pods")
213
+ .query({ watch: "true", resourceVersion: "75" })
214
+ .replyWithError("Something bad happened");
215
+ watcher = (0, _1.K8s)(__1.kind.Pod).Watch(evtMock, {
216
+ resyncFailureMax: 1,
217
+ resyncDelaySec: 0.01,
218
+ lastSeenLimitSeconds: 1,
219
+ });
220
+ setupAndStartWatcher(__1.WatchEvent.GIVE_UP, error => {
221
+ (0, globals_1.expect)(error.message).toContain("Retry limit (1) exceeded, giving up");
222
+ done();
223
+ });
224
+ });
225
+ });
226
+ /**
227
+ * Creates a mock pod object
228
+ *
229
+ * @param name The name of the pod
230
+ * @param resourceVersion The resource version of the pod
231
+ * @returns A mock pod object
232
+ */
233
+ function createMockPod(name, resourceVersion) {
234
+ return {
235
+ kind: "Pod",
236
+ apiVersion: "v1",
237
+ metadata: {
238
+ name: name,
239
+ resourceVersion: resourceVersion,
240
+ uid: Math.random().toString(36).substring(7),
241
+ // ... other metadata fields
242
+ },
243
+ spec: {
244
+ containers: [
245
+ {
246
+ name: "nginx",
247
+ image: "nginx:1.14.2",
248
+ ports: [
249
+ {
250
+ containerPort: 80,
251
+ protocol: "TCP",
252
+ },
253
+ ],
254
+ },
255
+ ],
256
+ },
257
+ status: {
258
+ // ... pod status
259
+ },
260
+ };
261
+ }
@@ -0,0 +1,84 @@
1
+ import { InputData, TargetLanguage } from "quicktype-core";
2
+ import { CustomResourceDefinition } from "./upstream";
3
+ import { LogFn } from "./types";
4
+ export interface GenerateOptions {
5
+ source: string;
6
+ directory?: string;
7
+ plain?: boolean;
8
+ language?: string | TargetLanguage;
9
+ npmPackage?: string;
10
+ logFn: LogFn;
11
+ noPost?: boolean;
12
+ }
13
+ /**
14
+ * Converts a CustomResourceDefinition to TypeScript types
15
+ *
16
+ * @param crd - The CustomResourceDefinition object to convert.
17
+ * @param opts - The options for generating the TypeScript types.
18
+ * @returns A promise that resolves to a record of generated TypeScript types.
19
+ */
20
+ export declare function convertCRDtoTS(crd: CustomResourceDefinition, opts: GenerateOptions): Promise<{
21
+ results: Record<string, string[]>;
22
+ name: string;
23
+ crd: CustomResourceDefinition;
24
+ version: string;
25
+ }[]>;
26
+ /**
27
+ * Prepares the input data for quicktype from the provided schema.
28
+ *
29
+ * @param name - The name of the schema.
30
+ * @param schema - The JSON schema as a string.
31
+ * @returns A promise that resolves to the input data for quicktype.
32
+ */
33
+ export declare function prepareInputData(name: string, schema: string): Promise<InputData>;
34
+ /**
35
+ * Generates TypeScript types using quicktype.
36
+ *
37
+ * @param inputData - The input data for quicktype.
38
+ * @param opts - The options for generating the TypeScript types.
39
+ * @returns A promise that resolves to an array of generated TypeScript type lines.
40
+ */
41
+ export declare function generateTypes(inputData: InputData, opts: GenerateOptions): Promise<string[]>;
42
+ /**
43
+ * Writes the processed lines to the output file.
44
+ *
45
+ * @param fileName - The name of the file to write.
46
+ * @param directory - The directory where the file will be written.
47
+ * @param content - The content to write to the file.
48
+ * @param language - The programming language of the file.
49
+ */
50
+ export declare function writeGeneratedFile(fileName: string, directory: string, content: string[], language: string | TargetLanguage): void;
51
+ /**
52
+ * Reads or fetches a CustomResourceDefinition from a file, URL, or the cluster.
53
+ *
54
+ * @param opts - The options for generating the TypeScript types.
55
+ * @returns A promise that resolves to an array of CustomResourceDefinition objects.
56
+ */
57
+ export declare function readOrFetchCrd(opts: GenerateOptions): Promise<CustomResourceDefinition[]>;
58
+ /**
59
+ * Resolves the source file path, treating relative paths as local files.
60
+ *
61
+ * @param source - The source path to resolve.
62
+ * @returns The resolved file path.
63
+ */
64
+ export declare function resolveFilePath(source: string): string;
65
+ /**
66
+ * Tries to parse the source as a URL.
67
+ *
68
+ * @param source - The source string to parse as a URL.
69
+ * @returns The parsed URL object or null if parsing fails.
70
+ */
71
+ export declare function tryParseUrl(source: string): URL | null;
72
+ /**
73
+ * Main generate function to convert CRDs to TypeScript types.
74
+ *
75
+ * @param opts - The options for generating the TypeScript types.
76
+ * @returns A promise that resolves to a record of generated TypeScript types.
77
+ */
78
+ export declare function generate(opts: GenerateOptions): Promise<{
79
+ results: Record<string, string[]>;
80
+ name: string;
81
+ crd: CustomResourceDefinition;
82
+ version: string;
83
+ }[]>;
84
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,SAAS,EAET,cAAc,EAEf,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,eAAe,GACpB,OAAO,CACR;IACE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,wBAAwB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB,EAAE,CACJ,CAuCA;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAYvF;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,MAAM,GAAG,cAAc,GAChC,IAAI,CAON;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CA0B/F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,CAMtD;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAC5D;IACE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,wBAAwB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB,EAAE,CACJ,CA8BA"}
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || function (mod) {
21
+ if (mod && mod.__esModule) return mod;
22
+ var result = {};
23
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24
+ __setModuleDefault(result, mod);
25
+ return result;
26
+ };
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;
35
+ exports.generate = generate;
36
+ const client_node_1 = require("@kubernetes/client-node");
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const quicktype_core_1 = require("quicktype-core");
40
+ const fetch_1 = require("./fetch");
41
+ const fluent_1 = require("./fluent");
42
+ const upstream_1 = require("./upstream");
43
+ /**
44
+ * Converts a CustomResourceDefinition to TypeScript types
45
+ *
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.
49
+ */
50
+ async function convertCRDtoTS(crd, opts) {
51
+ const name = crd.spec.names.kind;
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
60
+ for (const match of crd.spec.versions) {
61
+ if (!match.schema?.openAPIV3Schema) {
62
+ opts.logFn(`Skipping ${crd.metadata?.name ?? "unknown"}, it does not appear to have a valid schema`);
63
+ continue;
64
+ }
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 });
73
+ }
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;
92
+ }
93
+ /**
94
+ * Generates TypeScript types using quicktype.
95
+ *
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.
132
+ */
133
+ async function readOrFetchCrd(opts) {
134
+ try {
135
+ const filePath = resolveFilePath(opts.source);
136
+ if (fs.existsSync(filePath)) {
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);
140
+ }
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);
147
+ }
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
+ }
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`);
156
+ }
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) {
174
+ try {
175
+ return new URL(source);
176
+ }
177
+ catch {
178
+ return null;
179
+ }
180
+ }
181
+ /**
182
+ * Main generate function to convert CRDs to TypeScript types.
183
+ *
184
+ * @param opts - The options for generating the TypeScript types.
185
+ * @returns A promise that resolves to a record of generated TypeScript types.
186
+ */
187
+ async function generate(opts) {
188
+ const crds = (await readOrFetchCrd(opts)).filter(crd => !!crd);
189
+ const allResults = [];
190
+ opts.logFn("");
191
+ for (const crd of crds) {
192
+ if (crd.kind !== "CustomResourceDefinition" || !crd.spec?.versions?.length) {
193
+ opts.logFn(`Skipping ${crd?.metadata?.name}, it does not appear to be a CRD`);
194
+ // Ignore empty and non-CRD objects
195
+ continue;
196
+ }
197
+ allResults.push(...(await convertCRDtoTS(crd, opts)));
198
+ }
199
+ if (opts.directory) {
200
+ // Notify the user that the files have been generated
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`);
206
+ }
207
+ return allResults;
208
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.test.d.ts","sourceRoot":"","sources":["../src/generate.test.ts"],"names":[],"mappings":""}