kubernetes-fluent-client 3.0.3 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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/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 +123 -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/generate.test.ts +368 -358
- package/src/generate.ts +173 -154
- package/src/postProcessing.test.ts +742 -0
- package/src/postProcessing.ts +568 -0
package/.prettierignore
ADDED
package/README.md
CHANGED
|
@@ -105,6 +105,30 @@ Promise.all([
|
|
|
105
105
|
});
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
### Generating TypeScript Definitions from CRDs
|
|
109
|
+
|
|
110
|
+
The Kubernetes Fluent Client can generate TypeScript definitions from Custom Resource Definitions (CRDs) using the `generate` command. This command will generate TypeScript interfaces for the CRDs in the cluster and save them to a file.
|
|
111
|
+
|
|
112
|
+
To generate TypeScript definitions from CRDs, run the following command:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
kubernetes-fluent-client crd /path/to/input.yaml /path/to/output/folder
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
If you have a CRD in a file named `crd.yaml` and you want to generate TypeScript definitions in a folder named `types`, you can run the following command:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
kubernetes-fluent-client crd crd.yaml types
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This will generate TypeScript interfaces for the CRD in the `crd.yaml` file and save them to the `types` folder.
|
|
125
|
+
|
|
126
|
+
By default, the generated TypeScript interfaces will be post-processed to make them more user-friendly. If you want to disable this post-processing, you can use the `--noPost` flag:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
kubernetes-fluent-client crd crd.yaml types --noPost
|
|
130
|
+
```
|
|
131
|
+
|
|
108
132
|
### Community
|
|
109
133
|
|
|
110
134
|
To chat with other users & see some examples of the fluent client in active use, go to [Kubernetes Slack](https://communityinviter.com/apps/kubernetes/community) and join `#pepr` channel.
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,8 @@ const helpers_1 = require("yargs/helpers");
|
|
|
10
10
|
const yargs_1 = __importDefault(require("yargs/yargs"));
|
|
11
11
|
const generate_1 = require("./generate");
|
|
12
12
|
const package_json_1 = require("../package.json");
|
|
13
|
+
const postProcessing_1 = require("./postProcessing");
|
|
14
|
+
const fileSystem_1 = require("./fileSystem"); // Import your new file system
|
|
13
15
|
void (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
14
16
|
.version("version", "Display version number", `kubernetes-fluent-client v${package_json_1.version}`)
|
|
15
17
|
.alias("version", "V")
|
|
@@ -33,13 +35,31 @@ void (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
|
33
35
|
type: "string",
|
|
34
36
|
default: "ts",
|
|
35
37
|
description: "the language to generate types in, see https://github.com/glideapps/quicktype#target-languages for a list of supported languages",
|
|
38
|
+
})
|
|
39
|
+
.option("noPost", {
|
|
40
|
+
alias: "x",
|
|
41
|
+
type: "boolean",
|
|
42
|
+
default: false,
|
|
43
|
+
description: "disable post-processing after generating the types",
|
|
36
44
|
})
|
|
37
45
|
.demandOption(["source", "directory"]);
|
|
38
46
|
}, async (argv) => {
|
|
39
47
|
const opts = argv;
|
|
40
48
|
opts.logFn = console.log;
|
|
49
|
+
// Pass the `post` flag to opts
|
|
50
|
+
opts.noPost = argv.noPost;
|
|
51
|
+
// Use NodeFileSystem as the file system for post-processing
|
|
52
|
+
const fileSystem = new fileSystem_1.NodeFileSystem(); // Create an instance of NodeFileSystem
|
|
53
|
+
if (!opts.noPost) {
|
|
54
|
+
console.log("\n✅ Post-processing has been enabled.\n");
|
|
55
|
+
}
|
|
41
56
|
try {
|
|
42
|
-
|
|
57
|
+
// Capture the results returned by generate
|
|
58
|
+
const allResults = await (0, generate_1.generate)(opts);
|
|
59
|
+
// If noPost is false, run post-processing
|
|
60
|
+
if (!opts.noPost) {
|
|
61
|
+
await (0, postProcessing_1.postProcessing)(allResults, opts, fileSystem); // Pass the file system to postProcessing
|
|
62
|
+
}
|
|
43
63
|
}
|
|
44
64
|
catch (e) {
|
|
45
65
|
console.log(`\n❌ ${e.message}`);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface FileSystem {
|
|
2
|
+
readFile(filePath: string): string;
|
|
3
|
+
writeFile(filePath: string, content: string): void;
|
|
4
|
+
readdirSync(directory: string): string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class NodeFileSystem implements FileSystem {
|
|
7
|
+
readFile(filePath: string): string;
|
|
8
|
+
writeFile(filePath: string, content: string): void;
|
|
9
|
+
readdirSync(directory: string): string[];
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=fileSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileSystem.d.ts","sourceRoot":"","sources":["../src/fileSystem.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACnD,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1C;AAGD,qBAAa,cAAe,YAAW,UAAU;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIlC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlD,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;CAGzC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
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.NodeFileSystem = void 0;
|
|
29
|
+
const fs = __importStar(require("fs"));
|
|
30
|
+
/* eslint class-methods-use-this: "off" */
|
|
31
|
+
class NodeFileSystem {
|
|
32
|
+
readFile(filePath) {
|
|
33
|
+
return fs.readFileSync(filePath, "utf8");
|
|
34
|
+
}
|
|
35
|
+
writeFile(filePath, content) {
|
|
36
|
+
fs.writeFileSync(filePath, content, "utf8");
|
|
37
|
+
}
|
|
38
|
+
readdirSync(directory) {
|
|
39
|
+
return fs.readdirSync(directory);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.NodeFileSystem = NodeFileSystem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileSystem.test.d.ts","sourceRoot":"","sources":["../src/fileSystem.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
const fs = __importStar(require("fs"));
|
|
29
|
+
const fileSystem_1 = require("./fileSystem");
|
|
30
|
+
const globals_1 = require("@jest/globals");
|
|
31
|
+
// Mock the fs module
|
|
32
|
+
globals_1.jest.mock("fs");
|
|
33
|
+
(0, globals_1.describe)("NodeFileSystem", () => {
|
|
34
|
+
let nodeFileSystem;
|
|
35
|
+
(0, globals_1.beforeEach)(() => {
|
|
36
|
+
nodeFileSystem = new fileSystem_1.NodeFileSystem();
|
|
37
|
+
globals_1.jest.clearAllMocks(); // Clear all mocks before each test
|
|
38
|
+
});
|
|
39
|
+
(0, globals_1.describe)("readFile", () => {
|
|
40
|
+
(0, globals_1.test)("should call fs.readFileSync with correct arguments", () => {
|
|
41
|
+
const mockFilePath = "test-file.txt";
|
|
42
|
+
const mockFileContent = "This is a test file";
|
|
43
|
+
// Mock the fs.readFileSync method to return the mock file content
|
|
44
|
+
fs.readFileSync.mockReturnValue(mockFileContent);
|
|
45
|
+
const result = nodeFileSystem.readFile(mockFilePath);
|
|
46
|
+
// Assert that fs.readFileSync was called with the correct file path and encoding
|
|
47
|
+
(0, globals_1.expect)(fs.readFileSync).toHaveBeenCalledWith(mockFilePath, "utf8");
|
|
48
|
+
// Assert that the returned content matches the mock file content
|
|
49
|
+
(0, globals_1.expect)(result).toBe(mockFileContent);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
(0, globals_1.describe)("writeFile", () => {
|
|
53
|
+
(0, globals_1.test)("should call fs.writeFileSync with correct arguments", () => {
|
|
54
|
+
const mockFilePath = "test-file.txt";
|
|
55
|
+
const mockFileContent = "This is a test file";
|
|
56
|
+
// Call the writeFile method
|
|
57
|
+
nodeFileSystem.writeFile(mockFilePath, mockFileContent);
|
|
58
|
+
// Assert that fs.writeFileSync was called with the correct arguments
|
|
59
|
+
(0, globals_1.expect)(fs.writeFileSync).toHaveBeenCalledWith(mockFilePath, mockFileContent, "utf8");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
(0, globals_1.describe)("readdirSync", () => {
|
|
63
|
+
(0, globals_1.test)("should call fs.readdirSync with correct arguments and return file list", () => {
|
|
64
|
+
const mockDirectoryPath = "test-directory";
|
|
65
|
+
const mockFileList = ["file1.txt", "file2.txt"];
|
|
66
|
+
// Mock the fs.readdirSync method to return the mock file list
|
|
67
|
+
fs.readdirSync.mockReturnValue(mockFileList);
|
|
68
|
+
const result = nodeFileSystem.readdirSync(mockDirectoryPath);
|
|
69
|
+
// Assert that fs.readdirSync was called with the correct directory path
|
|
70
|
+
(0, globals_1.expect)(fs.readdirSync).toHaveBeenCalledWith(mockDirectoryPath);
|
|
71
|
+
// Assert that the returned file list matches the mock file list
|
|
72
|
+
(0, globals_1.expect)(result).toEqual(mockFileList);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
package/dist/generate.d.ts
CHANGED
|
@@ -1,24 +1,84 @@
|
|
|
1
|
-
import { TargetLanguage } from "quicktype-core";
|
|
1
|
+
import { InputData, TargetLanguage } from "quicktype-core";
|
|
2
|
+
import { CustomResourceDefinition } from "./upstream";
|
|
2
3
|
import { LogFn } from "./types";
|
|
3
4
|
export interface GenerateOptions {
|
|
4
|
-
/** The source URL, yaml file path or K8s CRD name */
|
|
5
5
|
source: string;
|
|
6
|
-
/** The output directory path */
|
|
7
6
|
directory?: string;
|
|
8
|
-
/** Disable kubernetes-fluent-client wrapping */
|
|
9
7
|
plain?: boolean;
|
|
10
|
-
/** The language to generate types in */
|
|
11
8
|
language?: string | TargetLanguage;
|
|
12
|
-
/** Override the NPM package to import when generating formatted Typescript */
|
|
13
9
|
npmPackage?: string;
|
|
14
|
-
/** Log function callback */
|
|
15
10
|
logFn: LogFn;
|
|
11
|
+
noPost?: boolean;
|
|
16
12
|
}
|
|
17
13
|
/**
|
|
18
|
-
*
|
|
14
|
+
* Converts a CustomResourceDefinition to TypeScript types
|
|
19
15
|
*
|
|
20
|
-
* @param
|
|
21
|
-
* @
|
|
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.
|
|
22
19
|
*/
|
|
23
|
-
export declare function
|
|
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
|
+
}[]>;
|
|
24
84
|
//# sourceMappingURL=generate.d.ts.map
|
package/dist/generate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAMA,OAAO,
|
|
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"}
|
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
|
|
41
|
-
* @returns A promise that resolves
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
107
|
-
|
|
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
|
|
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
|
-
*
|
|
94
|
+
* Generates TypeScript types using quicktype.
|
|
113
95
|
*
|
|
114
|
-
* @param
|
|
115
|
-
* @
|
|
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
|
|
133
|
-
return (0, client_node_1.loadAllYaml)(
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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 (
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
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
|
-
|
|
162
|
-
return [await (0, fluent_1.K8s)(upstream_1.CustomResourceDefinition).Get(source)];
|
|
175
|
+
return new URL(source);
|
|
163
176
|
}
|
|
164
|
-
catch
|
|
165
|
-
|
|
177
|
+
catch {
|
|
178
|
+
return null;
|
|
166
179
|
}
|
|
167
180
|
}
|
|
168
181
|
/**
|
|
169
|
-
*
|
|
182
|
+
* Main generate function to convert CRDs to TypeScript types.
|
|
170
183
|
*
|
|
171
|
-
* @param opts The options
|
|
172
|
-
* @returns A promise that resolves
|
|
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
|
|
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
|
-
|
|
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 ${
|
|
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
|
|
207
|
+
return allResults;
|
|
195
208
|
}
|