kubernetes-fluent-client 1.5.0 → 1.6.0
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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -0
- package/dist/fetch.d.ts +1 -1
- package/dist/fetch.js +2 -2
- package/dist/fetch.test.js +1 -1
- package/dist/fluent/apply.js +1 -1
- package/dist/fluent/index.d.ts +1 -0
- package/dist/fluent/index.d.ts.map +1 -1
- package/dist/fluent/index.js +45 -3
- package/dist/fluent/types.d.ts +33 -21
- package/dist/fluent/types.d.ts.map +1 -1
- package/dist/fluent/types.js +1 -1
- package/dist/fluent/utils.d.ts +18 -7
- package/dist/fluent/utils.d.ts.map +1 -1
- package/dist/fluent/utils.js +19 -8
- package/dist/fluent/utils.test.js +1 -1
- package/dist/fluent/watch.d.ts +9 -2
- package/dist/fluent/watch.d.ts.map +1 -1
- package/dist/fluent/watch.js +19 -2
- package/dist/generate.d.ts +19 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +165 -0
- package/dist/generate.test.d.ts +2 -0
- package/dist/generate.test.d.ts.map +1 -0
- package/dist/generate.test.js +256 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/kinds.d.ts +6 -0
- package/dist/kinds.d.ts.map +1 -1
- package/dist/kinds.js +53 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -7
- package/src/cli.ts +44 -0
- package/src/fetch.test.ts +1 -1
- package/src/fetch.ts +2 -2
- package/src/fluent/apply.ts +1 -1
- package/src/fluent/index.ts +46 -4
- package/src/fluent/types.ts +34 -22
- package/src/fluent/utils.test.ts +1 -1
- package/src/fluent/utils.ts +19 -8
- package/src/fluent/watch.ts +22 -4
- package/src/generate.test.ts +266 -0
- package/src/generate.ts +189 -0
- package/src/index.ts +3 -0
- package/src/kinds.ts +53 -0
- package/src/types.ts +1 -1
package/src/fluent/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The
|
|
2
|
+
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
3
|
|
|
4
4
|
import { KubernetesListObject, KubernetesObject } from "@kubernetes/client-node";
|
|
5
5
|
import { Operation } from "fast-json-patch";
|
|
@@ -28,6 +28,14 @@ export interface Filters {
|
|
|
28
28
|
namespace?: string;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Get the resource or resources matching the filters.
|
|
33
|
+
* If no filters are specified, all resources will be returned.
|
|
34
|
+
* If a name is specified, only a single resource will be returned.
|
|
35
|
+
*
|
|
36
|
+
* @param name - (optional) the name of the resource to get
|
|
37
|
+
* @returns the resource or list of resources
|
|
38
|
+
*/
|
|
31
39
|
export type GetFunction<K extends KubernetesObject> = {
|
|
32
40
|
(): Promise<KubernetesListObject<K>>;
|
|
33
41
|
(name: string): Promise<K>;
|
|
@@ -42,16 +50,18 @@ export type K8sFilteredActions<K extends KubernetesObject> = {
|
|
|
42
50
|
Get: GetFunction<K>;
|
|
43
51
|
|
|
44
52
|
/**
|
|
45
|
-
* Delete the resource
|
|
53
|
+
* Delete the resource matching the filters.
|
|
46
54
|
*
|
|
47
55
|
* @param filter - the resource or resource name to delete
|
|
48
56
|
*/
|
|
49
57
|
Delete: (filter?: K | string) => Promise<void>;
|
|
50
58
|
|
|
51
59
|
/**
|
|
60
|
+
* Watch the resource matching the filters.
|
|
52
61
|
*
|
|
53
|
-
* @param callback
|
|
54
|
-
* @
|
|
62
|
+
* @param callback - the callback function to call when an event occurs
|
|
63
|
+
* @param watchCfg - (optional) watch configuration
|
|
64
|
+
* @returns a watch controller
|
|
55
65
|
*/
|
|
56
66
|
Watch: (
|
|
57
67
|
callback: (payload: K, phase: WatchPhase) => void,
|
|
@@ -63,16 +73,17 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
|
|
|
63
73
|
/**
|
|
64
74
|
* Perform a server-side apply of the provided K8s resource.
|
|
65
75
|
*
|
|
66
|
-
* @param resource
|
|
67
|
-
* @
|
|
76
|
+
* @param resource - the resource to apply
|
|
77
|
+
* @param applyCfg - (optional) apply configuration
|
|
78
|
+
* @returns the applied resource
|
|
68
79
|
*/
|
|
69
80
|
Apply: (resource: PartialDeep<K>, applyCfg?: ApplyCfg) => Promise<K>;
|
|
70
81
|
|
|
71
82
|
/**
|
|
72
83
|
* Create the provided K8s resource or throw an error if it already exists.
|
|
73
84
|
*
|
|
74
|
-
* @param resource
|
|
75
|
-
* @returns
|
|
85
|
+
* @param resource - the resource to create
|
|
86
|
+
* @returns the created resource
|
|
76
87
|
*/
|
|
77
88
|
Create: (resource: K) => Promise<K>;
|
|
78
89
|
|
|
@@ -94,18 +105,18 @@ export type K8sWithFilters<K extends KubernetesObject> = K8sFilteredActions<K> &
|
|
|
94
105
|
*
|
|
95
106
|
* ```ts
|
|
96
107
|
* K8s(kind.Deployment)
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
108
|
+
* .WithField("metadata.name", "bar")
|
|
109
|
+
* .WithField("metadata.namespace", "qux")
|
|
110
|
+
* .Delete(...)
|
|
100
111
|
* ```
|
|
101
112
|
*
|
|
102
113
|
* Will only delete the Deployment if it has the `metadata.name=bar` and `metadata.namespace=qux` fields.
|
|
103
114
|
* Not all fields are supported, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/#supported-fields,
|
|
104
115
|
* but Typescript will limit to only fields that exist on the resource.
|
|
105
116
|
*
|
|
106
|
-
* @param key
|
|
107
|
-
* @param value
|
|
108
|
-
* @returns
|
|
117
|
+
* @param key - the field key
|
|
118
|
+
* @param value - the field value
|
|
119
|
+
* @returns the fluent API
|
|
109
120
|
*/
|
|
110
121
|
WithField: <P extends Paths<K>>(key: P, value: string) => K8sWithFilters<K>;
|
|
111
122
|
|
|
@@ -115,15 +126,16 @@ export type K8sWithFilters<K extends KubernetesObject> = K8sFilteredActions<K> &
|
|
|
115
126
|
*
|
|
116
127
|
* ```ts
|
|
117
128
|
* K8s(kind.Deployment)
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
129
|
+
* .WithLabel("foo", "bar")
|
|
130
|
+
* .WithLabel("baz", "qux")
|
|
131
|
+
* .Delete(...)
|
|
121
132
|
* ```
|
|
122
133
|
*
|
|
123
134
|
* Will only delete the Deployment if it has the`foo=bar` and `baz=qux` labels.
|
|
124
135
|
*
|
|
125
|
-
* @param key
|
|
126
|
-
* @param value
|
|
136
|
+
* @param key - the label key
|
|
137
|
+
* @param value - the label value
|
|
138
|
+
* @returns the fluent API
|
|
127
139
|
*/
|
|
128
140
|
WithLabel: (key: string, value: string) => K8sWithFilters<K>;
|
|
129
141
|
};
|
|
@@ -131,10 +143,10 @@ export type K8sWithFilters<K extends KubernetesObject> = K8sFilteredActions<K> &
|
|
|
131
143
|
export type K8sInit<K extends KubernetesObject> = K8sWithFilters<K> &
|
|
132
144
|
K8sUnfilteredActions<K> & {
|
|
133
145
|
/**
|
|
134
|
-
*
|
|
146
|
+
* Set the namespace filter.
|
|
135
147
|
*
|
|
136
|
-
* @param namespace
|
|
137
|
-
* @returns
|
|
148
|
+
* @param namespace - the namespace to filter on
|
|
149
|
+
* @returns the fluent API
|
|
138
150
|
*/
|
|
139
151
|
InNamespace: (namespace: string) => K8sWithFilters<K>;
|
|
140
152
|
};
|
package/src/fluent/utils.test.ts
CHANGED
package/src/fluent/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The
|
|
2
|
+
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
3
|
|
|
4
4
|
import { KubeConfig, PatchStrategy } from "@kubernetes/client-node";
|
|
5
5
|
|
|
@@ -16,11 +16,11 @@ const SSA_CONTENT_TYPE = "application/apply-patch+yaml";
|
|
|
16
16
|
/**
|
|
17
17
|
* Generate a path to a Kubernetes resource
|
|
18
18
|
*
|
|
19
|
-
* @param serverUrl
|
|
20
|
-
* @param model
|
|
21
|
-
* @param filters
|
|
22
|
-
* @param excludeName
|
|
23
|
-
* @returns
|
|
19
|
+
* @param serverUrl - the URL of the Kubernetes API server
|
|
20
|
+
* @param model - the model to use for the API
|
|
21
|
+
* @param filters - (optional) filter overrides, can also be chained
|
|
22
|
+
* @param excludeName - (optional) exclude the name from the path
|
|
23
|
+
* @returns the path to the resource
|
|
24
24
|
*/
|
|
25
25
|
export function pathBuilder<T extends GenericClass>(
|
|
26
26
|
serverUrl: string,
|
|
@@ -90,8 +90,8 @@ export function pathBuilder<T extends GenericClass>(
|
|
|
90
90
|
* - We have to create an agent to handle the TLS connection (for the custom CA + mTLS in some cases)
|
|
91
91
|
* - The K8s lib uses request instead of node-fetch today so the object is slightly different
|
|
92
92
|
*
|
|
93
|
-
* @param method
|
|
94
|
-
* @returns
|
|
93
|
+
* @param method - the HTTP method to use
|
|
94
|
+
* @returns the fetch options and server URL
|
|
95
95
|
*/
|
|
96
96
|
export async function k8sCfg(method: FetchMethods) {
|
|
97
97
|
const kubeConfig = new KubeConfig();
|
|
@@ -119,6 +119,17 @@ export async function k8sCfg(method: FetchMethods) {
|
|
|
119
119
|
return { opts, serverUrl: cluster.server };
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Execute a request against the Kubernetes API server.
|
|
124
|
+
*
|
|
125
|
+
* @param model - the model to use for the API
|
|
126
|
+
* @param filters - (optional) filter overrides, can also be chained
|
|
127
|
+
* @param method - the HTTP method to use
|
|
128
|
+
* @param payload - (optional) the payload to send
|
|
129
|
+
* @param applyCfg - (optional) configuration for the apply method
|
|
130
|
+
*
|
|
131
|
+
* @returns the parsed JSON response
|
|
132
|
+
*/
|
|
122
133
|
export async function k8sExec<T extends GenericClass, K>(
|
|
123
134
|
model: T,
|
|
124
135
|
filters: Filters,
|
package/src/fluent/watch.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The
|
|
2
|
+
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
3
|
|
|
4
4
|
import byline from "byline";
|
|
5
5
|
import fetch from "node-fetch";
|
|
@@ -14,13 +14,14 @@ import { k8sCfg, pathBuilder } from "./utils";
|
|
|
14
14
|
export type WatchController = {
|
|
15
15
|
/**
|
|
16
16
|
* Abort the watch.
|
|
17
|
+
*
|
|
17
18
|
* @param reason optional reason for aborting the watch
|
|
18
|
-
* @returns
|
|
19
19
|
*/
|
|
20
20
|
abort: (reason?: string) => void;
|
|
21
21
|
/**
|
|
22
22
|
* Get the AbortSignal for the watch.
|
|
23
|
-
*
|
|
23
|
+
*
|
|
24
|
+
* @returns the AbortSignal
|
|
24
25
|
*/
|
|
25
26
|
signal: () => AbortSignal;
|
|
26
27
|
};
|
|
@@ -49,6 +50,12 @@ export type WatchCfg = {
|
|
|
49
50
|
|
|
50
51
|
/**
|
|
51
52
|
* Execute a watch on the specified resource.
|
|
53
|
+
*
|
|
54
|
+
* @param model - the model to use for the API
|
|
55
|
+
* @param filters - (optional) filter overrides, can also be chained
|
|
56
|
+
* @param callback - the callback function to call when an event is received
|
|
57
|
+
* @param watchCfg - (optional) watch configuration
|
|
58
|
+
* @returns a WatchController to allow the watch to be aborted externally
|
|
52
59
|
*/
|
|
53
60
|
export async function ExecWatch<T extends GenericClass>(
|
|
54
61
|
model: T,
|
|
@@ -94,6 +101,9 @@ export async function ExecWatch<T extends GenericClass>(
|
|
|
94
101
|
// Create a wrapped AbortController to allow the watch to be aborted externally
|
|
95
102
|
const abortWrapper = {} as WatchController;
|
|
96
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Bind the abort controller to the wrapper.
|
|
106
|
+
*/
|
|
97
107
|
function bindAbortController() {
|
|
98
108
|
// Create a new AbortController
|
|
99
109
|
abortController = new AbortController();
|
|
@@ -106,6 +116,9 @@ export async function ExecWatch<T extends GenericClass>(
|
|
|
106
116
|
opts.signal = abortController.signal;
|
|
107
117
|
}
|
|
108
118
|
|
|
119
|
+
/**
|
|
120
|
+
* The main watch runner. This will run until the process is terminated or the watch is aborted.
|
|
121
|
+
*/
|
|
109
122
|
async function runner() {
|
|
110
123
|
let doneCalled = false;
|
|
111
124
|
|
|
@@ -130,6 +143,7 @@ export async function ExecWatch<T extends GenericClass>(
|
|
|
130
143
|
}
|
|
131
144
|
};
|
|
132
145
|
|
|
146
|
+
// Cleanup the stream listeners
|
|
133
147
|
const cleanup = () => {
|
|
134
148
|
if (!doneCalled) {
|
|
135
149
|
doneCalled = true;
|
|
@@ -181,7 +195,11 @@ export async function ExecWatch<T extends GenericClass>(
|
|
|
181
195
|
onError(e);
|
|
182
196
|
}
|
|
183
197
|
|
|
184
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Reload the watch.
|
|
200
|
+
*
|
|
201
|
+
* @param e - the error that caused the reload
|
|
202
|
+
*/
|
|
185
203
|
async function reload(e: Error) {
|
|
186
204
|
// If there are more attempts, retry the watch
|
|
187
205
|
if (watchCfg.retryMax! > retryCount) {
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
|
|
2
|
+
import { generate } from "./generate";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
|
|
5
|
+
const sampleYaml = `
|
|
6
|
+
# non-crd should be ignored
|
|
7
|
+
apiVersion: v1
|
|
8
|
+
kind: ConfigMap
|
|
9
|
+
metadata:
|
|
10
|
+
name: test
|
|
11
|
+
namespace: default
|
|
12
|
+
data:
|
|
13
|
+
any: bleh
|
|
14
|
+
---
|
|
15
|
+
apiVersion: apiextensions.k8s.io/v1
|
|
16
|
+
kind: CustomResourceDefinition
|
|
17
|
+
metadata:
|
|
18
|
+
name: movies.example.com
|
|
19
|
+
spec:
|
|
20
|
+
group: example.com
|
|
21
|
+
names:
|
|
22
|
+
kind: Movie
|
|
23
|
+
plural: movies
|
|
24
|
+
scope: Namespaced
|
|
25
|
+
versions:
|
|
26
|
+
- name: v1
|
|
27
|
+
schema:
|
|
28
|
+
openAPIV3Schema:
|
|
29
|
+
type: object
|
|
30
|
+
description: Movie nerd
|
|
31
|
+
properties:
|
|
32
|
+
spec:
|
|
33
|
+
properties:
|
|
34
|
+
title:
|
|
35
|
+
type: string
|
|
36
|
+
author:
|
|
37
|
+
type: string
|
|
38
|
+
type: object
|
|
39
|
+
---
|
|
40
|
+
# duplicate entries should not break things
|
|
41
|
+
apiVersion: apiextensions.k8s.io/v1
|
|
42
|
+
kind: CustomResourceDefinition
|
|
43
|
+
metadata:
|
|
44
|
+
name: movies.example.com
|
|
45
|
+
spec:
|
|
46
|
+
group: example.com
|
|
47
|
+
names:
|
|
48
|
+
kind: Movie
|
|
49
|
+
plural: movies
|
|
50
|
+
scope: Namespaced
|
|
51
|
+
versions:
|
|
52
|
+
- name: v1
|
|
53
|
+
schema:
|
|
54
|
+
openAPIV3Schema:
|
|
55
|
+
type: object
|
|
56
|
+
description: Movie nerd
|
|
57
|
+
properties:
|
|
58
|
+
spec:
|
|
59
|
+
properties:
|
|
60
|
+
title:
|
|
61
|
+
type: string
|
|
62
|
+
author:
|
|
63
|
+
type: string
|
|
64
|
+
type: object
|
|
65
|
+
---
|
|
66
|
+
# should support multiple versions
|
|
67
|
+
apiVersion: apiextensions.k8s.io/v1
|
|
68
|
+
kind: CustomResourceDefinition
|
|
69
|
+
metadata:
|
|
70
|
+
name: books.example.com
|
|
71
|
+
spec:
|
|
72
|
+
group: example.com
|
|
73
|
+
names:
|
|
74
|
+
kind: Book
|
|
75
|
+
plural: books
|
|
76
|
+
scope: Namespaced
|
|
77
|
+
versions:
|
|
78
|
+
- name: v1
|
|
79
|
+
schema:
|
|
80
|
+
openAPIV3Schema:
|
|
81
|
+
type: object
|
|
82
|
+
description: Book nerd
|
|
83
|
+
properties:
|
|
84
|
+
spec:
|
|
85
|
+
properties:
|
|
86
|
+
title:
|
|
87
|
+
type: string
|
|
88
|
+
author:
|
|
89
|
+
type: string
|
|
90
|
+
type: object
|
|
91
|
+
- name: v2
|
|
92
|
+
schema:
|
|
93
|
+
openAPIV3Schema:
|
|
94
|
+
type: object
|
|
95
|
+
description: Book nerd
|
|
96
|
+
properties:
|
|
97
|
+
spec:
|
|
98
|
+
properties:
|
|
99
|
+
author:
|
|
100
|
+
type: string
|
|
101
|
+
type: object
|
|
102
|
+
served: true
|
|
103
|
+
storage: true
|
|
104
|
+
`;
|
|
105
|
+
|
|
106
|
+
jest.mock("./fetch", () => ({
|
|
107
|
+
fetch: jest.fn(),
|
|
108
|
+
}));
|
|
109
|
+
|
|
110
|
+
jest.mock("./fluent", () => ({
|
|
111
|
+
K8s: jest.fn(),
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
describe("CRD to TypeScript Conversion", () => {
|
|
115
|
+
const originalReadFileSync = fs.readFileSync;
|
|
116
|
+
|
|
117
|
+
jest.isolateModules(() => {
|
|
118
|
+
jest.spyOn(fs, "existsSync").mockReturnValue(true);
|
|
119
|
+
jest.spyOn(fs, "readFileSync").mockImplementation((...args) => {
|
|
120
|
+
// Super janky hack due ot source-map-support calling readFileSync internally
|
|
121
|
+
if (args[0].toString().includes("test-crd.yaml")) {
|
|
122
|
+
return sampleYaml;
|
|
123
|
+
}
|
|
124
|
+
return originalReadFileSync(...args);
|
|
125
|
+
});
|
|
126
|
+
jest.spyOn(fs, "mkdirSync").mockReturnValue(undefined);
|
|
127
|
+
jest.spyOn(fs, "writeFileSync").mockReturnValue(undefined);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
beforeEach(() => {
|
|
131
|
+
jest.clearAllMocks();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("converts CRD to TypeScript", async () => {
|
|
135
|
+
const options = { source: "test-crd.yaml", language: "ts" }; // specify your options
|
|
136
|
+
|
|
137
|
+
const actual = await generate(options);
|
|
138
|
+
const expectedMovie = [
|
|
139
|
+
"// This file is auto-generated by kubernetes-fluent-client, do not edit manually\n",
|
|
140
|
+
'import { GenericKind, RegisterKind } from "kubernetes-fluent-client";\n',
|
|
141
|
+
"/**",
|
|
142
|
+
" * Movie nerd",
|
|
143
|
+
" */",
|
|
144
|
+
"export class Movie extends GenericKind {",
|
|
145
|
+
" spec?: Spec;",
|
|
146
|
+
"}",
|
|
147
|
+
"",
|
|
148
|
+
"export interface Spec {",
|
|
149
|
+
" author?: string;",
|
|
150
|
+
" title?: string;",
|
|
151
|
+
"}",
|
|
152
|
+
"",
|
|
153
|
+
"RegisterKind(Movie, {",
|
|
154
|
+
' group: "example.com",',
|
|
155
|
+
' version: "v1",',
|
|
156
|
+
' kind: "Movie",',
|
|
157
|
+
"});",
|
|
158
|
+
];
|
|
159
|
+
const expectedBookV1 = [
|
|
160
|
+
"// This file is auto-generated by kubernetes-fluent-client, do not edit manually\n",
|
|
161
|
+
'import { GenericKind, RegisterKind } from "kubernetes-fluent-client";\n',
|
|
162
|
+
"/**",
|
|
163
|
+
" * Book nerd",
|
|
164
|
+
" */",
|
|
165
|
+
"export class Book extends GenericKind {",
|
|
166
|
+
" spec?: Spec;",
|
|
167
|
+
"}",
|
|
168
|
+
"",
|
|
169
|
+
"export interface Spec {",
|
|
170
|
+
" author?: string;",
|
|
171
|
+
" title?: string;",
|
|
172
|
+
"}",
|
|
173
|
+
"",
|
|
174
|
+
"RegisterKind(Book, {",
|
|
175
|
+
' group: "example.com",',
|
|
176
|
+
' version: "v1",',
|
|
177
|
+
' kind: "Book",',
|
|
178
|
+
"});",
|
|
179
|
+
];
|
|
180
|
+
const expectedBookV2 = expectedBookV1
|
|
181
|
+
.filter(line => !line.includes("title?"))
|
|
182
|
+
.map(line => line.replace("v1", "v2"));
|
|
183
|
+
|
|
184
|
+
expect(actual["movie-v1"]).toEqual(expectedMovie);
|
|
185
|
+
expect(actual["book-v1"]).toEqual(expectedBookV1);
|
|
186
|
+
expect(actual["book-v2"]).toEqual(expectedBookV2);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("converts CRD to TypeScript with plain option", async () => {
|
|
190
|
+
const options = { source: "test-crd.yaml", language: "ts", plain: true }; // specify your options
|
|
191
|
+
|
|
192
|
+
const actual = await generate(options);
|
|
193
|
+
const expectedMovie = [
|
|
194
|
+
"/**",
|
|
195
|
+
" * Movie nerd",
|
|
196
|
+
" */",
|
|
197
|
+
"export interface Movie {",
|
|
198
|
+
" spec?: Spec;",
|
|
199
|
+
"}",
|
|
200
|
+
"",
|
|
201
|
+
"export interface Spec {",
|
|
202
|
+
" author?: string;",
|
|
203
|
+
" title?: string;",
|
|
204
|
+
"}",
|
|
205
|
+
"",
|
|
206
|
+
];
|
|
207
|
+
const expectedBookV1 = [
|
|
208
|
+
"/**",
|
|
209
|
+
" * Book nerd",
|
|
210
|
+
" */",
|
|
211
|
+
"export interface Book {",
|
|
212
|
+
" spec?: Spec;",
|
|
213
|
+
"}",
|
|
214
|
+
"",
|
|
215
|
+
"export interface Spec {",
|
|
216
|
+
" author?: string;",
|
|
217
|
+
" title?: string;",
|
|
218
|
+
"}",
|
|
219
|
+
"",
|
|
220
|
+
];
|
|
221
|
+
const expectedBookV2 = expectedBookV1
|
|
222
|
+
.filter(line => !line.includes("title?"))
|
|
223
|
+
.map(line => line.replace("v1", "v2"));
|
|
224
|
+
|
|
225
|
+
expect(actual["movie-v1"]).toEqual(expectedMovie);
|
|
226
|
+
expect(actual["book-v1"]).toEqual(expectedBookV1);
|
|
227
|
+
expect(actual["book-v2"]).toEqual(expectedBookV2);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("converts CRD to Go", async () => {
|
|
231
|
+
const options = { source: "test-crd.yaml", language: "go" }; // specify your options
|
|
232
|
+
|
|
233
|
+
const actual = await generate(options);
|
|
234
|
+
const expectedMovie = [
|
|
235
|
+
"// Movie nerd",
|
|
236
|
+
"type Movie struct {",
|
|
237
|
+
'\tSpec *Spec `json:"spec,omitempty"`',
|
|
238
|
+
"}",
|
|
239
|
+
"",
|
|
240
|
+
"type Spec struct {",
|
|
241
|
+
'\tAuthor *string `json:"author,omitempty"`',
|
|
242
|
+
'\tTitle *string `json:"title,omitempty"`',
|
|
243
|
+
"}",
|
|
244
|
+
"",
|
|
245
|
+
];
|
|
246
|
+
const expectedBookV1 = [
|
|
247
|
+
"// Book nerd",
|
|
248
|
+
"type Book struct {",
|
|
249
|
+
'\tSpec *Spec `json:"spec,omitempty"`',
|
|
250
|
+
"}",
|
|
251
|
+
"",
|
|
252
|
+
"type Spec struct {",
|
|
253
|
+
'\tAuthor *string `json:"author,omitempty"`',
|
|
254
|
+
'\tTitle *string `json:"title,omitempty"`',
|
|
255
|
+
"}",
|
|
256
|
+
"",
|
|
257
|
+
];
|
|
258
|
+
const expectedBookV2 = expectedBookV1
|
|
259
|
+
.filter(line => !line.includes("Title"))
|
|
260
|
+
.map(line => line.replace("v1", "v2"));
|
|
261
|
+
|
|
262
|
+
expect(actual["movie-v1"]).toEqual(expectedMovie);
|
|
263
|
+
expect(actual["book-v1"]).toEqual(expectedBookV1);
|
|
264
|
+
expect(actual["book-v2"]).toEqual(expectedBookV2);
|
|
265
|
+
});
|
|
266
|
+
});
|