codify-plugin-lib 1.0.182-beta44 → 1.0.182-beta46
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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/plugin/plugin.js +1 -1
- package/dist/resource/parsed-resource-settings.d.ts +3 -1
- package/dist/resource/parsed-resource-settings.js +15 -2
- package/dist/resource/resource-controller.js +5 -5
- package/dist/resource/resource-settings.d.ts +8 -2
- package/dist/resource/resource-settings.js +2 -2
- package/package.json +3 -2
- package/src/index.ts +1 -0
- package/src/plugin/plugin.test.ts +31 -0
- package/src/plugin/plugin.ts +1 -1
- package/src/resource/parsed-resource-settings.test.ts +24 -0
- package/src/resource/parsed-resource-settings.ts +23 -7
- package/src/resource/resource-controller.test.ts +126 -0
- package/src/resource/resource-controller.ts +5 -6
- package/src/resource/resource-settings.test.ts +36 -0
- package/src/resource/resource-settings.ts +11 -4
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './utils/file-utils.js';
|
|
|
14
14
|
export * from './utils/functions.js';
|
|
15
15
|
export * from './utils/index.js';
|
|
16
16
|
export * from './utils/verbosity-level.js';
|
|
17
|
+
export * from 'zod/v4';
|
|
17
18
|
export async function runPlugin(plugin) {
|
|
18
19
|
const messageHandler = new MessageHandler(plugin);
|
|
19
20
|
process.on('message', (message) => messageHandler.onMessage(message));
|
package/dist/plugin/plugin.js
CHANGED
|
@@ -55,7 +55,7 @@ export class Plugin {
|
|
|
55
55
|
throw new Error(`Cannot get info for resource ${data.type}, resource doesn't exist`);
|
|
56
56
|
}
|
|
57
57
|
const resource = this.resourceControllers.get(data.type);
|
|
58
|
-
const schema = resource.
|
|
58
|
+
const schema = resource.parsedSettings.schema;
|
|
59
59
|
const requiredPropertyNames = (resource.settings.importAndDestroy?.requiredParameters
|
|
60
60
|
?? (typeof resource.settings.allowMultiple === 'object' ? resource.settings.allowMultiple.identifyingParameters : null)
|
|
61
61
|
?? schema?.required
|
|
@@ -18,10 +18,12 @@ export type ParsedParameterSetting = {
|
|
|
18
18
|
export declare class ParsedResourceSettings<T extends StringIndexedObject> implements ResourceSettings<T> {
|
|
19
19
|
private cache;
|
|
20
20
|
id: string;
|
|
21
|
+
description?: string;
|
|
21
22
|
schema?: Partial<JSONSchemaType<T | any>>;
|
|
22
23
|
allowMultiple?: {
|
|
24
|
+
identifyingParameters?: string[];
|
|
23
25
|
matcher?: (desired: Partial<T>, current: Partial<T>) => boolean;
|
|
24
|
-
|
|
26
|
+
findAllParameters?: () => Promise<Array<Partial<T>>>;
|
|
25
27
|
} | boolean;
|
|
26
28
|
removeStatefulParametersBeforeDestroy?: boolean | undefined;
|
|
27
29
|
dependencies?: string[] | undefined;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { ZodObject, z } from 'zod';
|
|
1
2
|
import { StatefulParameterController } from '../stateful-parameter/stateful-parameter-controller.js';
|
|
2
3
|
import { resolveElementEqualsFn, resolveEqualsFn, resolveMatcher, resolveParameterTransformFn } from './resource-settings.js';
|
|
3
4
|
export class ParsedResourceSettings {
|
|
4
5
|
cache = new Map();
|
|
5
6
|
id;
|
|
7
|
+
description;
|
|
6
8
|
schema;
|
|
7
9
|
allowMultiple;
|
|
8
10
|
removeStatefulParametersBeforeDestroy;
|
|
@@ -13,8 +15,19 @@ export class ParsedResourceSettings {
|
|
|
13
15
|
settings;
|
|
14
16
|
constructor(settings) {
|
|
15
17
|
this.settings = settings;
|
|
16
|
-
const { parameterSettings, ...rest } = settings;
|
|
18
|
+
const { parameterSettings, schema, ...rest } = settings;
|
|
17
19
|
Object.assign(this, rest);
|
|
20
|
+
if (schema) {
|
|
21
|
+
this.schema = schema instanceof ZodObject
|
|
22
|
+
? z.toJSONSchema(schema.strict(), {
|
|
23
|
+
target: 'draft-7',
|
|
24
|
+
override(ctx) {
|
|
25
|
+
ctx.jsonSchema.title = settings.id;
|
|
26
|
+
ctx.jsonSchema.description = settings.description ?? `${settings.id} resource. Can be used to manage ${settings.id}`;
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
: schema;
|
|
30
|
+
}
|
|
18
31
|
this.validateSettings();
|
|
19
32
|
}
|
|
20
33
|
get typeId() {
|
|
@@ -118,7 +131,7 @@ export class ParsedResourceSettings {
|
|
|
118
131
|
&& typeof this.settings.allowMultiple === 'object' && this.settings.allowMultiple?.identifyingParameters?.includes(k))) {
|
|
119
132
|
throw new Error(`Resource: ${this.id}. Stateful parameters are not allowed to be identifying parameters for allowMultiple.`);
|
|
120
133
|
}
|
|
121
|
-
const schema = this.
|
|
134
|
+
const schema = this.schema;
|
|
122
135
|
if (!this.settings.importAndDestroy && (schema?.oneOf
|
|
123
136
|
&& Array.isArray(schema.oneOf)
|
|
124
137
|
&& schema.oneOf.some((s) => s.required))
|
|
@@ -17,16 +17,16 @@ export class ResourceController {
|
|
|
17
17
|
this.settings = resource.getSettings();
|
|
18
18
|
this.typeId = this.settings.id;
|
|
19
19
|
this.dependencies = this.settings.dependencies ?? [];
|
|
20
|
-
|
|
20
|
+
this.parsedSettings = new ParsedResourceSettings(this.settings);
|
|
21
|
+
if (this.parsedSettings.schema) {
|
|
21
22
|
this.ajv = new Ajv({
|
|
22
23
|
allErrors: true,
|
|
23
24
|
strict: true,
|
|
24
25
|
strictRequired: false,
|
|
25
26
|
allowUnionTypes: true
|
|
26
27
|
});
|
|
27
|
-
this.schemaValidator = this.ajv.compile(this.
|
|
28
|
+
this.schemaValidator = this.ajv.compile(this.parsedSettings.schema);
|
|
28
29
|
}
|
|
29
|
-
this.parsedSettings = new ParsedResourceSettings(this.settings);
|
|
30
30
|
}
|
|
31
31
|
async initialize() {
|
|
32
32
|
return this.resource.initialize();
|
|
@@ -374,8 +374,8 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
374
374
|
.sort((a, b) => this.parsedSettings.statefulParameterOrder.get(a.name) - this.parsedSettings.statefulParameterOrder.get(b.name));
|
|
375
375
|
}
|
|
376
376
|
getAllParameterKeys() {
|
|
377
|
-
return this.
|
|
378
|
-
? Object.keys(this.
|
|
377
|
+
return this.parsedSettings.schema
|
|
378
|
+
? Object.keys(this.parsedSettings.schema?.properties)
|
|
379
379
|
: Object.keys(this.parsedSettings.parameterSettings);
|
|
380
380
|
}
|
|
381
381
|
getParametersToRefreshForImport(parameters, context) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { JSONSchemaType } from 'ajv';
|
|
2
2
|
import { OS, StringIndexedObject } from 'codify-schemas';
|
|
3
|
+
import { ZodObject } from 'zod';
|
|
3
4
|
import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
|
|
5
|
+
import { ParsedResourceSettings } from './parsed-resource-settings.js';
|
|
4
6
|
import { RefreshContext } from './resource.js';
|
|
5
7
|
export interface InputTransformation {
|
|
6
8
|
to: (input: any) => Promise<any> | any;
|
|
@@ -21,12 +23,16 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
21
23
|
/**
|
|
22
24
|
* Schema to validate user configs with. Must be in the format JSON Schema draft07
|
|
23
25
|
*/
|
|
24
|
-
schema?: Partial<JSONSchemaType<T | any
|
|
26
|
+
schema?: Partial<JSONSchemaType<T | any>> | ZodObject;
|
|
25
27
|
/**
|
|
26
28
|
* Mark the resource as sensitive. Defaults to false. This prevents the resource from automatically being imported by init and import.
|
|
27
29
|
* This differs from the parameter level sensitivity which also prevents the parameter value from being displayed in the plan.
|
|
28
30
|
*/
|
|
29
31
|
isSensitive?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* An optional description of the resource. This does not affect the behavior of the resource.
|
|
34
|
+
*/
|
|
35
|
+
description?: string;
|
|
30
36
|
/**
|
|
31
37
|
* Allow multiple of the same resource to unique. Set truthy if
|
|
32
38
|
* multiples are allowed, for example for applications, there can be multiple copy of the same application installed
|
|
@@ -290,4 +296,4 @@ export declare function resolveEqualsFn(parameter: ParameterSetting): (desired:
|
|
|
290
296
|
export declare function resolveElementEqualsFn(parameter: ArrayParameterSetting): (desired: unknown, current: unknown) => boolean;
|
|
291
297
|
export declare function resolveFnFromEqualsFnOrString(fnOrString: ((a: unknown, b: unknown) => boolean) | ParameterSettingType | undefined): ((a: unknown, b: unknown) => boolean) | undefined;
|
|
292
298
|
export declare function resolveParameterTransformFn(parameter: ParameterSetting): InputTransformation | undefined;
|
|
293
|
-
export declare function resolveMatcher<T extends StringIndexedObject>(settings:
|
|
299
|
+
export declare function resolveMatcher<T extends StringIndexedObject>(settings: ParsedResourceSettings<T>): (desired: Partial<T>, current: Partial<T>) => boolean;
|
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { addVariablesToPath, areArraysEqual, resolvePathWithVariables, tildify, untildify } from '../utils/functions.js';
|
|
4
4
|
const ParameterEqualsDefaults = {
|
|
5
5
|
'boolean': (a, b) => Boolean(a) === Boolean(b),
|
|
6
|
-
'directory'
|
|
6
|
+
'directory'(a, b) {
|
|
7
7
|
let transformedA = resolvePathWithVariables(untildify(String(a)));
|
|
8
8
|
let transformedB = resolvePathWithVariables(untildify(String(b)));
|
|
9
9
|
if (transformedA.startsWith('.')) { // Only relative paths start with '.'
|
|
@@ -65,7 +65,7 @@ export function resolveFnFromEqualsFnOrString(fnOrString) {
|
|
|
65
65
|
const ParameterTransformationDefaults = {
|
|
66
66
|
'directory': {
|
|
67
67
|
to: (a) => resolvePathWithVariables((untildify(String(a)))),
|
|
68
|
-
from
|
|
68
|
+
from(a, original) {
|
|
69
69
|
if (ParameterEqualsDefaults.directory(a, original)) {
|
|
70
70
|
return original;
|
|
71
71
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-lib",
|
|
3
|
-
"version": "1.0.182-
|
|
3
|
+
"version": "1.0.182-beta46",
|
|
4
4
|
"description": "Library plugin library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"lodash.isequal": "^4.5.0",
|
|
27
27
|
"nanoid": "^5.0.9",
|
|
28
28
|
"strip-ansi": "^7.1.0",
|
|
29
|
-
"uuid": "^10.0.0"
|
|
29
|
+
"uuid": "^10.0.0",
|
|
30
|
+
"zod": "4.1.13"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@apidevtools/json-schema-ref-parser": "^11.7.2",
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from './utils/file-utils.js'
|
|
|
16
16
|
export * from './utils/functions.js'
|
|
17
17
|
export * from './utils/index.js'
|
|
18
18
|
export * from './utils/verbosity-level.js'
|
|
19
|
+
export * from 'zod/v4';
|
|
19
20
|
|
|
20
21
|
export async function runPlugin(plugin: Plugin) {
|
|
21
22
|
const messageHandler = new MessageHandler(plugin);
|
|
@@ -7,6 +7,7 @@ import { spy } from 'sinon';
|
|
|
7
7
|
import { ResourceSettings } from '../resource/resource-settings.js';
|
|
8
8
|
import { TestConfig, TestStatefulParameter } from '../utils/test-utils.test.js';
|
|
9
9
|
import { getPty } from '../pty/index.js';
|
|
10
|
+
import { z } from 'zod';
|
|
10
11
|
|
|
11
12
|
interface TestConfig extends StringIndexedObject {
|
|
12
13
|
propA: string;
|
|
@@ -170,6 +171,36 @@ describe('Plugin tests', () => {
|
|
|
170
171
|
})
|
|
171
172
|
})
|
|
172
173
|
|
|
174
|
+
it('Can get resource info (zod schema)', async () => {
|
|
175
|
+
const schema = z
|
|
176
|
+
.object({
|
|
177
|
+
plugins: z
|
|
178
|
+
.array(z.string())
|
|
179
|
+
.describe(
|
|
180
|
+
'Asdf plugins to install. See: https://github.com/asdf-community for a full list'
|
|
181
|
+
)
|
|
182
|
+
})
|
|
183
|
+
.strict()
|
|
184
|
+
|
|
185
|
+
const resource = new class extends TestResource {
|
|
186
|
+
getSettings(): ResourceSettings<TestConfig> {
|
|
187
|
+
return {
|
|
188
|
+
id: 'typeId',
|
|
189
|
+
operatingSystems: [OS.Darwin],
|
|
190
|
+
schema,
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const testPlugin = Plugin.create('testPlugin', [resource as any])
|
|
195
|
+
|
|
196
|
+
const resourceInfo = await testPlugin.getResourceInfo({ type: 'typeId' })
|
|
197
|
+
expect(resourceInfo.import).toMatchObject({
|
|
198
|
+
requiredParameters: [
|
|
199
|
+
'plugins'
|
|
200
|
+
]
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
173
204
|
it('Get resource info to default import to the one specified in the resource settings', async () => {
|
|
174
205
|
const schema = {
|
|
175
206
|
'$schema': 'http://json-schema.org/draft-07/schema',
|
package/src/plugin/plugin.ts
CHANGED
|
@@ -89,7 +89,7 @@ export class Plugin {
|
|
|
89
89
|
|
|
90
90
|
const resource = this.resourceControllers.get(data.type)!;
|
|
91
91
|
|
|
92
|
-
const schema = resource.
|
|
92
|
+
const schema = resource.parsedSettings.schema as JSONSchemaType<any> | undefined;
|
|
93
93
|
const requiredPropertyNames = (
|
|
94
94
|
resource.settings.importAndDestroy?.requiredParameters
|
|
95
95
|
?? (typeof resource.settings.allowMultiple === 'object' ? resource.settings.allowMultiple.identifyingParameters : null)
|
|
@@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { ResourceSettings } from './resource-settings.js';
|
|
3
3
|
import { ParsedResourceSettings } from './parsed-resource-settings.js';
|
|
4
4
|
import { TestConfig } from '../utils/test-utils.test.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { OS } from 'codify-schemas';
|
|
5
7
|
|
|
6
8
|
describe('Resource options parser tests', () => {
|
|
7
9
|
it('Parses default values from options', () => {
|
|
@@ -159,4 +161,26 @@ describe('Resource options parser tests', () => {
|
|
|
159
161
|
|
|
160
162
|
expect(() => new ParsedResourceSettings(option)).toThrowError()
|
|
161
163
|
})
|
|
164
|
+
|
|
165
|
+
it('Can handle a zod schema', () => {
|
|
166
|
+
|
|
167
|
+
const schema = z.object({
|
|
168
|
+
propA: z.string(),
|
|
169
|
+
repository: z.string(),
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const option: ResourceSettings<z.infer<typeof schema>> = {
|
|
173
|
+
id: 'typeId',
|
|
174
|
+
operatingSystems: [OS.Darwin],
|
|
175
|
+
schema,
|
|
176
|
+
importAndDestroy: {
|
|
177
|
+
defaultRefreshValues: {
|
|
178
|
+
repository: 'abc'
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log(new ParsedResourceSettings(option))
|
|
184
|
+
|
|
185
|
+
})
|
|
162
186
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { JSONSchemaType } from 'ajv';
|
|
2
2
|
import { OS, StringIndexedObject } from 'codify-schemas';
|
|
3
|
+
import { ZodObject, z } from 'zod';
|
|
3
4
|
|
|
4
5
|
import { StatefulParameterController } from '../stateful-parameter/stateful-parameter-controller.js';
|
|
5
6
|
import {
|
|
@@ -7,12 +8,12 @@ import {
|
|
|
7
8
|
DefaultParameterSetting,
|
|
8
9
|
InputTransformation,
|
|
9
10
|
ParameterSetting,
|
|
11
|
+
ResourceSettings,
|
|
12
|
+
StatefulParameterSetting,
|
|
10
13
|
resolveElementEqualsFn,
|
|
11
14
|
resolveEqualsFn,
|
|
12
15
|
resolveMatcher,
|
|
13
|
-
resolveParameterTransformFn
|
|
14
|
-
ResourceSettings,
|
|
15
|
-
StatefulParameterSetting
|
|
16
|
+
resolveParameterTransformFn
|
|
16
17
|
} from './resource-settings.js';
|
|
17
18
|
|
|
18
19
|
export interface ParsedStatefulParameterSetting extends DefaultParameterSetting {
|
|
@@ -29,7 +30,7 @@ export type ParsedArrayParameterSetting = {
|
|
|
29
30
|
|
|
30
31
|
export type ParsedParameterSetting =
|
|
31
32
|
{
|
|
32
|
-
|
|
33
|
+
isEqual: (desired: unknown, current: unknown) => boolean;
|
|
33
34
|
} & (DefaultParameterSetting
|
|
34
35
|
| ParsedArrayParameterSetting
|
|
35
36
|
| ParsedStatefulParameterSetting)
|
|
@@ -37,10 +38,13 @@ export type ParsedParameterSetting =
|
|
|
37
38
|
export class ParsedResourceSettings<T extends StringIndexedObject> implements ResourceSettings<T> {
|
|
38
39
|
private cache = new Map<string, unknown>();
|
|
39
40
|
id!: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
|
|
40
43
|
schema?: Partial<JSONSchemaType<T | any>>;
|
|
41
44
|
allowMultiple?: {
|
|
45
|
+
identifyingParameters?: string[];
|
|
42
46
|
matcher?: (desired: Partial<T>, current: Partial<T>) => boolean;
|
|
43
|
-
|
|
47
|
+
findAllParameters?: () => Promise<Array<Partial<T>>>
|
|
44
48
|
} | boolean;
|
|
45
49
|
|
|
46
50
|
removeStatefulParametersBeforeDestroy?: boolean | undefined;
|
|
@@ -54,10 +58,22 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
|
|
|
54
58
|
|
|
55
59
|
constructor(settings: ResourceSettings<T>) {
|
|
56
60
|
this.settings = settings;
|
|
61
|
+
const { parameterSettings, schema, ...rest } = settings;
|
|
57
62
|
|
|
58
|
-
const { parameterSettings, ...rest } = settings;
|
|
59
63
|
Object.assign(this, rest);
|
|
60
64
|
|
|
65
|
+
if (schema) {
|
|
66
|
+
this.schema = schema instanceof ZodObject
|
|
67
|
+
? z.toJSONSchema(schema.strict(), {
|
|
68
|
+
target: 'draft-7',
|
|
69
|
+
override(ctx) {
|
|
70
|
+
ctx.jsonSchema.title = settings.id;
|
|
71
|
+
ctx.jsonSchema.description = settings.description ?? `${settings.id} resource. Can be used to manage ${settings.id}`;
|
|
72
|
+
}
|
|
73
|
+
}) as JSONSchemaType<T>
|
|
74
|
+
: schema;
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
this.validateSettings();
|
|
62
78
|
}
|
|
63
79
|
|
|
@@ -199,7 +215,7 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
|
|
|
199
215
|
throw new Error(`Resource: ${this.id}. Stateful parameters are not allowed to be identifying parameters for allowMultiple.`)
|
|
200
216
|
}
|
|
201
217
|
|
|
202
|
-
const schema = this.
|
|
218
|
+
const schema = this.schema as JSONSchemaType<any>;
|
|
203
219
|
if (!this.settings.importAndDestroy && (schema?.oneOf
|
|
204
220
|
&& Array.isArray(schema.oneOf)
|
|
205
221
|
&& schema.oneOf.some((s) => s.required)
|
|
@@ -11,6 +11,7 @@ import { tildify, untildify } from '../utils/functions.js';
|
|
|
11
11
|
import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
|
|
12
12
|
import { Plan } from '../plan/plan.js';
|
|
13
13
|
import os from 'node:os';
|
|
14
|
+
import { z } from 'zod';
|
|
14
15
|
|
|
15
16
|
describe('Resource tests', () => {
|
|
16
17
|
|
|
@@ -952,4 +953,129 @@ describe('Resource tests', () => {
|
|
|
952
953
|
|
|
953
954
|
process.env = oldProcessEnv;
|
|
954
955
|
})
|
|
956
|
+
|
|
957
|
+
it('Can import and return all of the imported parameters (zod schema)', async () => {
|
|
958
|
+
const schema = z.object({
|
|
959
|
+
path: z
|
|
960
|
+
.string()
|
|
961
|
+
.describe(
|
|
962
|
+
'A list of paths to add to the PATH environment variable'
|
|
963
|
+
),
|
|
964
|
+
paths: z
|
|
965
|
+
.array(z.string())
|
|
966
|
+
.describe(
|
|
967
|
+
'A list of paths to add to the PATH environment variable'
|
|
968
|
+
),
|
|
969
|
+
prepend: z
|
|
970
|
+
.boolean()
|
|
971
|
+
.describe(
|
|
972
|
+
'Whether to prepend the paths to the PATH environment variable'
|
|
973
|
+
),
|
|
974
|
+
declarationsOnly: z
|
|
975
|
+
.boolean()
|
|
976
|
+
.describe(
|
|
977
|
+
'Whether to only declare the paths in the PATH environment variable'
|
|
978
|
+
),
|
|
979
|
+
})
|
|
980
|
+
|
|
981
|
+
const resource = new class extends TestResource {
|
|
982
|
+
getSettings(): ResourceSettings<any> {
|
|
983
|
+
return {
|
|
984
|
+
id: 'path',
|
|
985
|
+
schema,
|
|
986
|
+
operatingSystems: [OS.Darwin],
|
|
987
|
+
parameterSettings: {
|
|
988
|
+
path: { type: 'directory' },
|
|
989
|
+
paths: { canModify: true, type: 'array', itemType: 'directory' },
|
|
990
|
+
prepend: { default: false, setting: true },
|
|
991
|
+
declarationsOnly: { default: false, setting: true },
|
|
992
|
+
},
|
|
993
|
+
importAndDestroy: {
|
|
994
|
+
refreshMapper: (input, context) => {
|
|
995
|
+
if (Object.keys(input).length === 0) {
|
|
996
|
+
return { paths: [], declarationsOnly: true };
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
return input;
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
allowMultiple: {
|
|
1003
|
+
matcher: (desired, current) => {
|
|
1004
|
+
if (desired.path) {
|
|
1005
|
+
return desired.path === current.path;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
const currentPaths = new Set(current.paths)
|
|
1009
|
+
return desired.paths?.some((p) => currentPaths.has(p));
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
async refresh(parameters: Partial<TestConfig>): Promise<Partial<TestConfig> | null> {
|
|
1016
|
+
return {
|
|
1017
|
+
paths: [
|
|
1018
|
+
`${os.homedir()}/.pyenv/bin`,
|
|
1019
|
+
`${os.homedir()}/.bun/bin`,
|
|
1020
|
+
`${os.homedir()}/.deno/bin`,
|
|
1021
|
+
`${os.homedir()}/.jenv/bin`,
|
|
1022
|
+
`${os.homedir()}/a/random/path`,
|
|
1023
|
+
`${os.homedir()}/.nvm/.bin/2`,
|
|
1024
|
+
`${os.homedir()}/.nvm/.bin/3`
|
|
1025
|
+
]
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
const oldProcessEnv = structuredClone(process.env);
|
|
1031
|
+
|
|
1032
|
+
process.env['PYENV_ROOT'] = `${os.homedir()}/.pyenv`
|
|
1033
|
+
process.env['BUN_INSTALL'] = `${os.homedir()}/.bun`
|
|
1034
|
+
process.env['DENO_INSTALL'] = `${os.homedir()}/.deno`
|
|
1035
|
+
process.env['JENV'] = `${os.homedir()}/.jenv`
|
|
1036
|
+
process.env['NVM_DIR'] = `${os.homedir()}/.nvm`
|
|
1037
|
+
|
|
1038
|
+
const controller = new ResourceController(resource);
|
|
1039
|
+
const importResult1 = await controller.import({ type: 'path' }, {});
|
|
1040
|
+
expect(importResult1).toMatchObject([
|
|
1041
|
+
{
|
|
1042
|
+
'core': {
|
|
1043
|
+
'type': 'path'
|
|
1044
|
+
},
|
|
1045
|
+
'parameters': {
|
|
1046
|
+
'paths': [
|
|
1047
|
+
'$PYENV_ROOT/bin',
|
|
1048
|
+
'$BUN_INSTALL/bin',
|
|
1049
|
+
'$DENO_INSTALL/bin',
|
|
1050
|
+
'$JENV/bin',
|
|
1051
|
+
'~/a/random/path',
|
|
1052
|
+
'$NVM_DIR/.bin/2',
|
|
1053
|
+
'$NVM_DIR/.bin/3'
|
|
1054
|
+
]
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
])
|
|
1058
|
+
|
|
1059
|
+
const importResult2 = await controller.import({ type: 'path' }, { paths: ['$PYENV_ROOT/bin', '$BUN_INSTALL/bin'] });
|
|
1060
|
+
expect(importResult2).toMatchObject([
|
|
1061
|
+
{
|
|
1062
|
+
'core': {
|
|
1063
|
+
'type': 'path'
|
|
1064
|
+
},
|
|
1065
|
+
'parameters': {
|
|
1066
|
+
'paths': [
|
|
1067
|
+
'$PYENV_ROOT/bin',
|
|
1068
|
+
'$BUN_INSTALL/bin',
|
|
1069
|
+
'$DENO_INSTALL/bin',
|
|
1070
|
+
'$JENV/bin',
|
|
1071
|
+
'~/a/random/path',
|
|
1072
|
+
'$NVM_DIR/.bin/2',
|
|
1073
|
+
'$NVM_DIR/.bin/3'
|
|
1074
|
+
]
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
])
|
|
1078
|
+
|
|
1079
|
+
process.env = oldProcessEnv;
|
|
1080
|
+
})
|
|
955
1081
|
});
|
|
@@ -36,18 +36,17 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
36
36
|
|
|
37
37
|
this.typeId = this.settings.id;
|
|
38
38
|
this.dependencies = this.settings.dependencies ?? [];
|
|
39
|
+
this.parsedSettings = new ParsedResourceSettings<T>(this.settings);
|
|
39
40
|
|
|
40
|
-
if (this.
|
|
41
|
+
if (this.parsedSettings.schema) {
|
|
41
42
|
this.ajv = new Ajv({
|
|
42
43
|
allErrors: true,
|
|
43
44
|
strict: true,
|
|
44
45
|
strictRequired: false,
|
|
45
46
|
allowUnionTypes: true
|
|
46
47
|
})
|
|
47
|
-
this.schemaValidator = this.ajv.compile(this.
|
|
48
|
+
this.schemaValidator = this.ajv.compile(this.parsedSettings.schema);
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
-
this.parsedSettings = new ParsedResourceSettings<T>(this.settings);
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
async initialize(): Promise<void> {
|
|
@@ -526,8 +525,8 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
526
525
|
}
|
|
527
526
|
|
|
528
527
|
private getAllParameterKeys(): string[] {
|
|
529
|
-
return this.
|
|
530
|
-
? Object.keys((this.
|
|
528
|
+
return this.parsedSettings.schema
|
|
529
|
+
? Object.keys((this.parsedSettings.schema as any)?.properties)
|
|
531
530
|
: Object.keys(this.parsedSettings.parameterSettings);
|
|
532
531
|
}
|
|
533
532
|
|
|
@@ -13,6 +13,7 @@ import { ArrayParameterSetting, ParameterSetting, ResourceSettings } from './res
|
|
|
13
13
|
import { ResourceController } from './resource-controller.js';
|
|
14
14
|
import os from 'node:os';
|
|
15
15
|
import path from 'node:path';
|
|
16
|
+
import { z } from 'zod';
|
|
16
17
|
|
|
17
18
|
describe('Resource parameter tests', () => {
|
|
18
19
|
it('Generates a resource plan that includes stateful parameters (create)', async () => {
|
|
@@ -1174,4 +1175,39 @@ describe('Resource parameter tests', () => {
|
|
|
1174
1175
|
expect(from2).to.eq('$HOME/abc/def')
|
|
1175
1176
|
|
|
1176
1177
|
})
|
|
1178
|
+
|
|
1179
|
+
it('Can match directories 2', async () => {
|
|
1180
|
+
|
|
1181
|
+
const schema = z.object({
|
|
1182
|
+
propA: z.string(),
|
|
1183
|
+
propB: z.number(),
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
const resource = new class extends TestResource {
|
|
1187
|
+
getSettings(): ResourceSettings<z.infer<typeof schema>> {
|
|
1188
|
+
return {
|
|
1189
|
+
id: 'resourceType',
|
|
1190
|
+
schema,
|
|
1191
|
+
operatingSystems: [OS.Darwin],
|
|
1192
|
+
parameterSettings: {
|
|
1193
|
+
propA: { type: 'directory' }
|
|
1194
|
+
},
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
const controller = new ResourceController(resource);
|
|
1200
|
+
const transformations = controller.parsedSettings.inputTransformations.propA;
|
|
1201
|
+
|
|
1202
|
+
const to = transformations!.to('$HOME/abc/def')
|
|
1203
|
+
expect(to).to.eq(os.homedir() + '/abc/def')
|
|
1204
|
+
|
|
1205
|
+
const from = transformations!.from(os.homedir() + '/abc/def')
|
|
1206
|
+
expect(from).to.eq('~/abc/def')
|
|
1207
|
+
|
|
1208
|
+
const from2 = transformations!.from(os.homedir() + '/abc/def', '$HOME/abc/def')
|
|
1209
|
+
expect(from2).to.eq('$HOME/abc/def')
|
|
1210
|
+
|
|
1211
|
+
})
|
|
1212
|
+
|
|
1177
1213
|
})
|
|
@@ -2,6 +2,7 @@ import { JSONSchemaType } from 'ajv';
|
|
|
2
2
|
import { OS, StringIndexedObject } from 'codify-schemas';
|
|
3
3
|
import isObjectsEqual from 'lodash.isequal'
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { ZodObject } from 'zod';
|
|
5
6
|
|
|
6
7
|
import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
|
|
7
8
|
import {
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
tildify,
|
|
12
13
|
untildify
|
|
13
14
|
} from '../utils/functions.js';
|
|
15
|
+
import { ParsedResourceSettings } from './parsed-resource-settings.js';
|
|
14
16
|
import { RefreshContext } from './resource.js';
|
|
15
17
|
|
|
16
18
|
export interface InputTransformation {
|
|
@@ -36,7 +38,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
36
38
|
/**
|
|
37
39
|
* Schema to validate user configs with. Must be in the format JSON Schema draft07
|
|
38
40
|
*/
|
|
39
|
-
schema?: Partial<JSONSchemaType<T | any
|
|
41
|
+
schema?: Partial<JSONSchemaType<T | any>> | ZodObject;
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
44
|
* Mark the resource as sensitive. Defaults to false. This prevents the resource from automatically being imported by init and import.
|
|
@@ -44,6 +46,11 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
44
46
|
*/
|
|
45
47
|
isSensitive?: boolean;
|
|
46
48
|
|
|
49
|
+
/**
|
|
50
|
+
* An optional description of the resource. This does not affect the behavior of the resource.
|
|
51
|
+
*/
|
|
52
|
+
description?: string;
|
|
53
|
+
|
|
47
54
|
/**
|
|
48
55
|
* Allow multiple of the same resource to unique. Set truthy if
|
|
49
56
|
* multiples are allowed, for example for applications, there can be multiple copy of the same application installed
|
|
@@ -349,7 +356,7 @@ export interface StatefulParameterSetting extends DefaultParameterSetting {
|
|
|
349
356
|
|
|
350
357
|
const ParameterEqualsDefaults: Partial<Record<ParameterSettingType, (a: unknown, b: unknown) => boolean>> = {
|
|
351
358
|
'boolean': (a: unknown, b: unknown) => Boolean(a) === Boolean(b),
|
|
352
|
-
'directory'
|
|
359
|
+
'directory'(a: unknown, b: unknown) {
|
|
353
360
|
let transformedA = resolvePathWithVariables(untildify(String(a)))
|
|
354
361
|
let transformedB = resolvePathWithVariables(untildify(String(b)))
|
|
355
362
|
|
|
@@ -430,7 +437,7 @@ export function resolveFnFromEqualsFnOrString(
|
|
|
430
437
|
const ParameterTransformationDefaults: Partial<Record<ParameterSettingType, InputTransformation>> = {
|
|
431
438
|
'directory': {
|
|
432
439
|
to: (a: unknown) => resolvePathWithVariables((untildify(String(a)))),
|
|
433
|
-
from
|
|
440
|
+
from(a: unknown, original) {
|
|
434
441
|
if (ParameterEqualsDefaults.directory!(a, original)) {
|
|
435
442
|
return original;
|
|
436
443
|
}
|
|
@@ -489,7 +496,7 @@ export function resolveParameterTransformFn(
|
|
|
489
496
|
}
|
|
490
497
|
|
|
491
498
|
export function resolveMatcher<T extends StringIndexedObject>(
|
|
492
|
-
settings:
|
|
499
|
+
settings: ParsedResourceSettings<T>
|
|
493
500
|
): (desired: Partial<T>, current: Partial<T>) => boolean {
|
|
494
501
|
return typeof settings.allowMultiple === 'boolean' || !settings.allowMultiple?.matcher
|
|
495
502
|
? ((desired: Partial<T>, current: Partial<T>) => {
|