@objectstack/cli 3.0.6 → 3.0.8
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/.turbo/turbo-build.log +2 -26
- package/CHANGELOG.md +27 -0
- package/README.md +98 -54
- package/bin/run-dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/bin.d.ts +11 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +12 -3767
- package/dist/bin.js.map +1 -0
- package/dist/commands/codemod/v2-to-v3.d.ts +10 -0
- package/dist/commands/codemod/v2-to-v3.d.ts.map +1 -0
- package/dist/commands/codemod/v2-to-v3.js +145 -0
- package/dist/commands/codemod/v2-to-v3.js.map +1 -0
- package/dist/commands/compile.d.ts +13 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +91 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/create.d.ts +91 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +259 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +67 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/diff.d.ts +16 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +239 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +532 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explain.d.ts +12 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +368 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +833 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/info.d.ts +12 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +100 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +22 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +295 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +13 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +255 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/plugin/add.d.ts +22 -0
- package/dist/commands/plugin/add.d.ts.map +1 -0
- package/dist/commands/plugin/add.js +93 -0
- package/dist/commands/plugin/add.js.map +1 -0
- package/dist/commands/plugin/info.d.ts +10 -0
- package/dist/commands/plugin/info.d.ts.map +1 -0
- package/dist/commands/plugin/info.js +65 -0
- package/dist/commands/plugin/info.js.map +1 -0
- package/dist/commands/plugin/list.d.ts +13 -0
- package/dist/commands/plugin/list.d.ts.map +1 -0
- package/dist/commands/plugin/list.js +78 -0
- package/dist/commands/plugin/list.js.map +1 -0
- package/dist/commands/plugin/remove.d.ts +20 -0
- package/dist/commands/plugin/remove.d.ts.map +1 -0
- package/dist/commands/plugin/remove.js +79 -0
- package/dist/commands/plugin/remove.js.map +1 -0
- package/dist/commands/serve.d.ts +15 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +286 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/studio.d.ts +19 -0
- package/dist/commands/studio.d.ts.map +1 -0
- package/dist/commands/studio.js +43 -0
- package/dist/commands/studio.js.map +1 -0
- package/dist/commands/test.d.ts +13 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +120 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/validate.d.ts +13 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +115 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +15 -114
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -2805
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +21 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +66 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/format.d.ts +52 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +202 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/plugin-helpers.d.ts +14 -0
- package/dist/utils/plugin-helpers.d.ts.map +1 -0
- package/dist/utils/plugin-helpers.js +40 -0
- package/dist/utils/plugin-helpers.js.map +1 -0
- package/dist/utils/studio.d.ts +58 -0
- package/dist/utils/studio.d.ts.map +1 -0
- package/dist/utils/studio.js +288 -0
- package/dist/utils/studio.js.map +1 -0
- package/package.json +33 -15
- package/src/bin.ts +11 -104
- package/src/commands/{codemod.ts → codemod/v2-to-v3.ts} +21 -28
- package/src/commands/compile.ts +31 -22
- package/src/commands/create.ts +29 -19
- package/src/commands/dev.ts +21 -10
- package/src/commands/diff.ts +28 -19
- package/src/commands/doctor.ts +17 -10
- package/src/commands/explain.ts +20 -10
- package/src/commands/generate.ts +81 -90
- package/src/commands/info.ts +20 -11
- package/src/commands/init.ts +32 -20
- package/src/commands/lint.ts +24 -14
- package/src/commands/plugin/add.ts +112 -0
- package/src/commands/plugin/info.ts +79 -0
- package/src/commands/plugin/list.ts +93 -0
- package/src/commands/plugin/remove.ts +97 -0
- package/src/commands/serve.ts +30 -20
- package/src/commands/studio.ts +21 -11
- package/src/commands/test.ts +21 -10
- package/src/commands/validate.ts +32 -22
- package/src/index.ts +20 -12
- package/src/utils/plugin-helpers.ts +37 -0
- package/src/utils/studio.ts +0 -1
- package/test/commands.test.ts +76 -37
- package/test/plugin-commands.test.ts +42 -160
- package/test/plugin.test.ts +19 -23
- package/tsconfig.build.json +18 -0
- package/bin/objectstack.js +0 -2
- package/dist/chunk-T2YN4AB7.js +0 -249
- package/dist/chunk-XNACYTC5.js +0 -251
- package/dist/config-FOXDQ5F7.js +0 -10
- package/dist/config-GBR54FKL.js +0 -11
- package/src/commands/plugin.ts +0 -372
- package/src/utils/plugin-commands.ts +0 -163
package/src/commands/validate.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { ZodError } from 'zod';
|
|
6
6
|
import { ObjectStackDefinitionSchema, normalizeStackInput } from '@objectstack/spec';
|
|
@@ -17,53 +17,62 @@ import {
|
|
|
17
17
|
printMetadataStats,
|
|
18
18
|
} from '../utils/format.js';
|
|
19
19
|
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
export default class Validate extends Command {
|
|
21
|
+
static override description = 'Validate ObjectStack configuration against the protocol schema';
|
|
22
|
+
|
|
23
|
+
static override args = {
|
|
24
|
+
config: Args.string({ description: 'Configuration file path', required: false }),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static override flags = {
|
|
28
|
+
strict: Flags.boolean({ description: 'Treat warnings as errors' }),
|
|
29
|
+
json: Flags.boolean({ description: 'Output results as JSON' }),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
async run(): Promise<void> {
|
|
33
|
+
const { args, flags } = await this.parse(Validate);
|
|
34
|
+
|
|
26
35
|
const timer = createTimer();
|
|
27
36
|
|
|
28
|
-
if (!
|
|
37
|
+
if (!flags.json) {
|
|
29
38
|
printHeader('Validate');
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
try {
|
|
33
42
|
// 1. Load configuration
|
|
34
|
-
if (!
|
|
35
|
-
const { config, absolutePath, duration } = await loadConfig(
|
|
43
|
+
if (!flags.json) printStep('Loading configuration...');
|
|
44
|
+
const { config, absolutePath, duration } = await loadConfig(args.config);
|
|
36
45
|
|
|
37
|
-
if (!
|
|
46
|
+
if (!flags.json) {
|
|
38
47
|
printKV('Config', absolutePath);
|
|
39
48
|
printKV('Load time', `${duration}ms`);
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
// 2. Normalize map-formatted stack definition and validate against schema
|
|
43
|
-
if (!
|
|
52
|
+
if (!flags.json) printStep('Validating against ObjectStack Protocol...');
|
|
44
53
|
const normalized = normalizeStackInput(config as Record<string, unknown>);
|
|
45
54
|
const result = ObjectStackDefinitionSchema.safeParse(normalized);
|
|
46
55
|
|
|
47
56
|
if (!result.success) {
|
|
48
|
-
if (
|
|
57
|
+
if (flags.json) {
|
|
49
58
|
console.log(JSON.stringify({
|
|
50
59
|
valid: false,
|
|
51
60
|
errors: (result.error as unknown as ZodError).issues,
|
|
52
61
|
duration: timer.elapsed(),
|
|
53
62
|
}, null, 2));
|
|
54
|
-
|
|
63
|
+
this.exit(1);
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
console.log('');
|
|
58
67
|
printError('Validation failed');
|
|
59
68
|
formatZodErrors(result.error as unknown as ZodError);
|
|
60
|
-
|
|
69
|
+
this.exit(1);
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
// 3. Collect and display stats
|
|
64
73
|
const stats = collectMetadataStats(config);
|
|
65
74
|
|
|
66
|
-
if (
|
|
75
|
+
if (flags.json) {
|
|
67
76
|
console.log(JSON.stringify({
|
|
68
77
|
valid: true,
|
|
69
78
|
manifest: config.manifest,
|
|
@@ -109,25 +118,26 @@ export const validateCommand = new Command('validate')
|
|
|
109
118
|
for (const w of warnings) {
|
|
110
119
|
console.log(chalk.yellow(` ⚠ ${w}`));
|
|
111
120
|
}
|
|
112
|
-
if (
|
|
121
|
+
if (flags.strict) {
|
|
113
122
|
console.log('');
|
|
114
123
|
printError('Strict mode: warnings treated as errors');
|
|
115
|
-
|
|
124
|
+
this.exit(1);
|
|
116
125
|
}
|
|
117
126
|
}
|
|
118
127
|
|
|
119
128
|
console.log('');
|
|
120
129
|
} catch (error: any) {
|
|
121
|
-
if (
|
|
130
|
+
if (flags.json) {
|
|
122
131
|
console.log(JSON.stringify({
|
|
123
132
|
valid: false,
|
|
124
133
|
error: error.message,
|
|
125
134
|
duration: timer.elapsed(),
|
|
126
135
|
}, null, 2));
|
|
127
|
-
|
|
136
|
+
this.exit(1);
|
|
128
137
|
}
|
|
129
138
|
console.log('');
|
|
130
139
|
printError(error.message || String(error));
|
|
131
|
-
|
|
140
|
+
this.exit(1);
|
|
132
141
|
}
|
|
133
|
-
}
|
|
142
|
+
}
|
|
143
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
3
|
+
// ─── oclif Command Classes ──────────────────────────────────────────
|
|
4
|
+
// Each command is auto-discovered by oclif from `src/commands/`.
|
|
5
|
+
// These re-exports provide programmatic access for testing and integration.
|
|
6
|
+
|
|
7
|
+
export { default as CompileCommand } from './commands/compile.js';
|
|
8
|
+
export { default as ValidateCommand } from './commands/validate.js';
|
|
9
|
+
export { default as InfoCommand } from './commands/info.js';
|
|
10
|
+
export { default as InitCommand } from './commands/init.js';
|
|
11
|
+
export { default as GenerateCommand } from './commands/generate.js';
|
|
12
|
+
export { default as CreateCommand } from './commands/create.js';
|
|
13
|
+
export { default as DevCommand } from './commands/dev.js';
|
|
14
|
+
export { default as ServeCommand } from './commands/serve.js';
|
|
15
|
+
export { default as TestCommand } from './commands/test.js';
|
|
16
|
+
export { default as DoctorCommand } from './commands/doctor.js';
|
|
17
|
+
|
|
18
|
+
// ─── Plugin topic subcommands ───────────────────────────────────────
|
|
19
|
+
export { default as PluginListCommand } from './commands/plugin/list.js';
|
|
20
|
+
export { default as PluginInfoCommand } from './commands/plugin/info.js';
|
|
21
|
+
export { default as PluginAddCommand } from './commands/plugin/add.js';
|
|
22
|
+
export { default as PluginRemoveCommand } from './commands/plugin/remove.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve plugin display name from a plugin entry.
|
|
5
|
+
* Plugins can be string package names, objects with `.name`, or class instances.
|
|
6
|
+
*/
|
|
7
|
+
export function resolvePluginName(plugin: unknown): string {
|
|
8
|
+
if (typeof plugin === 'string') return plugin;
|
|
9
|
+
if (plugin && typeof plugin === 'object') {
|
|
10
|
+
const p = plugin as Record<string, unknown>;
|
|
11
|
+
if (typeof p.name === 'string') return p.name;
|
|
12
|
+
if (p.constructor && p.constructor.name !== 'Object') return p.constructor.name;
|
|
13
|
+
}
|
|
14
|
+
return 'unknown';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolve plugin version from a plugin entry.
|
|
19
|
+
*/
|
|
20
|
+
export function resolvePluginVersion(plugin: unknown): string {
|
|
21
|
+
if (plugin && typeof plugin === 'object') {
|
|
22
|
+
const p = plugin as Record<string, unknown>;
|
|
23
|
+
if (typeof p.version === 'string') return p.version;
|
|
24
|
+
}
|
|
25
|
+
return '-';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve plugin type from a plugin entry.
|
|
30
|
+
*/
|
|
31
|
+
export function resolvePluginType(plugin: unknown): string {
|
|
32
|
+
if (plugin && typeof plugin === 'object') {
|
|
33
|
+
const p = plugin as Record<string, unknown>;
|
|
34
|
+
if (typeof p.type === 'string') return p.type;
|
|
35
|
+
}
|
|
36
|
+
return 'standard';
|
|
37
|
+
}
|
package/src/utils/studio.ts
CHANGED
|
@@ -236,7 +236,6 @@ export function createStudioProxyPlugin(vitePort: number) {
|
|
|
236
236
|
method: c.req.method,
|
|
237
237
|
headers,
|
|
238
238
|
body: isBodyAllowed ? c.req.raw.body : undefined,
|
|
239
|
-
// @ts-expect-error — duplex required for streaming request body
|
|
240
239
|
duplex: isBodyAllowed ? 'half' : undefined,
|
|
241
240
|
});
|
|
242
241
|
|
package/test/commands.test.ts
CHANGED
|
@@ -1,70 +1,109 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
import Compile from '../src/commands/compile';
|
|
3
|
+
import Serve from '../src/commands/serve';
|
|
4
|
+
import Dev from '../src/commands/dev';
|
|
5
|
+
import Doctor from '../src/commands/doctor';
|
|
6
|
+
import Create from '../src/commands/create';
|
|
7
|
+
import Test from '../src/commands/test';
|
|
8
|
+
import Validate from '../src/commands/validate';
|
|
9
|
+
import Init from '../src/commands/init';
|
|
10
|
+
import Info from '../src/commands/info';
|
|
11
|
+
import Generate from '../src/commands/generate';
|
|
12
|
+
import Lint from '../src/commands/lint';
|
|
13
|
+
import Diff from '../src/commands/diff';
|
|
14
|
+
import Explain from '../src/commands/explain';
|
|
15
|
+
import Studio from '../src/commands/studio';
|
|
16
|
+
import PluginList from '../src/commands/plugin/list';
|
|
17
|
+
import PluginInfo from '../src/commands/plugin/info';
|
|
18
|
+
import PluginAdd from '../src/commands/plugin/add';
|
|
19
|
+
import PluginRemove from '../src/commands/plugin/remove';
|
|
20
|
+
import V2ToV3 from '../src/commands/codemod/v2-to-v3';
|
|
21
|
+
|
|
22
|
+
describe('CLI Commands (oclif)', () => {
|
|
15
23
|
it('should have compile command', () => {
|
|
16
|
-
expect(
|
|
17
|
-
expect(compileCommand.description()).toContain('Compile');
|
|
24
|
+
expect(Compile.description).toContain('Compile');
|
|
18
25
|
});
|
|
19
26
|
|
|
20
27
|
it('should have serve command', () => {
|
|
21
|
-
expect(
|
|
22
|
-
expect(serveCommand.description()).toContain('server');
|
|
28
|
+
expect(Serve.description).toContain('server');
|
|
23
29
|
});
|
|
24
30
|
|
|
25
31
|
it('should have dev command', () => {
|
|
26
|
-
expect(
|
|
27
|
-
expect(devCommand.description()).toContain('development mode');
|
|
32
|
+
expect(Dev.description).toContain('development mode');
|
|
28
33
|
});
|
|
29
34
|
|
|
30
35
|
it('should have doctor command', () => {
|
|
31
|
-
expect(
|
|
32
|
-
expect(doctorCommand.description()).toContain('health');
|
|
36
|
+
expect(Doctor.description).toContain('health');
|
|
33
37
|
});
|
|
34
38
|
|
|
35
39
|
it('should have create command', () => {
|
|
36
|
-
expect(
|
|
37
|
-
expect(createCommand.description()).toContain('Create');
|
|
40
|
+
expect(Create.description).toContain('Create');
|
|
38
41
|
});
|
|
39
42
|
|
|
40
43
|
it('should have test command', () => {
|
|
41
|
-
expect(
|
|
42
|
-
expect(testCommand.description()).toContain('Quality Protocol');
|
|
44
|
+
expect(Test.description).toContain('Quality Protocol');
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
it('should have validate command', () => {
|
|
46
|
-
expect(
|
|
47
|
-
expect(validateCommand.description()).toContain('Validate');
|
|
48
|
+
expect(Validate.description).toContain('Validate');
|
|
48
49
|
});
|
|
49
50
|
|
|
50
51
|
it('should have init command', () => {
|
|
51
|
-
expect(
|
|
52
|
-
expect(initCommand.description()).toContain('Initialize');
|
|
52
|
+
expect(Init.description).toContain('Initialize');
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
it('should have info command', () => {
|
|
56
|
-
expect(
|
|
57
|
-
expect(infoCommand.description()).toContain('summary');
|
|
56
|
+
expect(Info.description).toContain('summary');
|
|
58
57
|
});
|
|
59
58
|
|
|
60
59
|
it('should have generate command with alias', () => {
|
|
61
|
-
expect(
|
|
62
|
-
expect(
|
|
63
|
-
|
|
60
|
+
expect(Generate.aliases).toContain('g');
|
|
61
|
+
expect(Generate.description).toContain('Generate');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should have lint command', () => {
|
|
65
|
+
expect(Lint.description).toContain('style');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should have diff command', () => {
|
|
69
|
+
expect(Diff.description).toContain('Compare');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should have explain command', () => {
|
|
73
|
+
expect(Explain.description).toContain('explanation');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should have studio command', () => {
|
|
77
|
+
expect(Studio.description).toContain('Studio');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should have codemod v2-to-v3 command', () => {
|
|
81
|
+
expect(V2ToV3.description).toContain('v2');
|
|
64
82
|
});
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
describe('Plugin subcommands', () => {
|
|
85
|
+
it('should have plugin list command', () => {
|
|
86
|
+
expect(PluginList.description).toContain('List');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should have plugin info command', () => {
|
|
90
|
+
expect(PluginInfo.description).toContain('information');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should have plugin add command', () => {
|
|
94
|
+
expect(PluginAdd.description).toContain('Add');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should have plugin remove command', () => {
|
|
98
|
+
expect(PluginRemove.description).toContain('Remove');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should have plugin remove alias', () => {
|
|
102
|
+
expect(PluginRemove.aliases).toContain('plugin rm');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should have plugin list alias', () => {
|
|
106
|
+
expect(PluginList.aliases).toContain('plugin ls');
|
|
107
|
+
});
|
|
69
108
|
});
|
|
70
109
|
});
|
|
@@ -1,162 +1,44 @@
|
|
|
1
|
-
import { describe, it, expect
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
expect(
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should do nothing when plugins array is empty', async () => {
|
|
46
|
-
mockedLoadConfig.mockResolvedValue({
|
|
47
|
-
config: {
|
|
48
|
-
plugins: [],
|
|
49
|
-
},
|
|
50
|
-
absolutePath: '/test/objectstack.config.ts',
|
|
51
|
-
duration: 10,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
await loadPluginCommands(program);
|
|
55
|
-
expect(program.commands).toHaveLength(0);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should do nothing when config has no plugins key', async () => {
|
|
59
|
-
mockedLoadConfig.mockResolvedValue({
|
|
60
|
-
config: {},
|
|
61
|
-
absolutePath: '/test/objectstack.config.ts',
|
|
62
|
-
duration: 10,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
await loadPluginCommands(program);
|
|
66
|
-
expect(program.commands).toHaveLength(0);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should detect command contributions from plugin manifest', async () => {
|
|
70
|
-
// This test verifies that the contribution detection logic works,
|
|
71
|
-
// even though the dynamic import will fail (no real module to load)
|
|
72
|
-
mockedLoadConfig.mockResolvedValue({
|
|
73
|
-
config: {
|
|
74
|
-
plugins: [
|
|
75
|
-
{
|
|
76
|
-
name: '@acme/plugin-marketplace',
|
|
77
|
-
manifest: {
|
|
78
|
-
contributes: {
|
|
79
|
-
commands: [
|
|
80
|
-
{
|
|
81
|
-
name: 'marketplace',
|
|
82
|
-
description: 'Manage marketplace apps',
|
|
83
|
-
module: './cli',
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
},
|
|
91
|
-
absolutePath: '/test/objectstack.config.ts',
|
|
92
|
-
duration: 10,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// loadPluginCommands will try to import the module and fail silently
|
|
96
|
-
// (since no real module exists), but it should not throw
|
|
97
|
-
await loadPluginCommands(program);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should detect contributions from top-level contributes field', async () => {
|
|
101
|
-
mockedLoadConfig.mockResolvedValue({
|
|
102
|
-
config: {
|
|
103
|
-
plugins: [
|
|
104
|
-
{
|
|
105
|
-
name: '@acme/plugin-deploy',
|
|
106
|
-
contributes: {
|
|
107
|
-
commands: [
|
|
108
|
-
{
|
|
109
|
-
name: 'deploy',
|
|
110
|
-
description: 'Deploy to cloud',
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
},
|
|
117
|
-
absolutePath: '/test/objectstack.config.ts',
|
|
118
|
-
duration: 10,
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// Should not throw even if import fails
|
|
122
|
-
await loadPluginCommands(program);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should skip non-object plugins', async () => {
|
|
126
|
-
mockedLoadConfig.mockResolvedValue({
|
|
127
|
-
config: {
|
|
128
|
-
plugins: [
|
|
129
|
-
'some-string-plugin',
|
|
130
|
-
null,
|
|
131
|
-
undefined,
|
|
132
|
-
42,
|
|
133
|
-
],
|
|
134
|
-
},
|
|
135
|
-
absolutePath: '/test/objectstack.config.ts',
|
|
136
|
-
duration: 10,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
await loadPluginCommands(program);
|
|
140
|
-
expect(program.commands).toHaveLength(0);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should handle plugins with non-array commands gracefully', async () => {
|
|
144
|
-
mockedLoadConfig.mockResolvedValue({
|
|
145
|
-
config: {
|
|
146
|
-
plugins: [
|
|
147
|
-
{
|
|
148
|
-
name: '@acme/bad-plugin',
|
|
149
|
-
contributes: {
|
|
150
|
-
commands: 'not-an-array',
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
],
|
|
154
|
-
},
|
|
155
|
-
absolutePath: '/test/objectstack.config.ts',
|
|
156
|
-
duration: 10,
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
await loadPluginCommands(program);
|
|
160
|
-
expect(program.commands).toHaveLength(0);
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The custom loadPluginCommands mechanism has been removed.
|
|
5
|
+
* Plugin command extension is now handled by oclif's built-in plugin system.
|
|
6
|
+
*
|
|
7
|
+
* Plugins extend the CLI by:
|
|
8
|
+
* 1. Including `oclif` config in their package.json
|
|
9
|
+
* 2. Exporting oclif Command classes from `src/commands/`
|
|
10
|
+
* 3. Being installed via `os plugins install <package>`
|
|
11
|
+
*
|
|
12
|
+
* The objectstack.config.ts no longer determines CLI command availability.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
describe('oclif Plugin System', () => {
|
|
16
|
+
it('should have oclif plugins configured in package.json', async () => {
|
|
17
|
+
const { createRequire } = await import('module');
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const pkg = require('../package.json');
|
|
20
|
+
|
|
21
|
+
expect(pkg.oclif).toBeDefined();
|
|
22
|
+
expect(pkg.oclif.plugins).toContain('@oclif/plugin-help');
|
|
23
|
+
expect(pkg.oclif.plugins).toContain('@oclif/plugin-plugins');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should have oclif command discovery configured', async () => {
|
|
27
|
+
const { createRequire } = await import('module');
|
|
28
|
+
const require = createRequire(import.meta.url);
|
|
29
|
+
const pkg = require('../package.json');
|
|
30
|
+
|
|
31
|
+
expect(pkg.oclif.commands).toBeDefined();
|
|
32
|
+
expect(pkg.oclif.commands.strategy).toBe('pattern');
|
|
33
|
+
expect(pkg.oclif.commands.target).toBe('./dist/commands');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should have bin entries pointing to oclif runner', async () => {
|
|
37
|
+
const { createRequire } = await import('module');
|
|
38
|
+
const require = createRequire(import.meta.url);
|
|
39
|
+
const pkg = require('../package.json');
|
|
40
|
+
|
|
41
|
+
expect(pkg.bin.os).toBe('./bin/run.js');
|
|
42
|
+
expect(pkg.bin.objectstack).toBe('./bin/run.js');
|
|
161
43
|
});
|
|
162
44
|
});
|
package/test/plugin.test.ts
CHANGED
|
@@ -1,39 +1,35 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import
|
|
2
|
+
import PluginList from '../src/commands/plugin/list';
|
|
3
|
+
import PluginInfo from '../src/commands/plugin/info';
|
|
4
|
+
import PluginAdd from '../src/commands/plugin/add';
|
|
5
|
+
import PluginRemove from '../src/commands/plugin/remove';
|
|
3
6
|
import fs from 'fs';
|
|
4
7
|
import path from 'path';
|
|
5
8
|
import os from 'os';
|
|
6
9
|
|
|
7
|
-
describe('Plugin
|
|
8
|
-
it('should have plugin command
|
|
9
|
-
expect(
|
|
10
|
-
expect(pluginCommand.description()).toContain('plugin');
|
|
10
|
+
describe('Plugin Commands (oclif)', () => {
|
|
11
|
+
it('should have plugin list command', () => {
|
|
12
|
+
expect(PluginList.description).toContain('List');
|
|
11
13
|
});
|
|
12
14
|
|
|
13
|
-
it('should have list
|
|
14
|
-
|
|
15
|
-
expect(list).toBeDefined();
|
|
16
|
-
expect(list!.alias()).toBe('ls');
|
|
17
|
-
expect(list!.description()).toContain('List');
|
|
15
|
+
it('should have plugin list alias', () => {
|
|
16
|
+
expect(PluginList.aliases).toContain('plugin ls');
|
|
18
17
|
});
|
|
19
18
|
|
|
20
|
-
it('should have info
|
|
21
|
-
|
|
22
|
-
expect(info).toBeDefined();
|
|
23
|
-
expect(info!.description()).toContain('information');
|
|
19
|
+
it('should have plugin info command', () => {
|
|
20
|
+
expect(PluginInfo.description).toContain('information');
|
|
24
21
|
});
|
|
25
22
|
|
|
26
|
-
it('should have add
|
|
27
|
-
|
|
28
|
-
expect(add).toBeDefined();
|
|
29
|
-
expect(add!.description()).toContain('Add');
|
|
23
|
+
it('should have plugin add command', () => {
|
|
24
|
+
expect(PluginAdd.description).toContain('Add');
|
|
30
25
|
});
|
|
31
26
|
|
|
32
|
-
it('should have remove
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
it('should have plugin remove command', () => {
|
|
28
|
+
expect(PluginRemove.description).toContain('Remove');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should have plugin remove alias', () => {
|
|
32
|
+
expect(PluginRemove.aliases).toContain('plugin rm');
|
|
37
33
|
});
|
|
38
34
|
});
|
|
39
35
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "dist",
|
|
12
|
+
"rootDir": "src",
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"]
|
|
18
|
+
}
|
package/bin/objectstack.js
DELETED