codify-plugin-lib 1.0.182-beta26 → 1.0.182-beta29

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.
@@ -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.settings.schema;
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
@@ -10,8 +10,8 @@ export declare class BackgroundPty implements IPty {
10
10
  private basePty;
11
11
  private promiseQueue;
12
12
  constructor();
13
- spawn(cmd: string, options?: SpawnOptions): Promise<SpawnResult>;
14
- spawnSafe(cmd: string, options?: SpawnOptions): Promise<SpawnResult>;
13
+ spawn(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>;
14
+ spawnSafe(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>;
15
15
  kill(): Promise<{
16
16
  exitCode: number;
17
17
  signal?: number | undefined;
@@ -30,11 +30,12 @@ export class BackgroundPty {
30
30
  async spawn(cmd, options) {
31
31
  const spawnResult = await this.spawnSafe(cmd, options);
32
32
  if (spawnResult.status !== 'success') {
33
- throw new SpawnError(cmd, spawnResult.exitCode, spawnResult.data);
33
+ throw new SpawnError(Array.isArray(cmd) ? cmd.join(' ') : cmd, spawnResult.exitCode, spawnResult.data);
34
34
  }
35
35
  return spawnResult;
36
36
  }
37
37
  async spawnSafe(cmd, options) {
38
+ cmd = Array.isArray(cmd) ? cmd.join('\\\n') : cmd;
38
39
  // cid is command id
39
40
  const cid = nanoid(10);
40
41
  debugLog(cid);
@@ -36,8 +36,8 @@ export declare class SpawnError extends Error {
36
36
  constructor(cmd: string, exitCode: number, data: string);
37
37
  }
38
38
  export interface IPty {
39
- spawn(cmd: string, options?: SpawnOptions): Promise<SpawnResult>;
40
- spawnSafe(cmd: string, options?: SpawnOptions): Promise<SpawnResult>;
39
+ spawn(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>;
40
+ spawnSafe(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>;
41
41
  kill(): Promise<{
42
42
  exitCode: number;
43
43
  signal?: number | undefined;
@@ -6,8 +6,8 @@ import { IPty, SpawnOptions, SpawnResult } from './index.js';
6
6
  * without a tty (or even a stdin) attached so interactive commands will not work.
7
7
  */
8
8
  export declare class SequentialPty implements IPty {
9
- spawn(cmd: string, options?: SpawnOptions): Promise<SpawnResult>;
10
- spawnSafe(cmd: string, options?: SpawnOptions): Promise<SpawnResult>;
9
+ spawn(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>;
10
+ spawnSafe(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>;
11
11
  kill(): Promise<{
12
12
  exitCode: number;
13
13
  signal?: number | undefined;
@@ -22,11 +22,12 @@ export class SequentialPty {
22
22
  async spawn(cmd, options) {
23
23
  const spawnResult = await this.spawnSafe(cmd, options);
24
24
  if (spawnResult.status !== 'success') {
25
- throw new SpawnError(cmd, spawnResult.exitCode, spawnResult.data);
25
+ throw new SpawnError(Array.isArray(cmd) ? cmd.join('\n') : cmd, spawnResult.exitCode, spawnResult.data);
26
26
  }
27
27
  return spawnResult;
28
28
  }
29
29
  async spawnSafe(cmd, options) {
30
+ cmd = Array.isArray(cmd) ? cmd.join(' ') : cmd;
30
31
  if (cmd.includes('sudo')) {
31
32
  throw new Error('Do not directly use sudo. Use the option { requiresRoot: true } instead');
32
33
  }
@@ -34,7 +35,7 @@ export class SequentialPty {
34
35
  if (options?.stdin || options?.requiresRoot) {
35
36
  return this.externalSpawn(cmd, options);
36
37
  }
37
- console.log(`Running command: ${cmd}` + (options?.cwd ? `(${options?.cwd})` : ''));
38
+ console.log(`Running command: ${Array.isArray(cmd) ? cmd.join('\\\n') : cmd}` + (options?.cwd ? `(${options?.cwd})` : ''));
38
39
  return new Promise((resolve) => {
39
40
  const output = [];
40
41
  const historyIgnore = Utils.getShell() === Shell.ZSH ? { HISTORY_IGNORE: '*' } : { HISTIGNORE: '*' };
@@ -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
- requiredParameters?: string[];
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,17 @@ 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
+ this.schema = schema instanceof ZodObject
21
+ ? z.toJSONSchema(schema, {
22
+ target: 'draft-7',
23
+ override(ctx) {
24
+ ctx.jsonSchema.title = settings.id;
25
+ ctx.jsonSchema.description = settings.description ?? `${settings.id} resource. Can be used to manage ${settings.id}`;
26
+ }
27
+ })
28
+ : schema;
18
29
  this.validateSettings();
19
30
  }
20
31
  get typeId() {
@@ -118,7 +129,7 @@ export class ParsedResourceSettings {
118
129
  && typeof this.settings.allowMultiple === 'object' && this.settings.allowMultiple?.identifyingParameters?.includes(k))) {
119
130
  throw new Error(`Resource: ${this.id}. Stateful parameters are not allowed to be identifying parameters for allowMultiple.`);
120
131
  }
121
- const schema = this.settings.schema;
132
+ const schema = this.schema;
122
133
  if (!this.settings.importAndDestroy && (schema?.oneOf
123
134
  && Array.isArray(schema.oneOf)
124
135
  && 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
- if (this.settings.schema) {
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.settings.schema);
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();
@@ -1,7 +1,9 @@
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';
4
5
  import { RefreshContext } from './resource.js';
6
+ import { ParsedResourceSettings } from './parsed-resource-settings.js';
5
7
  export interface InputTransformation {
6
8
  to: (input: any) => Promise<any> | any;
7
9
  from: (current: any, original: 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: ResourceSettings<T>): (desired: Partial<T>, current: Partial<T>) => boolean;
299
+ export declare function resolveMatcher<T extends StringIndexedObject>(settings: ParsedResourceSettings<T>): (desired: Partial<T>, current: Partial<T>) => boolean;
@@ -25,7 +25,6 @@ export function tildify(pathWithTilde) {
25
25
  return homeDirectory ? pathWithTilde.replace(homeDirectory, '~') : pathWithTilde;
26
26
  }
27
27
  export function resolvePathWithVariables(pathWithVariables) {
28
- // @ts-expect-error Ignore this for now
29
28
  return pathWithVariables.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b]);
30
29
  }
31
30
  export function addVariablesToPath(pathWithoutVariables) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.182-beta26",
3
+ "version": "1.0.182-beta29",
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",
@@ -89,7 +89,7 @@ export class Plugin {
89
89
 
90
90
  const resource = this.resourceControllers.get(data.type)!;
91
91
 
92
- const schema = resource.settings.schema as JSONSchemaType<any> | undefined;
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)
@@ -33,17 +33,19 @@ export class BackgroundPty implements IPty {
33
33
  this.initialize();
34
34
  }
35
35
 
36
- async spawn(cmd: string, options?: SpawnOptions): Promise<SpawnResult> {
36
+ async spawn(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult> {
37
37
  const spawnResult = await this.spawnSafe(cmd, options);
38
38
 
39
39
  if (spawnResult.status !== 'success') {
40
- throw new SpawnError(cmd, spawnResult.exitCode, spawnResult.data);
40
+ throw new SpawnError(Array.isArray(cmd) ? cmd.join(' ') : cmd, spawnResult.exitCode, spawnResult.data);
41
41
  }
42
42
 
43
43
  return spawnResult;
44
44
  }
45
45
 
46
- async spawnSafe(cmd: string, options?: SpawnOptions): Promise<SpawnResult> {
46
+ async spawnSafe(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult> {
47
+ cmd = Array.isArray(cmd) ? cmd.join('\\\n') : cmd;
48
+
47
49
  // cid is command id
48
50
  const cid = nanoid(10);
49
51
  debugLog(cid);
package/src/pty/index.ts CHANGED
@@ -50,9 +50,9 @@ export class SpawnError extends Error {
50
50
  }
51
51
 
52
52
  export interface IPty {
53
- spawn(cmd: string, options?: SpawnOptions): Promise<SpawnResult>
53
+ spawn(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>
54
54
 
55
- spawnSafe(cmd: string, options?: SpawnOptions): Promise<SpawnResult>
55
+ spawnSafe(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult>
56
56
 
57
57
  kill(): Promise<{ exitCode: number, signal?: number | undefined }>
58
58
  }
@@ -23,17 +23,19 @@ const validateSudoRequestResponse = ajv.compile(CommandRequestResponseDataSchema
23
23
  * without a tty (or even a stdin) attached so interactive commands will not work.
24
24
  */
25
25
  export class SequentialPty implements IPty {
26
- async spawn(cmd: string, options?: SpawnOptions): Promise<SpawnResult> {
26
+ async spawn(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult> {
27
27
  const spawnResult = await this.spawnSafe(cmd, options);
28
28
 
29
29
  if (spawnResult.status !== 'success') {
30
- throw new SpawnError(cmd, spawnResult.exitCode, spawnResult.data);
30
+ throw new SpawnError(Array.isArray(cmd) ? cmd.join('\n') : cmd, spawnResult.exitCode, spawnResult.data);
31
31
  }
32
32
 
33
33
  return spawnResult;
34
34
  }
35
35
 
36
- async spawnSafe(cmd: string, options?: SpawnOptions): Promise<SpawnResult> {
36
+ async spawnSafe(cmd: string | string[], options?: SpawnOptions): Promise<SpawnResult> {
37
+ cmd = Array.isArray(cmd) ? cmd.join(' ') : cmd;
38
+
37
39
  if (cmd.includes('sudo')) {
38
40
  throw new Error('Do not directly use sudo. Use the option { requiresRoot: true } instead')
39
41
  }
@@ -43,7 +45,7 @@ export class SequentialPty implements IPty {
43
45
  return this.externalSpawn(cmd, options);
44
46
  }
45
47
 
46
- console.log(`Running command: ${cmd}` + (options?.cwd ? `(${options?.cwd})` : ''))
48
+ console.log(`Running command: ${Array.isArray(cmd) ? cmd.join('\\\n') : cmd}` + (options?.cwd ? `(${options?.cwd})` : ''))
47
49
 
48
50
  return new Promise((resolve) => {
49
51
  const output: string[] = [];
@@ -51,6 +51,21 @@ describe('SequentialPty tests', () => {
51
51
  })
52
52
  });
53
53
 
54
+
55
+ it('Can use multi-line commands', async () => {
56
+ const pty = new SequentialPty();
57
+
58
+ const resultSuccess = await pty.spawnSafe([
59
+ 'pwd',
60
+ '&& ls',
61
+ ], { cwd: '/tmp' });
62
+ expect(resultSuccess).toMatchObject({
63
+ status: 'success',
64
+ exitCode: 0,
65
+ })
66
+ });
67
+
68
+
54
69
  it('It can launch a command in interactive mode', async () => {
55
70
  const originalSend = process.send;
56
71
  process.send = (req: IpcMessageV2) => {
@@ -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, ResourceConfig, ResourceSchema } 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,13 +8,14 @@ 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';
18
+ import { JSONSchema } from '@apidevtools/json-schema-ref-parser';
17
19
 
18
20
  export interface ParsedStatefulParameterSetting extends DefaultParameterSetting {
19
21
  type: 'stateful',
@@ -29,7 +31,7 @@ export type ParsedArrayParameterSetting = {
29
31
 
30
32
  export type ParsedParameterSetting =
31
33
  {
32
- isEqual: (desired: unknown, current: unknown) => boolean;
34
+ isEqual: (desired: unknown, current: unknown) => boolean;
33
35
  } & (DefaultParameterSetting
34
36
  | ParsedArrayParameterSetting
35
37
  | ParsedStatefulParameterSetting)
@@ -37,10 +39,13 @@ export type ParsedParameterSetting =
37
39
  export class ParsedResourceSettings<T extends StringIndexedObject> implements ResourceSettings<T> {
38
40
  private cache = new Map<string, unknown>();
39
41
  id!: string;
42
+ description?: string;
43
+
40
44
  schema?: Partial<JSONSchemaType<T | any>>;
41
45
  allowMultiple?: {
46
+ identifyingParameters?: string[];
42
47
  matcher?: (desired: Partial<T>, current: Partial<T>) => boolean;
43
- requiredParameters?: string[]
48
+ findAllParameters?: () => Promise<Array<Partial<T>>>
44
49
  } | boolean;
45
50
 
46
51
  removeStatefulParametersBeforeDestroy?: boolean | undefined;
@@ -54,9 +59,18 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
54
59
 
55
60
  constructor(settings: ResourceSettings<T>) {
56
61
  this.settings = settings;
62
+ const { parameterSettings, schema, ...rest } = settings;
57
63
 
58
- const { parameterSettings, ...rest } = settings;
59
64
  Object.assign(this, rest);
65
+ this.schema = schema instanceof ZodObject
66
+ ? z.toJSONSchema(schema, {
67
+ target: 'draft-7',
68
+ override(ctx) {
69
+ ctx.jsonSchema.title = settings.id;
70
+ ctx.jsonSchema.description = settings.description ?? `${settings.id} resource. Can be used to manage ${settings.id}`;
71
+ }
72
+ }) as JSONSchemaType<T>
73
+ : schema;
60
74
 
61
75
  this.validateSettings();
62
76
  }
@@ -199,7 +213,7 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
199
213
  throw new Error(`Resource: ${this.id}. Stateful parameters are not allowed to be identifying parameters for allowMultiple.`)
200
214
  }
201
215
 
202
- const schema = this.settings.schema as JSONSchemaType<any>;
216
+ const schema = this.schema as JSONSchemaType<any>;
203
217
  if (!this.settings.importAndDestroy && (schema?.oneOf
204
218
  && Array.isArray(schema.oneOf)
205
219
  && schema.oneOf.some((s) => s.required)
@@ -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.settings.schema) {
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.settings.schema);
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> {
@@ -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 {
@@ -12,6 +13,7 @@ import {
12
13
  untildify
13
14
  } from '../utils/functions.js';
14
15
  import { RefreshContext } from './resource.js';
16
+ import { ParsedResourceSettings } from './parsed-resource-settings.js';
15
17
 
16
18
  export interface InputTransformation {
17
19
  to: (input: any) => Promise<any> | any;
@@ -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
@@ -489,7 +496,7 @@ export function resolveParameterTransformFn(
489
496
  }
490
497
 
491
498
  export function resolveMatcher<T extends StringIndexedObject>(
492
- settings: ResourceSettings<T>
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>) => {
@@ -36,8 +36,7 @@ export function tildify(pathWithTilde: string) {
36
36
  }
37
37
 
38
38
  export function resolvePathWithVariables(pathWithVariables: string) {
39
- // @ts-expect-error Ignore this for now
40
- return pathWithVariables.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b])
39
+ return pathWithVariables.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b]!)
41
40
  }
42
41
 
43
42
  export function addVariablesToPath(pathWithoutVariables: string) {
@@ -1,6 +1,7 @@
1
1
  import { OS } from 'codify-schemas';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
+
4
5
  import { getPty, SpawnStatus } from '../pty/index.js';
5
6
 
6
7
  export function isDebug(): boolean {