|
1 | 1 | import { describe, it, expect } from 'vitest'; |
| 2 | +import { createRequire } from 'node:module'; |
2 | 3 |
|
3 | 4 | /** |
4 | | - * The custom loadPluginCommands mechanism has been removed. |
5 | | - * Plugin command extension is now handled by oclif's built-in plugin system. |
| 5 | + * The published `os` binary's oclif plugin surface. |
6 | 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>` |
| 7 | + * Command extension is handled by oclif's plugin system: a plugin package |
| 8 | + * carries its own `oclif` config and exports oclif Command classes from |
| 9 | + * `src/commands/`. The host project's `objectstack.config.ts` does not decide |
| 10 | + * which CLI commands exist. |
11 | 11 | * |
12 | | - * The objectstack.config.ts no longer determines CLI command availability. |
| 12 | + * This package ships NO plugin manager and loads no plugin of its own. It used |
| 13 | + * to list `@oclif/plugin-help` and `@oclif/plugin-plugins` under |
| 14 | + * `oclif.plugins` while both sat in `devDependencies`. `@oclif/core`'s |
| 15 | + * core-plugin loader (`lib/config/plugin-loader.js`, `loadCorePlugins`) |
| 16 | + * matches `oclif.plugins` names only against `dependencies`, so neither ever |
| 17 | + * loaded: `os plugins …` and `os help` were never commands, and `os --help` |
| 18 | + * read the same with or without the array. The array was dead configuration, |
| 19 | + * and every text that read it as "`os plugins install` works" was false. |
| 20 | + * |
| 21 | + * What these pins hold is the state the published text now describes |
| 22 | + * (`README.md` → "`os plugins` and `os help` (not commands)" and "oclif Plugin |
| 23 | + * System"; `content/docs/plugins/index.mdx` → the Step 3 callout; |
| 24 | + * `bin/run.js` → the `enableAutoTranspile` note on linked plugins). Shipping a |
| 25 | + * plugin manager is a product change, not a manifest tweak: it lists the |
| 26 | + * plugin in BOTH `oclif.plugins` and `dependencies`, and corrects those texts |
| 27 | + * in the same change. |
13 | 28 | */ |
14 | 29 |
|
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'); |
| 30 | +const require = createRequire(import.meta.url); |
| 31 | +const pkg = require('../package.json'); |
| 32 | + |
| 33 | +const DEPENDENCY_FIELDS = [ |
| 34 | + 'dependencies', |
| 35 | + 'optionalDependencies', |
| 36 | + 'peerDependencies', |
| 37 | + 'devDependencies', |
| 38 | +] as const; |
20 | 39 |
|
| 40 | +describe('oclif plugin surface — the published `os` ships no plugin manager', () => { |
| 41 | + it('declares no oclif.plugins (oclif would load an entry only from `dependencies`)', () => { |
21 | 42 | expect(pkg.oclif).toBeDefined(); |
22 | | - expect(pkg.oclif.plugins).toContain('@oclif/plugin-help'); |
23 | | - expect(pkg.oclif.plugins).toContain('@oclif/plugin-plugins'); |
| 43 | + expect( |
| 44 | + pkg.oclif.plugins, |
| 45 | + 'package.json `oclif.plugins` is back. An entry here loads only when the same name is in `dependencies` ' + |
| 46 | + '(oclif loadCorePlugins); otherwise it is dead configuration. Either way README.md, ' + |
| 47 | + 'content/docs/plugins/index.mdx and bin/run.js state that this CLI ships no plugin manager — change them with it.', |
| 48 | + ).toBeUndefined(); |
24 | 49 | }); |
25 | 50 |
|
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'); |
| 51 | + it('depends on no @oclif/plugin-* package in any dependency field', () => { |
| 52 | + const found = DEPENDENCY_FIELDS.flatMap((field) => |
| 53 | + Object.keys(pkg[field] ?? {}) |
| 54 | + .filter((name) => name.startsWith('@oclif/plugin-')) |
| 55 | + .map((name) => `${field}: ${name}`), |
| 56 | + ); |
| 57 | + expect( |
| 58 | + found, |
| 59 | + 'an oclif plugin package is listed. Not named in `oclif.plugins` + `dependencies`, it never loads and is dead ' + |
| 60 | + 'weight; loaded, it makes `os plugins` / `os help` real and the published text false.', |
| 61 | + ).toEqual([]); |
| 62 | + }); |
| 63 | +}); |
30 | 64 |
|
| 65 | +describe('oclif command discovery and entry points', () => { |
| 66 | + it('discovers commands by pattern under dist/commands', () => { |
31 | 67 | expect(pkg.oclif.commands).toBeDefined(); |
32 | 68 | expect(pkg.oclif.commands.strategy).toBe('pattern'); |
33 | 69 | expect(pkg.oclif.commands.target).toBe('./dist/commands'); |
34 | 70 | }); |
35 | 71 |
|
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 | | - |
| 72 | + it('points both bin entries at the oclif runner', () => { |
41 | 73 | expect(pkg.bin.os).toBe('./bin/run.js'); |
42 | 74 | expect(pkg.bin.objectstack).toBe('./bin/run.js'); |
43 | 75 | }); |
|
0 commit comments