@reformer/builder-plugin-cli 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/cli.d.ts +26 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +207 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/build.d.ts +57 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +261 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create.d.ts +31 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +43 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +35 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +79 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/dry-run.d.ts +38 -0
- package/dist/commands/dry-run.d.ts.map +1 -0
- package/dist/commands/dry-run.js +148 -0
- package/dist/commands/dry-run.js.map +1 -0
- package/dist/commands/findings.d.ts +31 -0
- package/dist/commands/findings.d.ts.map +1 -0
- package/dist/commands/findings.js +14 -0
- package/dist/commands/findings.js.map +1 -0
- package/dist/commands/pack.d.ts +33 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +78 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/template.d.ts +34 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +109 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/validate.d.ts +43 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +128 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* «Сухая» активация собранного плагина: исполнить `main.js` под Node и посмотреть, что он
|
|
3
|
+
* зарегистрирует, — ради двух отказов, которые оболочка иначе покажет только при включении.
|
|
4
|
+
*
|
|
5
|
+
* - **`not-a-plugin` и `id-mismatch`** — экспорты точки входа узнаются правилом загрузчика
|
|
6
|
+
* (`pluginFromExports` из контракта), `id` сверяется с манифестом.
|
|
7
|
+
* - **`provides-unregistered`** — оболочка после `activate` смотрит, занят ли в реестре служб
|
|
8
|
+
* слот каждой объявленной возможности. Здесь то же: реестр служб контекста записывает,
|
|
9
|
+
* под какими идентификаторами плагин что-то зарегистрировал.
|
|
10
|
+
*
|
|
11
|
+
* ## Что настоящее, а что нет
|
|
12
|
+
*
|
|
13
|
+
* Настоящий — пакет контракта (`@reformer/builder-plugin-api`, он же `@builder/sdk`): токены
|
|
14
|
+
* служб в нём — объекты с `id`, и регистрация под подменным токеном дала бы ложный отказ.
|
|
15
|
+
* Остальные модули рантайма (React, ядро форм, кит) и всё в контексте, кроме реестра служб, —
|
|
16
|
+
* заглушки, принимающие любое обращение. Подними мы их по-настоящему, проверка требовала бы DOM
|
|
17
|
+
* и всего билдера.
|
|
18
|
+
*
|
|
19
|
+
* Отсюда граница честности. Если код падает НА ЗАГЛУШКЕ — при исполнении модуля или в `activate`,
|
|
20
|
+
* — это не отказ: вне оболочки такое бывает у рабочих плагинов (например, `activate` читает
|
|
21
|
+
* значение службы, которой здесь нет). Такой исход возвращается ЗАМЕТКОЙ «не проверено»,
|
|
22
|
+
* а не отказом, и сборка проходит. Отказом становится только то, что видно наверняка.
|
|
23
|
+
*
|
|
24
|
+
* @module @reformer/builder-plugin-cli/commands/dry-run
|
|
25
|
+
*/
|
|
26
|
+
import { pluginFromExports, PLUGIN_RUNTIME_MODULES, } from '@reformer/builder-plugin-api/tooling';
|
|
27
|
+
const PLUGIN_API_SPECIFIERS = new Set(['@builder/sdk', '@reformer/builder-plugin-api']);
|
|
28
|
+
/**
|
|
29
|
+
* Заглушка, принимающая любое обращение: свойство, вызов, `new`.
|
|
30
|
+
*
|
|
31
|
+
* `then` отсутствует намеренно — иначе `await stub` никогда бы не завершился. Приведение
|
|
32
|
+
* к строке и числу даёт пустое значение, чтобы шаблонные строки в коде плагина не падали.
|
|
33
|
+
*/
|
|
34
|
+
function createStub() {
|
|
35
|
+
const target = function stub() { };
|
|
36
|
+
const proxy = new Proxy(target, {
|
|
37
|
+
get(_, key) {
|
|
38
|
+
if (key === 'then')
|
|
39
|
+
return undefined;
|
|
40
|
+
if (key === Symbol.toPrimitive)
|
|
41
|
+
return () => '';
|
|
42
|
+
if (key === Symbol.iterator)
|
|
43
|
+
return function* () { };
|
|
44
|
+
return proxy;
|
|
45
|
+
},
|
|
46
|
+
apply: () => proxy,
|
|
47
|
+
construct: () => proxy,
|
|
48
|
+
});
|
|
49
|
+
return proxy;
|
|
50
|
+
}
|
|
51
|
+
function describe(error) {
|
|
52
|
+
return error instanceof Error ? error.message : String(error);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @param code собранный `main.js` (CommonJS)
|
|
56
|
+
* @param manifest манифест, против которого сверяются `id` и `provides`
|
|
57
|
+
*/
|
|
58
|
+
export async function dryActivate(code, manifest) {
|
|
59
|
+
const pluginApi = (await import('@reformer/builder-plugin-api'));
|
|
60
|
+
const requireShim = (specifier) => {
|
|
61
|
+
if (PLUGIN_API_SPECIFIERS.has(specifier))
|
|
62
|
+
return pluginApi;
|
|
63
|
+
if (PLUGIN_RUNTIME_MODULES.includes(specifier))
|
|
64
|
+
return createStub();
|
|
65
|
+
// Сюда сборка не пропускает: всё, что не модуль рантайма, вложено в `main.js`.
|
|
66
|
+
throw new Error(`модуль «${specifier}» оболочка не подставляет`);
|
|
67
|
+
};
|
|
68
|
+
const module = { exports: {} };
|
|
69
|
+
try {
|
|
70
|
+
const evaluate = new Function('module', 'exports', 'require', code);
|
|
71
|
+
evaluate(module, module.exports, requireShim);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
findings: [],
|
|
76
|
+
notices: [`модуль не исполнился вне оболочки (${describe(error)}) — экспорты не проверены`],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const plugin = pluginFromExports(module.exports);
|
|
80
|
+
if (plugin === undefined) {
|
|
81
|
+
return {
|
|
82
|
+
findings: [
|
|
83
|
+
{
|
|
84
|
+
code: 'not-a-plugin',
|
|
85
|
+
message: 'main.js не экспортировал плагин: ожидается объект с «id» и «activate» ' +
|
|
86
|
+
'в module.exports или в экспорте по умолчанию',
|
|
87
|
+
file: 'main.js',
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
notices: [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (plugin.id !== manifest.id) {
|
|
94
|
+
return {
|
|
95
|
+
findings: [
|
|
96
|
+
{
|
|
97
|
+
code: 'id-mismatch',
|
|
98
|
+
message: `код объявляет плагин «${plugin.id}», а манифест — «${manifest.id}»`,
|
|
99
|
+
file: 'main.js',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
notices: [],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const provides = manifest.provides ?? [];
|
|
106
|
+
if (provides.length === 0)
|
|
107
|
+
return { findings: [], notices: [] };
|
|
108
|
+
const registered = new Set();
|
|
109
|
+
const disposable = { dispose: () => undefined };
|
|
110
|
+
const services = {
|
|
111
|
+
register: (token) => {
|
|
112
|
+
registered.add(token.id);
|
|
113
|
+
return disposable;
|
|
114
|
+
},
|
|
115
|
+
get: () => undefined,
|
|
116
|
+
require: () => createStub(),
|
|
117
|
+
onDidChange: () => disposable,
|
|
118
|
+
};
|
|
119
|
+
const stub = createStub();
|
|
120
|
+
const ctx = new Proxy({ id: manifest.id, services, subscriptions: [] }, {
|
|
121
|
+
get: (target, key) => key in target ? target[key] : stub[key],
|
|
122
|
+
});
|
|
123
|
+
try {
|
|
124
|
+
await Promise.resolve(plugin.activate(ctx));
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
return {
|
|
128
|
+
findings: [],
|
|
129
|
+
notices: [`activate упал вне оболочки (${describe(error)}) — «provides» не проверен`],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const missing = provides.filter((item) => !registered.has(item.id));
|
|
133
|
+
if (missing.length === 0)
|
|
134
|
+
return { findings: [], notices: [] };
|
|
135
|
+
const names = missing.map((item) => `«${item.id}» версии ${item.version}`).join(', ');
|
|
136
|
+
return {
|
|
137
|
+
findings: [
|
|
138
|
+
{
|
|
139
|
+
code: 'provides-unregistered',
|
|
140
|
+
message: `манифест обещает ${names}, но activate это не зарегистрировал. ` +
|
|
141
|
+
'Оболочка выключит такой плагин при включении',
|
|
142
|
+
file: 'manifest.json',
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
notices: [],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=dry-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dry-run.js","sourceRoot":"","sources":["../../src/commands/dry-run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Замечания команд CLI — одним типом на `validate`, `build`, `dev` и `pack`.
|
|
3
|
+
*
|
|
4
|
+
* Отказы, которые знает оболочка, идут её кодами ({@link PluginProblem}): автор ищет их
|
|
5
|
+
* в документации оболочки, и второй словарь для тех же бед только мешал бы. Свои коды у CLI —
|
|
6
|
+
* только для того, чего оболочка не видит: `package.json`, сборки и каталога вывода.
|
|
7
|
+
*
|
|
8
|
+
* @module @reformer/builder-plugin-cli/commands/findings
|
|
9
|
+
*/
|
|
10
|
+
import type { PluginProblem } from '@reformer/builder-plugin-api/tooling';
|
|
11
|
+
export type CliFindingCode =
|
|
12
|
+
/** Версия `package.json` не совпадает с версией манифеста. */
|
|
13
|
+
'package-version'
|
|
14
|
+
/** Сборщик отказал: синтаксис, неразрешённый импорт. */
|
|
15
|
+
| 'build-failed'
|
|
16
|
+
/** Импорт `@reformer/*`, которого оболочка не подставляет. */
|
|
17
|
+
| 'module-unavailable'
|
|
18
|
+
/** Код импортирует CSS: стили плагина объявляются в манифесте. */
|
|
19
|
+
| 'css-from-code'
|
|
20
|
+
/** Каталог вывода не пуст и не содержит сборку этого же плагина. */
|
|
21
|
+
| 'output-not-ours'
|
|
22
|
+
/** `npm pack` отказал. */
|
|
23
|
+
| 'pack-failed';
|
|
24
|
+
export type Finding = PluginProblem | {
|
|
25
|
+
readonly code: CliFindingCode;
|
|
26
|
+
readonly message: string;
|
|
27
|
+
readonly file?: string;
|
|
28
|
+
};
|
|
29
|
+
/** Одна строка для терминала: `✗ файл: сообщение`. */
|
|
30
|
+
export declare function formatFinding(finding: Finding): string;
|
|
31
|
+
//# sourceMappingURL=findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../src/commands/findings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAE1E,MAAM,MAAM,cAAc;AACxB,8DAA8D;AAC5D,iBAAiB;AACnB,wDAAwD;GACtD,cAAc;AAChB,8DAA8D;GAC5D,oBAAoB;AACtB,kEAAkE;GAChE,eAAe;AACjB,oEAAoE;GAClE,iBAAiB;AACnB,0BAA0B;GACxB,aAAa,CAAC;AAElB,MAAM,MAAM,OAAO,GACf,aAAa,GACb;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Замечания команд CLI — одним типом на `validate`, `build`, `dev` и `pack`.
|
|
3
|
+
*
|
|
4
|
+
* Отказы, которые знает оболочка, идут её кодами ({@link PluginProblem}): автор ищет их
|
|
5
|
+
* в документации оболочки, и второй словарь для тех же бед только мешал бы. Свои коды у CLI —
|
|
6
|
+
* только для того, чего оболочка не видит: `package.json`, сборки и каталога вывода.
|
|
7
|
+
*
|
|
8
|
+
* @module @reformer/builder-plugin-cli/commands/findings
|
|
9
|
+
*/
|
|
10
|
+
/** Одна строка для терминала: `✗ файл: сообщение`. */
|
|
11
|
+
export function formatFinding(finding) {
|
|
12
|
+
return `✗ ${finding.file === undefined ? '' : `${finding.file}: `}${finding.message}`;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/commands/findings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,sDAAsD;AACtD,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,KAAK,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;AACxF,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reformer-plugin pack`: собранный плагин → npm-архив `<имя>-<версия>.tgz`.
|
|
3
|
+
*
|
|
4
|
+
* В архиве ровно каталог сборки плюс `package.json`: установка из npm (фаза 9 плана) распакует
|
|
5
|
+
* его в каталог плагина, и загрузчик найдёт там то же, что после `build`. Исходники, тесты
|
|
6
|
+
* и `node_modules` в архив не попадают — упаковывается временный каталог, а не каталог автора.
|
|
7
|
+
*
|
|
8
|
+
* `package.json` архива собирается из исходного: имя, версия, описание, лицензия и ключевые
|
|
9
|
+
* слова, к которым добавляется `reformer-builder-plugin` — по нему плагин ищется в реестре.
|
|
10
|
+
* `private` снимается, зависимостей нет: всё, что плагину нужно, вложено в `main.js`
|
|
11
|
+
* или подставляется оболочкой. Версия берётся из манифеста — `validate` уже проверил, что
|
|
12
|
+
* с `package.json` она совпадает.
|
|
13
|
+
*
|
|
14
|
+
* Сам архив делает `npm pack`: формат tarball'а npm — не то, что стоит повторять руками.
|
|
15
|
+
*
|
|
16
|
+
* @module @reformer/builder-plugin-cli/commands/pack
|
|
17
|
+
*/
|
|
18
|
+
import type { Finding } from './findings.js';
|
|
19
|
+
export interface PackOptions {
|
|
20
|
+
readonly dir: string;
|
|
21
|
+
/** Куда положить архив; умолчание — каталог исходников. */
|
|
22
|
+
readonly destination?: string;
|
|
23
|
+
}
|
|
24
|
+
export type PackResult = {
|
|
25
|
+
readonly ok: true;
|
|
26
|
+
readonly file: string;
|
|
27
|
+
readonly notices: readonly string[];
|
|
28
|
+
} | {
|
|
29
|
+
readonly ok: false;
|
|
30
|
+
readonly findings: readonly Finding[];
|
|
31
|
+
};
|
|
32
|
+
export declare function packPlugin(options: PackOptions): Promise<PackResult>;
|
|
33
|
+
//# sourceMappingURL=pack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/commands/pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAO7C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACjF;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,CAAC;AAElE,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAsD1E"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reformer-plugin pack`: собранный плагин → npm-архив `<имя>-<версия>.tgz`.
|
|
3
|
+
*
|
|
4
|
+
* В архиве ровно каталог сборки плюс `package.json`: установка из npm (фаза 9 плана) распакует
|
|
5
|
+
* его в каталог плагина, и загрузчик найдёт там то же, что после `build`. Исходники, тесты
|
|
6
|
+
* и `node_modules` в архив не попадают — упаковывается временный каталог, а не каталог автора.
|
|
7
|
+
*
|
|
8
|
+
* `package.json` архива собирается из исходного: имя, версия, описание, лицензия и ключевые
|
|
9
|
+
* слова, к которым добавляется `reformer-builder-plugin` — по нему плагин ищется в реестре.
|
|
10
|
+
* `private` снимается, зависимостей нет: всё, что плагину нужно, вложено в `main.js`
|
|
11
|
+
* или подставляется оболочкой. Версия берётся из манифеста — `validate` уже проверил, что
|
|
12
|
+
* с `package.json` она совпадает.
|
|
13
|
+
*
|
|
14
|
+
* Сам архив делает `npm pack`: формат tarball'а npm — не то, что стоит повторять руками.
|
|
15
|
+
*
|
|
16
|
+
* @module @reformer/builder-plugin-cli/commands/pack
|
|
17
|
+
*/
|
|
18
|
+
import { exec } from 'node:child_process';
|
|
19
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
20
|
+
import { tmpdir } from 'node:os';
|
|
21
|
+
import { join, resolve } from 'node:path';
|
|
22
|
+
import { promisify } from 'node:util';
|
|
23
|
+
import { buildPlugin } from './build.js';
|
|
24
|
+
const run = promisify(exec);
|
|
25
|
+
/** Ключевое слово, по которому плагины билдера ищутся в реестре npm. */
|
|
26
|
+
const PLUGIN_KEYWORD = 'reformer-builder-plugin';
|
|
27
|
+
export async function packPlugin(options) {
|
|
28
|
+
const dir = resolve(options.dir);
|
|
29
|
+
const destination = resolve(dir, options.destination ?? '.');
|
|
30
|
+
const staging = await mkdtemp(join(tmpdir(), 'reformer-plugin-pack-'));
|
|
31
|
+
try {
|
|
32
|
+
const built = await buildPlugin({ dir, outDir: staging });
|
|
33
|
+
if (!built.ok)
|
|
34
|
+
return built;
|
|
35
|
+
const { manifest } = built;
|
|
36
|
+
let source = {};
|
|
37
|
+
try {
|
|
38
|
+
source = JSON.parse(await readFile(join(dir, 'package.json'), 'utf8'));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Без package.json имя пакета — идентификатор плагина.
|
|
42
|
+
}
|
|
43
|
+
const keywords = Array.isArray(source.keywords) ? source.keywords : [];
|
|
44
|
+
const pkg = {
|
|
45
|
+
name: typeof source.name === 'string' ? source.name : manifest.id.toLowerCase(),
|
|
46
|
+
version: manifest.version,
|
|
47
|
+
...(typeof source.description === 'string' ? { description: source.description } : {}),
|
|
48
|
+
...(typeof source.license === 'string' ? { license: source.license } : {}),
|
|
49
|
+
keywords: [...new Set([...keywords, PLUGIN_KEYWORD])],
|
|
50
|
+
};
|
|
51
|
+
await writeFile(join(staging, 'package.json'), `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
|
|
52
|
+
try {
|
|
53
|
+
// Одной строкой через оболочку — ради Windows: `npm` там командный файл и без оболочки
|
|
54
|
+
// не запускается, а массив аргументов вместе с `shell` Node объявил устаревшим (DEP0190).
|
|
55
|
+
// Единственный подставляемый аргумент — путь, и он в кавычках JSON.
|
|
56
|
+
const { stdout } = await run(`npm pack --json --pack-destination ${JSON.stringify(destination)}`, { cwd: staging });
|
|
57
|
+
const [info] = JSON.parse(stdout);
|
|
58
|
+
if (info === undefined)
|
|
59
|
+
throw new Error('npm pack не назвал архив');
|
|
60
|
+
return { ok: true, file: join(destination, info.filename), notices: built.notices };
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
findings: [
|
|
66
|
+
{
|
|
67
|
+
code: 'pack-failed',
|
|
68
|
+
message: `npm pack отказал: ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await rm(staging, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=pack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../src/commands/pack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Шаблон нового плагина: файлы, которые `reformer-plugin create` кладёт в пустой каталог.
|
|
3
|
+
*
|
|
4
|
+
* Шаблон — функции, а не файлы в пакете. Файлы пришлось бы копировать при сборке и не забыть
|
|
5
|
+
* в поле `files`, а их содержимое всё равно зависит от идентификатора и версий: подстановка
|
|
6
|
+
* в строках честнее мини-шаблонизатора.
|
|
7
|
+
*
|
|
8
|
+
* ## Что в шаблоне и почему
|
|
9
|
+
*
|
|
10
|
+
* - **`manifest.json` исходников** — `main` указывает на `src/main.ts`, словари объявлены.
|
|
11
|
+
* Сразу проходит `reformer-plugin validate`: это проверяется тестом, иначе первым опытом
|
|
12
|
+
* автора был бы отказ на только что созданном плагине.
|
|
13
|
+
* - **`src/main.ts`** — одна команда и её подпись из словаря. Минимум, который виден в оболочке
|
|
14
|
+
* (палитра команд) и при этом показывает оба обязательных приёма: вклад через `subscriptions`
|
|
15
|
+
* и строку через ключ, а не текстом.
|
|
16
|
+
* - **`locales/ru.json`, `locales/en.json`** — плоские словари.
|
|
17
|
+
* - **`src/main.test.ts`** — проверка, которую иначе сделает только оболочка: `id` кода совпадает
|
|
18
|
+
* с `id` манифеста. Расхождение — отказ загрузки (`id-mismatch`), и лучше увидеть его в тесте.
|
|
19
|
+
* - **`package.json`** — `@reformer/builder-plugin-api` в `devDependencies`: в рантайме модуль
|
|
20
|
+
* даёт оболочка, в сборку он не попадает (см. README пакета контракта).
|
|
21
|
+
*
|
|
22
|
+
* @module @reformer/builder-plugin-cli/commands/template
|
|
23
|
+
*/
|
|
24
|
+
export interface TemplateInput {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly name: string;
|
|
27
|
+
/** Версия самого CLI — для диапазона в `devDependencies` шаблона. */
|
|
28
|
+
readonly cliVersion: string;
|
|
29
|
+
}
|
|
30
|
+
/** Путь внутри каталога плагина → содержимое. */
|
|
31
|
+
export type TemplateFiles = Readonly<Record<string, string>>;
|
|
32
|
+
export declare function manifestTemplate({ id, name }: Pick<TemplateInput, 'id' | 'name'>): string;
|
|
33
|
+
export declare function pluginTemplate(input: TemplateInput): TemplateFiles;
|
|
34
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/commands/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,iDAAiD;AACjD,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAS7D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG,MAAM,CAWzF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAmElE"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Шаблон нового плагина: файлы, которые `reformer-plugin create` кладёт в пустой каталог.
|
|
3
|
+
*
|
|
4
|
+
* Шаблон — функции, а не файлы в пакете. Файлы пришлось бы копировать при сборке и не забыть
|
|
5
|
+
* в поле `files`, а их содержимое всё равно зависит от идентификатора и версий: подстановка
|
|
6
|
+
* в строках честнее мини-шаблонизатора.
|
|
7
|
+
*
|
|
8
|
+
* ## Что в шаблоне и почему
|
|
9
|
+
*
|
|
10
|
+
* - **`manifest.json` исходников** — `main` указывает на `src/main.ts`, словари объявлены.
|
|
11
|
+
* Сразу проходит `reformer-plugin validate`: это проверяется тестом, иначе первым опытом
|
|
12
|
+
* автора был бы отказ на только что созданном плагине.
|
|
13
|
+
* - **`src/main.ts`** — одна команда и её подпись из словаря. Минимум, который виден в оболочке
|
|
14
|
+
* (палитра команд) и при этом показывает оба обязательных приёма: вклад через `subscriptions`
|
|
15
|
+
* и строку через ключ, а не текстом.
|
|
16
|
+
* - **`locales/ru.json`, `locales/en.json`** — плоские словари.
|
|
17
|
+
* - **`src/main.test.ts`** — проверка, которую иначе сделает только оболочка: `id` кода совпадает
|
|
18
|
+
* с `id` манифеста. Расхождение — отказ загрузки (`id-mismatch`), и лучше увидеть его в тесте.
|
|
19
|
+
* - **`package.json`** — `@reformer/builder-plugin-api` в `devDependencies`: в рантайме модуль
|
|
20
|
+
* даёт оболочка, в сборку он не попадает (см. README пакета контракта).
|
|
21
|
+
*
|
|
22
|
+
* @module @reformer/builder-plugin-cli/commands/template
|
|
23
|
+
*/
|
|
24
|
+
import { BUILDER_API_VERSION } from '@reformer/builder-plugin-api/tooling';
|
|
25
|
+
const json = (value) => `${JSON.stringify(value, null, 2)}\n`;
|
|
26
|
+
/** Мажор API оболочки: диапазон, против которого написан новый плагин. */
|
|
27
|
+
function apiMajor() {
|
|
28
|
+
return BUILDER_API_VERSION.split('.')[0] ?? '1';
|
|
29
|
+
}
|
|
30
|
+
export function manifestTemplate({ id, name }) {
|
|
31
|
+
return json({
|
|
32
|
+
id,
|
|
33
|
+
name,
|
|
34
|
+
version: '0.1.0',
|
|
35
|
+
apiVersion: `^${apiMajor()}`,
|
|
36
|
+
main: 'src/main.ts',
|
|
37
|
+
contributes: {
|
|
38
|
+
messages: { ru: 'locales/ru.json', en: 'locales/en.json' },
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function pluginTemplate(input) {
|
|
43
|
+
const { id, name, cliVersion } = input;
|
|
44
|
+
const commandId = `${id}.hello`;
|
|
45
|
+
return {
|
|
46
|
+
'manifest.json': manifestTemplate(input),
|
|
47
|
+
'package.json': json({
|
|
48
|
+
// Имя пакета npm — только строчные; идентификатор плагина вправе быть другим.
|
|
49
|
+
name: id.toLowerCase(),
|
|
50
|
+
version: '0.1.0',
|
|
51
|
+
private: true,
|
|
52
|
+
type: 'module',
|
|
53
|
+
scripts: {
|
|
54
|
+
validate: 'reformer-plugin validate',
|
|
55
|
+
build: 'reformer-plugin build',
|
|
56
|
+
pack: 'reformer-plugin pack',
|
|
57
|
+
test: 'vitest run',
|
|
58
|
+
},
|
|
59
|
+
devDependencies: {
|
|
60
|
+
'@reformer/builder-plugin-api': `^${apiMajor()}.0.0`,
|
|
61
|
+
'@reformer/builder-plugin-cli': `^${cliVersion}`,
|
|
62
|
+
typescript: '^5.9.3',
|
|
63
|
+
vitest: '^4.0.8',
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
'tsconfig.json': json({
|
|
67
|
+
compilerOptions: {
|
|
68
|
+
target: 'ES2022',
|
|
69
|
+
module: 'ESNext',
|
|
70
|
+
moduleResolution: 'bundler',
|
|
71
|
+
strict: true,
|
|
72
|
+
noEmit: true,
|
|
73
|
+
skipLibCheck: true,
|
|
74
|
+
resolveJsonModule: true,
|
|
75
|
+
},
|
|
76
|
+
include: ['src'],
|
|
77
|
+
}),
|
|
78
|
+
'.gitignore': 'node_modules/\ndist/\n',
|
|
79
|
+
'src/main.ts': `import { definePlugin } from '@reformer/builder-plugin-api';
|
|
80
|
+
|
|
81
|
+
export default definePlugin({
|
|
82
|
+
id: '${id}',
|
|
83
|
+
activate(ctx) {
|
|
84
|
+
ctx.subscriptions.push(
|
|
85
|
+
ctx.commands.register({
|
|
86
|
+
id: '${commandId}',
|
|
87
|
+
// Ключ словаря плагина, а не текст: строки лежат в locales/*.json.
|
|
88
|
+
titleKey: 'command.hello',
|
|
89
|
+
run: () => true,
|
|
90
|
+
})
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
`,
|
|
95
|
+
'src/main.test.ts': `import { expect, it } from 'vitest';
|
|
96
|
+
|
|
97
|
+
import manifest from '../manifest.json';
|
|
98
|
+
import plugin from './main';
|
|
99
|
+
|
|
100
|
+
it('идентификатор кода совпадает с манифестом', () => {
|
|
101
|
+
// Иначе оболочка откажет в загрузке (id-mismatch).
|
|
102
|
+
expect(plugin.id).toBe(manifest.id);
|
|
103
|
+
});
|
|
104
|
+
`,
|
|
105
|
+
'locales/ru.json': json({ 'command.hello': `${name}: привет` }),
|
|
106
|
+
'locales/en.json': json({ 'command.hello': `${name}: hello` }),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/commands/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAY3E,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAE/E,0EAA0E;AAC1E,SAAS,QAAQ;IACf,OAAO,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAsC;IAC/E,OAAO,IAAI,CAAC;QACV,EAAE;QACF,IAAI;QACJ,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,IAAI,QAAQ,EAAE,EAAE;QAC5B,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE;YACX,QAAQ,EAAE,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,iBAAiB,EAAE;SAC3D;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IACvC,MAAM,SAAS,GAAG,GAAG,EAAE,QAAQ,CAAC;IAEhC,OAAO;QACL,eAAe,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACxC,cAAc,EAAE,IAAI,CAAC;YACnB,8EAA8E;YAC9E,IAAI,EAAE,EAAE,CAAC,WAAW,EAAE;YACtB,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE;gBACP,QAAQ,EAAE,0BAA0B;gBACpC,KAAK,EAAE,uBAAuB;gBAC9B,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,YAAY;aACnB;YACD,eAAe,EAAE;gBACf,8BAA8B,EAAE,IAAI,QAAQ,EAAE,MAAM;gBACpD,8BAA8B,EAAE,IAAI,UAAU,EAAE;gBAChD,UAAU,EAAE,QAAQ;gBACpB,MAAM,EAAE,QAAQ;aACjB;SACF,CAAC;QACF,eAAe,EAAE,IAAI,CAAC;YACpB,eAAe,EAAE;gBACf,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,QAAQ;gBAChB,gBAAgB,EAAE,SAAS;gBAC3B,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAI;gBACZ,YAAY,EAAE,IAAI;gBAClB,iBAAiB,EAAE,IAAI;aACxB;YACD,OAAO,EAAE,CAAC,KAAK,CAAC;SACjB,CAAC;QACF,YAAY,EAAE,wBAAwB;QACtC,aAAa,EAAE;;;SAGV,EAAE;;;;eAII,SAAS;;;;;;;;CAQvB;QACG,kBAAkB,EAAE;;;;;;;;;CASvB;QACG,iBAAiB,EAAE,IAAI,CAAC,EAAE,eAAe,EAAE,GAAG,IAAI,UAAU,EAAE,CAAC;QAC/D,iBAAiB,EAAE,IAAI,CAAC,EAAE,eAAe,EAAE,GAAG,IAAI,SAAS,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reformer-plugin validate`: пропустит ли оболочка этот плагин — ДО оболочки.
|
|
3
|
+
*
|
|
4
|
+
* Каждое правило здесь взято из пакета контракта, а не написано заново: разбор манифеста,
|
|
5
|
+
* разбор словаря, расширения кода. Валидатор, пропускающий то, что оболочка отвергнет, хуже
|
|
6
|
+
* отсутствия валидатора, — поэтому своего у CLI только то, чего оболочка не видит вовсе.
|
|
7
|
+
*
|
|
8
|
+
* ## Что проверяется
|
|
9
|
+
*
|
|
10
|
+
* 1. **Манифест исходников** — `parsePluginSourceManifest`: всё, что проверяет оболочка, кроме
|
|
11
|
+
* имени каталога, плюс обязательная версия. Отказ здесь останавливает проверку: без манифеста
|
|
12
|
+
* не известно, какие файлы искать.
|
|
13
|
+
* 2. **Файлы, на которые манифест ссылается**: точка входа (есть и это код), таблица стилей,
|
|
14
|
+
* словари (есть и плоские). Оболочка отказывает на них при загрузке — здесь то же
|
|
15
|
+
* отказом, но до неё. Эти проверки собираются ВСЕ: автору полезнее список, чем первая беда.
|
|
16
|
+
* 3. **Версия `package.json`**, если он есть, совпадает с версией манифеста. Оболочка
|
|
17
|
+
* `package.json` не читает, поэтому расхождение она не заметит, — а упаковка опубликует пакет
|
|
18
|
+
* одной версии с манифестом другой.
|
|
19
|
+
*
|
|
20
|
+
* Чего здесь НЕТ и почему: сверки `provides` с тем, что плагин регистрирует, потолка числа
|
|
21
|
+
* файлов и сверки `compatibility.builder` с версией билдера. Первое требует исполнить код,
|
|
22
|
+
* второе относится к собранному каталогу, а третьего CLI знать не может: в каком билдере плагин
|
|
23
|
+
* запустят, решает не он, и отказ по этому полю был бы отказом по выдуманному числу. Форма
|
|
24
|
+
* диапазона при этом проверяется — опечатка ловится здесь, а не у человека при загрузке.
|
|
25
|
+
*
|
|
26
|
+
* @module @reformer/builder-plugin-cli/commands/validate
|
|
27
|
+
*/
|
|
28
|
+
import { type PluginSourceManifest } from '@reformer/builder-plugin-api/tooling';
|
|
29
|
+
import type { Finding } from './findings.js';
|
|
30
|
+
/** Замечание валидатора; общий тип всех команд — `./findings`. */
|
|
31
|
+
export type ValidationFinding = Finding;
|
|
32
|
+
export type ValidationResult = {
|
|
33
|
+
readonly ok: true;
|
|
34
|
+
readonly manifest: PluginSourceManifest;
|
|
35
|
+
} | {
|
|
36
|
+
readonly ok: false;
|
|
37
|
+
/** Есть, если манифест разобран, а отказали файлы вокруг него. */
|
|
38
|
+
readonly manifest?: PluginSourceManifest;
|
|
39
|
+
readonly findings: readonly ValidationFinding[];
|
|
40
|
+
};
|
|
41
|
+
/** Проверяет каталог исходников плагина. Ничего не бросает: отказы — данные. */
|
|
42
|
+
export declare function validatePlugin(dir: string): Promise<ValidationResult>;
|
|
43
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,kEAAkE;AAClE,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAExC,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAA;CAAE,GAC9D;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACjD,CAAC;AAkBN,gFAAgF;AAChF,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoF3E"}
|