@reformer/builder-plugin-api 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 +206 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.js +76 -0
- package/dist/internal.d.ts +78 -0
- package/dist/internal.js +289 -0
- package/dist/permissions-BWlsUVPs.js +551 -0
- package/dist/plugin/bundled-modules.d.ts +25 -0
- package/dist/plugin/layout.d.ts +27 -0
- package/dist/plugin/manifest-parser.d.ts +54 -0
- package/dist/plugin/manifest.d.ts +320 -0
- package/dist/plugin/messages-bundle.d.ts +24 -0
- package/dist/plugin/permissions.d.ts +48 -0
- package/dist/plugin/plugin-exports.d.ts +10 -0
- package/dist/plugin/runtime-modules.d.ts +20 -0
- package/dist/plugin/storage.d.ts +70 -0
- package/dist/plugin/types.d.ts +136 -0
- package/dist/primitives/capability.d.ts +72 -0
- package/dist/primitives/command.d.ts +262 -0
- package/dist/primitives/disposable.d.ts +23 -0
- package/dist/primitives/event.d.ts +38 -0
- package/dist/primitives/extension-point.d.ts +53 -0
- package/dist/primitives/module-path.d.ts +21 -0
- package/dist/primitives/resource.d.ts +159 -0
- package/dist/primitives/semver.d.ts +93 -0
- package/dist/primitives/service.d.ts +68 -0
- package/dist/primitives/when-context.d.ts +69 -0
- package/dist/primitives/when-expr.d.ts +177 -0
- package/dist/resource-clipboard-Bdk_Is5N.js +381 -0
- package/dist/runtime-modules-CiUDFMIn.js +597 -0
- package/dist/services/context-keys.d.ts +52 -0
- package/dist/services/diagnostics/fixes.d.ts +40 -0
- package/dist/services/diagnostics/service.d.ts +34 -0
- package/dist/services/diagnostics/types.d.ts +148 -0
- package/dist/services/document-models.d.ts +20 -0
- package/dist/services/documents.d.ts +94 -0
- package/dist/services/host-messages.d.ts +10 -0
- package/dist/services/i18n.d.ts +43 -0
- package/dist/services/modules.d.ts +49 -0
- package/dist/services/notifications.d.ts +56 -0
- package/dist/services/plugin-settings.d.ts +10 -0
- package/dist/services/plugins-catalog.d.ts +58 -0
- package/dist/services/preview.d.ts +163 -0
- package/dist/services/prompt.d.ts +111 -0
- package/dist/services/resource-clipboard.d.ts +28 -0
- package/dist/services/selection.d.ts +46 -0
- package/dist/services/settings.d.ts +44 -0
- package/dist/services/theme.d.ts +15 -0
- package/dist/services/validation/types.d.ts +98 -0
- package/dist/services/workspace-files.d.ts +84 -0
- package/dist/services/workspace-resources.d.ts +41 -0
- package/dist/services/workspace-save.d.ts +18 -0
- package/dist/tooling.d.ts +28 -0
- package/dist/tooling.js +35 -0
- package/dist/ui/contributions/decorations.d.ts +55 -0
- package/dist/ui/contributions/editors.d.ts +58 -0
- package/dist/ui/contributions/plugin-settings.d.ts +54 -0
- package/dist/ui/keyboard/keybinding-rules.d.ts +48 -0
- package/dist/ui/keyboard/keybindings.d.ts +55 -0
- package/dist/ui/keyboard/keymap.d.ts +81 -0
- package/dist/ui/keyboard/scope.d.ts +38 -0
- package/dist/ui/menu/editor-menu.d.ts +25 -0
- package/dist/ui/menu/menu.d.ts +228 -0
- package/dist/ui/menu/palette.d.ts +36 -0
- package/dist/ui/menu/resource-menu.d.ts +45 -0
- package/dist/ui/slots.d.ts +113 -0
- package/dist/ui/useActiveDocument.d.ts +5 -0
- package/dist/ui/useLocale.d.ts +9 -0
- package/dist/ui/useTranslate.d.ts +4 -0
- package/dist/workspace/document.d.ts +42 -0
- package/dist/workspace/model/editor-view-states.d.ts +29 -0
- package/dist/workspace/model/model-document.d.ts +86 -0
- package/dist/workspace/model/provider.d.ts +140 -0
- package/dist/workspace/model/text-editor-focus.d.ts +22 -0
- package/dist/workspace/resource-names.d.ts +92 -0
- package/dist/workspace/write-options.d.ts +36 -0
- package/package.json +69 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Disposable } from '../../primitives/disposable.js';
|
|
2
|
+
import { ResourceId } from '../../primitives/resource.js';
|
|
3
|
+
import { Diagnostic } from './types.js';
|
|
4
|
+
export interface DiagnosticsService {
|
|
5
|
+
/**
|
|
6
|
+
* Замещает результаты источника по ресурсу.
|
|
7
|
+
*
|
|
8
|
+
* Пустой список снимает всё, что этот источник публиковал раньше. Записи других
|
|
9
|
+
* источников не затрагиваются: они сосуществуют и складываются в общий свод.
|
|
10
|
+
*/
|
|
11
|
+
publish(resource: ResourceId, source: string, items: readonly Diagnostic[]): void;
|
|
12
|
+
/**
|
|
13
|
+
* Все диагностики ресурса: сначала по источнику (в алфавитном порядке), внутри источника —
|
|
14
|
+
* в порядке публикации. Между изменениями — та же ссылка.
|
|
15
|
+
*/
|
|
16
|
+
get(resource: ResourceId): readonly Diagnostic[];
|
|
17
|
+
/**
|
|
18
|
+
* Ресурсы, у которых сейчас есть находки, — в алфавитном порядке идентификатора.
|
|
19
|
+
*
|
|
20
|
+
* Без перечисления свод читается только по одному адресу, а панель проблем спрашивает
|
|
21
|
+
* ровно обратное: «что вообще найдено». Собрать этот ответ снаружи нечем — обход открытых
|
|
22
|
+
* вкладок дал бы другой список, потому что публикуют не только по открытым документам,
|
|
23
|
+
* а перечисление источников не заменяет перечисления адресов.
|
|
24
|
+
*
|
|
25
|
+
* Порядок алфавитный по той же причине, по которой алфавитен порядок источников в {@link
|
|
26
|
+
* DiagnosticsService.get}: «кто успел раньше» перескакивало бы при каждом перезапуске
|
|
27
|
+
* валидаторов, и глаз терял бы строку, на которую смотрел. Между изменениями СОСТАВА —
|
|
28
|
+
* та же ссылка: список читает `useSyncExternalStore`.
|
|
29
|
+
*/
|
|
30
|
+
resources(): readonly ResourceId[];
|
|
31
|
+
/** Свод ресурса изменился. Полезная нагрузка — какого именно. */
|
|
32
|
+
onDidChange(cb: (resource: ResourceId) => void): Disposable;
|
|
33
|
+
}
|
|
34
|
+
export declare const DiagnosticsServiceToken: import('../../index.js').ServiceToken<DiagnosticsService>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Форма диагностики: во что валидатор облекает найденную проблему.
|
|
3
|
+
*
|
|
4
|
+
* Два свойства, из которых следует всё остальное:
|
|
5
|
+
*
|
|
6
|
+
* **У диагностики ровно одна цель.** Не «и диапазон, и узел». Синтаксическая ошибка адресуется
|
|
7
|
+
* диапазоном, потому что узла ещё нет — текст не разобрался. Структурная адресуется
|
|
8
|
+
* идентификатором узла, потому что он не съезжает при вставке соседей, а путь съезжает.
|
|
9
|
+
* Двойная адресация означала бы, что валидатор обязан посчитать оба адреса, и один из них
|
|
10
|
+
* (диапазон структурной ошибки) он вычислял бы симуляцией печати — то есть врал бы.
|
|
11
|
+
* Перевод «узел → диапазон» делает тот, кто рисует, по тексту, который сейчас в редакторе.
|
|
12
|
+
*
|
|
13
|
+
* Узловая цель при этом умеет СУЖАТЬСЯ до свойства внутри узла ({@link DiagnosticTarget.within}),
|
|
14
|
+
* и это не вторая адресация: адрес по-прежнему один — узел, — а путь отсчитывается ОТ НЕГО
|
|
15
|
+
* и потому съезжает не больше, чем сам идентификатор. Запрет на путь в находке — про путь
|
|
16
|
+
* УЗЛА от корня документа: тот двигается вставкой соседа где угодно выше и потому спрашивается
|
|
17
|
+
* у модели в момент показа. Путь ВНУТРИ узла двигается только вместе со своим узлом, а из
|
|
18
|
+
* текста его не восстановить: про то, что виноват именно `readOnly`, знает валидатор и никто
|
|
19
|
+
* больше. Без сужения «у компонента нет свойства readOnly» подчёркивало бы `$nodeId` —
|
|
20
|
+
* единственное место узла, которое к ошибке не относится.
|
|
21
|
+
*
|
|
22
|
+
* Правило для потребителя: **уточнение можно игнорировать**. Кто читает только `kind`
|
|
23
|
+
* и `nodeId`, остаётся прав — поэтому поле и необязательное, а не отдельный вид цели:
|
|
24
|
+
* новый вид молча выпал бы из проверок `kind === 'node'` в панели проблем и на канвасе.
|
|
25
|
+
*
|
|
26
|
+
* **Сообщение — это код и параметры, а не готовая строка.** По коду ассистент чинится сам,
|
|
27
|
+
* по переведённой фразе не может. И одна ошибка выглядит одинаково в интерфейсе, в логе
|
|
28
|
+
* и в тесте, потому что переводится в момент показа, а не в момент возникновения.
|
|
29
|
+
*
|
|
30
|
+
* @module @reformer/builder-plugin-api/services/diagnostics/types
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Полуинтервал `[start, end)` в тексте ресурса, **в кодовых единицах UTF-16**.
|
|
34
|
+
*
|
|
35
|
+
* Единицы названы намеренно и совпадают с `TextEdit.offset` из журнала изменений: JavaScript
|
|
36
|
+
* и Monaco считают именно так, и потребитель, решивший, что это байты или кодовые точки,
|
|
37
|
+
* сломается на первом эмодзи. Смещения, а не «строка/колонка», потому что смещение — это то,
|
|
38
|
+
* что отдаёт разбор с позициями, и то, что Monaco переводит в позицию одним вызовом;
|
|
39
|
+
* обратный перевод потребовал бы считать начала строк и разъезжался бы на разных переводах
|
|
40
|
+
* строки.
|
|
41
|
+
*/
|
|
42
|
+
export interface TextRange {
|
|
43
|
+
readonly start: number;
|
|
44
|
+
readonly end: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Что подчеркнуть у свойства, на которое показывает `within` узловой цели.
|
|
48
|
+
*
|
|
49
|
+
* `name` — токен имени вместе с кавычками, он всегда короткий. `value` — само значение,
|
|
50
|
+
* и только там, где виновато ОНО: `$component(Inpit)`, «must be boolean». Значение-поддерево
|
|
51
|
+
* при этом не подчёркивается — см. заметку о выборе места в `editor-monaco/diagnostics`.
|
|
52
|
+
*/
|
|
53
|
+
export type NodePart = 'name' | 'value';
|
|
54
|
+
/** Куда показывает диагностика. Ровно один вариант — см. заголовок модуля. */
|
|
55
|
+
export type DiagnosticTarget = {
|
|
56
|
+
readonly kind: 'node';
|
|
57
|
+
readonly nodeId: string;
|
|
58
|
+
/**
|
|
59
|
+
* Уточнение места ВНУТРИ узла: путь от самого узла до свойства-виновника
|
|
60
|
+
* (`['componentProps', 'readOnly']`). Отсутствует или пуст — находка о узле целиком.
|
|
61
|
+
*
|
|
62
|
+
* Это по-прежнему ОДНА цель, а не вторая: адресом остаётся узел, путь лишь сужает место
|
|
63
|
+
* внутри него. И он не съезжает ровно по той причине, по которой не съезжает
|
|
64
|
+
* идентификатор: он отсчитывается ОТ УЗЛА, поэтому вставка соседей где угодно в документе
|
|
65
|
+
* его не двигает. Абсолютный путь в находку класть по-прежнему нельзя — он устаревает
|
|
66
|
+
* вместе с показом.
|
|
67
|
+
*
|
|
68
|
+
* Перевод «путь → диапазон» остаётся за тем, кто РИСУЕТ: свойство ищется в тексте,
|
|
69
|
+
* который сейчас в редакторе. Не нашлось — подчёркивается узел, как и раньше.
|
|
70
|
+
*/
|
|
71
|
+
readonly within?: readonly (string | number)[];
|
|
72
|
+
/** Что подчеркнуть у найденного свойства. По умолчанию — имя: оно всегда коротко. */
|
|
73
|
+
readonly at?: NodePart;
|
|
74
|
+
} | {
|
|
75
|
+
readonly kind: 'range';
|
|
76
|
+
readonly range: TextRange;
|
|
77
|
+
}
|
|
78
|
+
/** Проблема всего ресурса: файл не читается, схема не того вида. */
|
|
79
|
+
| {
|
|
80
|
+
readonly kind: 'resource';
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Проблема ресурса, которой НЕТ в его тексте: она в приложенном файле, который этот ресурс
|
|
84
|
+
* тянет за собой, — для формы это сайдкар правил.
|
|
85
|
+
*
|
|
86
|
+
* Ресурс остаётся адресом, потому что через него проблема и чинится: команда правки правил
|
|
87
|
+
* получает адрес СХЕМЫ, а файл правил находит по нему сама. Но подчеркнуть в схеме нечего —
|
|
88
|
+
* правило указывает на поле, которого в ней нет, в том и находка. `resource` тут не годится:
|
|
89
|
+
* он означает «ошибка уровня документа», и рисующий ставит на неё маркер первой строки —
|
|
90
|
+
* то есть на `{` файла, к которому находка не относится.
|
|
91
|
+
*
|
|
92
|
+
* Отдельный вид, а не флаг у `resource`, потому что все, кто различает цели, должны решить
|
|
93
|
+
* заново: рисующий — не ставить маркер, канвас — посчитать в неразмещённые (как и `resource`),
|
|
94
|
+
* панель проблем — показать строку без бейджа узла. Проверка `kind !== 'node'` даёт всё это
|
|
95
|
+
* сама, а `switch` у рисующего заставит компилятор напомнить.
|
|
96
|
+
*/
|
|
97
|
+
| {
|
|
98
|
+
readonly kind: 'attached';
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Готовое исправление: ассистент получает не только «что не так», но и «чем чинить»,
|
|
102
|
+
* и чинит той же командой, что и человек.
|
|
103
|
+
*/
|
|
104
|
+
export interface QuickFix {
|
|
105
|
+
/** Ключ i18n подписи. */
|
|
106
|
+
readonly titleKey: string;
|
|
107
|
+
readonly commandId: string;
|
|
108
|
+
readonly args?: unknown;
|
|
109
|
+
}
|
|
110
|
+
export type DiagnosticSeverity = 'error' | 'warning' | 'info';
|
|
111
|
+
/**
|
|
112
|
+
* Порядок строгости: чем больше, тем строже.
|
|
113
|
+
*
|
|
114
|
+
* Живёт рядом со словарём, а не у каждого потребителя. Сравнивать строгости нужно всем,
|
|
115
|
+
* кто показывает диагностику — дереву (какой тон у значка), канвасу (метка на узле),
|
|
116
|
+
* панели проблем (что показать первым), — а плагины не видят друг друга и завели бы по
|
|
117
|
+
* копии. Копии совпадали бы «по договорённости», то есть до первой правки словаря.
|
|
118
|
+
*/
|
|
119
|
+
export declare const SEVERITY_RANK: Readonly<Record<DiagnosticSeverity, number>>;
|
|
120
|
+
export interface Diagnostic {
|
|
121
|
+
/** Идентификатор валидатора. По нему `publish` замещает прошлый результат. */
|
|
122
|
+
readonly source: string;
|
|
123
|
+
readonly severity: DiagnosticSeverity;
|
|
124
|
+
/**
|
|
125
|
+
* Ключ i18n, не текст. Голый код (`schema.unknown-component`) переводится словарём
|
|
126
|
+
* оболочки по ключу `errors.<code>`; код вида `<plugin-id>:<code>` — словарём ВНЁСШЕГО
|
|
127
|
+
* плагина по ключу `errors.<code>` (см. {@link pluginDiagnosticCode}).
|
|
128
|
+
*/
|
|
129
|
+
readonly code: string;
|
|
130
|
+
readonly params?: Record<string, unknown>;
|
|
131
|
+
readonly target: DiagnosticTarget;
|
|
132
|
+
readonly fixes?: readonly QuickFix[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Код находки, текст которой лежит в словаре плагина-владельца.
|
|
136
|
+
*
|
|
137
|
+
* Словарь оболочки общий (`errors.<code>`): одна ошибка звучит одинаково в подчёркивании,
|
|
138
|
+
* на канвасе и в панели проблем. Но стек, пришедший плагином, в словарь оболочки писать
|
|
139
|
+
* не может — и не должен: оболочка тогда знала бы его ошибки. Такой код несёт владельца,
|
|
140
|
+
* и переводчик ищет `errors.<code>` в его пространстве имён; плагин кладёт текст туда же,
|
|
141
|
+
* куда и остальные свои строки (`ctx.i18n.contribute`).
|
|
142
|
+
*/
|
|
143
|
+
export declare function pluginDiagnosticCode(pluginId: string, code: string): string;
|
|
144
|
+
/** Владелец кода находки (`null` — оболочка) и сам код без владельца. */
|
|
145
|
+
export declare function splitDiagnosticCode(code: string): {
|
|
146
|
+
readonly pluginId: string | null;
|
|
147
|
+
readonly code: string;
|
|
148
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Capability } from '../primitives/capability.js';
|
|
2
|
+
import { ResourceId } from '../primitives/resource.js';
|
|
3
|
+
import { ModelDocumentHandle } from '../workspace/model/model-document.js';
|
|
4
|
+
export interface DocumentModelsService {
|
|
5
|
+
/**
|
|
6
|
+
* Ручка модельного документа открытой вкладки.
|
|
7
|
+
*
|
|
8
|
+
* `null` — три разные вещи, одинаковые для редактора: вкладка ещё открывается, её закрыли,
|
|
9
|
+
* документ текстовый (провайдер не взялся или первый разбор не удался). Во всех трёх случаях
|
|
10
|
+
* править нечего.
|
|
11
|
+
*/
|
|
12
|
+
handleOf(id: ResourceId): ModelDocumentHandle<unknown> | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Возможность «модели документов». Провайдер — оболочка (`platform/services/host-capabilities`):
|
|
16
|
+
* модели заводит она, и без проекта служба честно отвечает `null`.
|
|
17
|
+
*
|
|
18
|
+
* Версия `1.0.0` — исходная.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DocumentModelsCapability: Capability<DocumentModelsService>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Disposable } from '../primitives/disposable.js';
|
|
2
|
+
import { ResourceId } from '../primitives/resource.js';
|
|
3
|
+
import { Capability } from '../primitives/capability.js';
|
|
4
|
+
import { Document } from '../workspace/document.js';
|
|
5
|
+
import { WriteOptions } from '../workspace/write-options.js';
|
|
6
|
+
/**
|
|
7
|
+
* Чем править открытие вкладки.
|
|
8
|
+
*
|
|
9
|
+
* Объявлено здесь, а не взято у хранилища вкладок: служба лежит НИЖЕ интерфейса и на его
|
|
10
|
+
* состояние ссылаться не должна. Совместимость с настоящими опциями вкладки проверяет
|
|
11
|
+
* компиляция порта — там значение уходит в `documents.open` без приведения.
|
|
12
|
+
*/
|
|
13
|
+
export interface OpenDocumentOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Временная вкладка (`true` по умолчанию, как у щелчка в дереве): следующая такая же
|
|
16
|
+
* займёт её место. `false` — закрепить: человек пришёл править, а не посмотреть.
|
|
17
|
+
*/
|
|
18
|
+
readonly preview?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface DocumentsService {
|
|
21
|
+
/** Открыт ли проект. Без него остальное отвечает `null` и отказом — см. шапку. */
|
|
22
|
+
hasProject(): boolean;
|
|
23
|
+
/** Ресурс активной вкладки; `null` без проекта и без вкладок. */
|
|
24
|
+
activeResource(): ResourceId | null;
|
|
25
|
+
/**
|
|
26
|
+
* Ресурсы ВСЕХ открытых вкладок, в порядке вкладок. Без проекта — пусто.
|
|
27
|
+
*
|
|
28
|
+
* Не то же, что {@link activeResource}, и нужен тем, чьё состояние живёт дольше активной
|
|
29
|
+
* вкладки: превью помнит значения формы и находки сборки, пока открыт хоть один файл её
|
|
30
|
+
* каталога, и «хоть один» из активного не выводится — активным в этот миг бывает файл
|
|
31
|
+
* из совсем другого места.
|
|
32
|
+
*
|
|
33
|
+
* Список, а не событие «вкладку закрыли»: у хранилища вкладок событие одно — «снимок
|
|
34
|
+
* сменился», — и сведение по снимку не пропускает закрытие, случившееся мимо уведомления
|
|
35
|
+
* (смена проекта закрывает все вкладки разом).
|
|
36
|
+
*/
|
|
37
|
+
openDocuments(): readonly ResourceId[];
|
|
38
|
+
/**
|
|
39
|
+
* Документ открытой вкладки. Настоящий {@link Document}, а не копия: `getText()` — то,
|
|
40
|
+
* что уйдёт в файл при сохранении, а {@link Document.onDidChangeContent} — единственный
|
|
41
|
+
* способ узнать о правке текста (в том числе чужой: ассистента, слияния, отката).
|
|
42
|
+
*/
|
|
43
|
+
documentOf(id: ResourceId): Document | null;
|
|
44
|
+
/**
|
|
45
|
+
* Записывает текст в рабочую копию. Без проекта — отказ обещанием, а не тишина:
|
|
46
|
+
* правка, ушедшая в никуда, выглядит как сохранённая.
|
|
47
|
+
*
|
|
48
|
+
* Третий аргумент обязателен к пробросу до рабочей области: без него ход ассистента
|
|
49
|
+
* попадает в журнал как правка человека.
|
|
50
|
+
*/
|
|
51
|
+
writeText(id: ResourceId, text: string, options?: WriteOptions): Promise<void>;
|
|
52
|
+
/** Открывает вкладку и делает её активной. Без проекта — отказ, как у записи. */
|
|
53
|
+
open(id: ResourceId, options?: OpenDocumentOptions): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Выполнить отложенную перерисовку буфера по модели. Зовётся на уходе фокуса.
|
|
56
|
+
*
|
|
57
|
+
* Нужен редактору модельного документа, и без него контракт редактора не закрывается. Пока
|
|
58
|
+
* человек печатает, платформа откладывает перерисовку буфера из модели — она спрашивает
|
|
59
|
+
* реестр фокуса (`TextEditorFocusToken`), в который редактор и пишет. Снятый фокус и есть
|
|
60
|
+
* тот момент, когда откладывать больше не из-за чего, поэтому порядок несущий: сперва
|
|
61
|
+
* `setFocused(id, false)`, потом `flush(id)`.
|
|
62
|
+
*
|
|
63
|
+
* У текстового документа модели нет и откладывать нечего: вызов безвреден.
|
|
64
|
+
*/
|
|
65
|
+
flush(id: ResourceId): void | Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Сменился проект или вкладки: открытие, закрытие, активация. Нагрузки нет намеренно —
|
|
68
|
+
* подписчик перечитывает снимок ({@link activeResource}, {@link documentOf}).
|
|
69
|
+
*/
|
|
70
|
+
onDidChange(cb: () => void): Disposable;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Рабочая область как ВОЗМОЖНОСТЬ: токен службы плюс версия контракта.
|
|
74
|
+
*
|
|
75
|
+
* Провайдер — сама оболочка, а не плагин (`services/host-capabilities`): служба существует
|
|
76
|
+
* с запуска, потому что без неё редактор из каталога проекта не редактор, и ставить её
|
|
77
|
+
* появление в зависимость от состава плагинов значило бы, что профиль без превью отнимает
|
|
78
|
+
* у внешнего редактора текст документа.
|
|
79
|
+
*
|
|
80
|
+
* Идентификатор ПРЕЖНИЙ — `shell.documents`, хотя RFC зовёт эту возможность
|
|
81
|
+
* `reformer.workspace`: смена `id` службы — это миграция сохранённых данных и чужих
|
|
82
|
+
* манифестов, и она отложена целиком в фазу 7 плана v4 (там же переименование `kits.active`).
|
|
83
|
+
*
|
|
84
|
+
* Версия `1.0.0` — исходная: {@link DocumentsService} на момент объявления, вместе
|
|
85
|
+
* с `openDocuments`. Растит её тот, кто интерфейс меняет: минор — добавленный метод,
|
|
86
|
+
* мажор — удалённый или сменивший смысл.
|
|
87
|
+
*/
|
|
88
|
+
export declare const DocumentsCapability: Capability<DocumentsService>;
|
|
89
|
+
/**
|
|
90
|
+
* Токен службы. ТОТ ЖЕ объект, что {@link DocumentsCapability}: возможность расширяет токен,
|
|
91
|
+
* второго реестра нет (`primitives/capability`). Имя оставлено — им пользуется `@reformer/builder-plugin-api`
|
|
92
|
+
* и каждый плагин, который уже берёт службу.
|
|
93
|
+
*/
|
|
94
|
+
export declare const DocumentsServiceToken: Capability<DocumentsService>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Capability } from '../primitives/capability.js';
|
|
2
|
+
import { PluginI18n } from './i18n.js';
|
|
3
|
+
/** Словарь оболочки: локаль, перевод ключа без приставки плагина, смена локали. */
|
|
4
|
+
export type HostMessagesService = Pick<PluginI18n, 'locale' | 't' | 'onDidChangeLocale'>;
|
|
5
|
+
/**
|
|
6
|
+
* Возможность «словарь оболочки». Провайдер — оболочка.
|
|
7
|
+
*
|
|
8
|
+
* Версия `1.0.0` — исходная.
|
|
9
|
+
*/
|
|
10
|
+
export declare const HostMessagesCapability: Capability<HostMessagesService>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Disposable } from '../primitives/disposable.js';
|
|
2
|
+
/** Вид сервиса для плагина: ключи автоматически префиксуются его идентификатором. */
|
|
3
|
+
export interface PluginI18n {
|
|
4
|
+
/**
|
|
5
|
+
* Действующая локаль — та же, что у корня: у вида своей быть не может.
|
|
6
|
+
*
|
|
7
|
+
* Нужна не для показа, а для перерисовки: снимок для `useSyncExternalStore` обязан меняться
|
|
8
|
+
* вместе с языком, иначе панель плагина осталась бы на прежних строках до следующей правки
|
|
9
|
+
* своего состояния (см. `ui/useTranslate`).
|
|
10
|
+
*/
|
|
11
|
+
readonly locale: string;
|
|
12
|
+
t(key: string, params?: Record<string, unknown>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Локаль сменилась. Тот же канал, что у корня: подписка идёт НАПРЯМУЮ к нему, потому что
|
|
15
|
+
* язык у приложения один, а вид — всего лишь пространство имён ключей.
|
|
16
|
+
*/
|
|
17
|
+
onDidChangeLocale(cb: (locale: string) => void): Disposable;
|
|
18
|
+
/**
|
|
19
|
+
* Регистрирует словарь в пространстве имён плагина.
|
|
20
|
+
*
|
|
21
|
+
* Повторный вызов для той же локали **дополняет** словарь, а не заменяет его: плагин вправе
|
|
22
|
+
* везти словарь по частям — например, догружать раздел вместе с панелью.
|
|
23
|
+
*
|
|
24
|
+
* Бросает, если сообщение не разбирается, называя ключ. Ни одно сообщение этого вызова
|
|
25
|
+
* при этом не регистрируется.
|
|
26
|
+
*/
|
|
27
|
+
contribute(locale: string, messages: Readonly<Record<string, string>>): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ключ сообщения, текст которого лежит в словаре плагина-владельца: `<plugin-id>:<key>`.
|
|
31
|
+
*
|
|
32
|
+
* Нужен там, где строку переводит НЕ плагин, а тот, кто показывает, — уведомления и находки.
|
|
33
|
+
* Показывающий общий на всех, и без владельца он знал бы только свой словарь: стек, пришедший
|
|
34
|
+
* плагином, либо писал бы в словарь оболочки (которой его строки не принадлежат), либо
|
|
35
|
+
* показывал бы маркер промаха. Ключ с владельцем переводится словарём владельца, голый — словарём
|
|
36
|
+
* оболочки, как раньше.
|
|
37
|
+
*/
|
|
38
|
+
export declare function pluginMessageKey(pluginId: string, key: string): string;
|
|
39
|
+
/** Владелец ключа (`null` — оболочка) и сам ключ без владельца. */
|
|
40
|
+
export declare function splitMessageKey(key: string): {
|
|
41
|
+
readonly pluginId: string | null;
|
|
42
|
+
readonly key: string;
|
|
43
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Capability } from '../primitives/capability.js';
|
|
2
|
+
import { TextRange } from './diagnostics/types.js';
|
|
3
|
+
/** Сбой загрузки одного файла. */
|
|
4
|
+
export interface ModuleLoadProblem {
|
|
5
|
+
readonly file: string;
|
|
6
|
+
readonly phase: 'resolve' | 'transpile' | 'evaluate';
|
|
7
|
+
readonly message: string;
|
|
8
|
+
/** Место в исходнике файла, если фаза его знает (транспиляция — знает). */
|
|
9
|
+
readonly range?: TextRange;
|
|
10
|
+
}
|
|
11
|
+
/** Результат загрузки графа модулей. */
|
|
12
|
+
export interface ModuleGraph {
|
|
13
|
+
readonly entry: unknown;
|
|
14
|
+
readonly modules: ReadonlyMap<string, unknown>;
|
|
15
|
+
readonly errors: readonly ModuleLoadProblem[];
|
|
16
|
+
/** Что пришлось транспилировать: путь → JS. Уходит обратно в кэш сборки. */
|
|
17
|
+
readonly compiled?: ReadonlyMap<string, string>;
|
|
18
|
+
}
|
|
19
|
+
/** Прогретая компиляция набора: готовое из кэша и способ вернуть собранное. */
|
|
20
|
+
export interface PrimedCompile {
|
|
21
|
+
/** Готовый JS, взятый из кэша: путь → код. */
|
|
22
|
+
readonly ready: ReadonlyMap<string, string>;
|
|
23
|
+
/** Нашлось ли всё. `false` означает, что движок транспиляции уже разбужен. */
|
|
24
|
+
readonly complete: boolean;
|
|
25
|
+
/** Отдать на хранение то, что собралось. Зовётся после линковки — до неё состав неизвестен. */
|
|
26
|
+
commit(compiled: ReadonlyMap<string, string>): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export interface ModuleLoaderService {
|
|
29
|
+
/**
|
|
30
|
+
* Прогрев перед линковкой; ОБЯЗАН завершиться до {@link load}: внутри `require` асинхронного
|
|
31
|
+
* шага быть не может. Принимает ФАЙЛЫ, а не имена: ответить «движок не нужен, всё собрано»
|
|
32
|
+
* можно, только зная содержимое.
|
|
33
|
+
*/
|
|
34
|
+
prepare(files: ReadonlyMap<string, string>): Promise<PrimedCompile>;
|
|
35
|
+
load(files: ReadonlyMap<string, string>, entry: string, options?: {
|
|
36
|
+
/** Готовый JS из кэша: путь → код. */
|
|
37
|
+
readonly ready?: ReadonlyMap<string, string>;
|
|
38
|
+
/** Подстановки импортов: спецификатор → готовые экспорты. */
|
|
39
|
+
readonly overrides?: ReadonlyMap<string, unknown>;
|
|
40
|
+
/** Лексически подставляемое окружение: `fetch`, `Date`, `Math`. */
|
|
41
|
+
readonly ambient?: Readonly<Record<string, unknown>>;
|
|
42
|
+
}): Promise<ModuleGraph>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Возможность «загрузчик модулей». Провайдер — оболочка: движок один на приложение.
|
|
46
|
+
*
|
|
47
|
+
* Версия `1.0.0` — исходная.
|
|
48
|
+
*/
|
|
49
|
+
export declare const ModuleLoaderCapability: Capability<ModuleLoaderService>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Disposable } from '../primitives/disposable.js';
|
|
2
|
+
/** Уровень тоста. Определяет вид и озвучку для скринридера, но не поведение очереди. */
|
|
3
|
+
export type NotificationLevel = 'info' | 'success' | 'warning' | 'error';
|
|
4
|
+
/** Необязательное действие: одна кнопка на тосте. */
|
|
5
|
+
export interface NotificationAction {
|
|
6
|
+
/** Ключ i18n подписи кнопки. */
|
|
7
|
+
readonly titleKey: string;
|
|
8
|
+
/** Что сделать по нажатию. Закрытие тоста — дело отрисовки, здесь только действие. */
|
|
9
|
+
run(): void;
|
|
10
|
+
}
|
|
11
|
+
/** Что просят показать. */
|
|
12
|
+
export interface NotificationRequest {
|
|
13
|
+
/** По умолчанию `info`. */
|
|
14
|
+
readonly level?: NotificationLevel;
|
|
15
|
+
/**
|
|
16
|
+
* Ключ i18n сообщения. Голый ключ переводит словарь оболочки; свою строку плагин называет
|
|
17
|
+
* ключом с владельцем — `pluginMessageKey(pluginId, key)` — и она берётся из ЕГО словаря.
|
|
18
|
+
*/
|
|
19
|
+
readonly messageKey: string;
|
|
20
|
+
readonly params?: Record<string, unknown>;
|
|
21
|
+
readonly action?: NotificationAction;
|
|
22
|
+
/** Подсказка отрисовке, сколько держать тост. Без значения решает отрисовка. */
|
|
23
|
+
readonly durationMs?: number;
|
|
24
|
+
}
|
|
25
|
+
/** Уведомление в очереди: запрос плюс выданный идентификатор, с проставленным уровнем. */
|
|
26
|
+
export interface Notification extends NotificationRequest {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly level: NotificationLevel;
|
|
29
|
+
}
|
|
30
|
+
/** Ссылка на показанное уведомление — чтобы снять его до того, как истечёт время. */
|
|
31
|
+
export interface NotificationHandle {
|
|
32
|
+
readonly id: string;
|
|
33
|
+
dismiss(): void;
|
|
34
|
+
}
|
|
35
|
+
/** Настройки одного уровня — всё, кроме самого уровня и сообщения. */
|
|
36
|
+
export type NotificationOptions = Omit<NotificationRequest, 'messageKey' | 'level'>;
|
|
37
|
+
export interface NotificationsService {
|
|
38
|
+
show(request: NotificationRequest): NotificationHandle;
|
|
39
|
+
info(messageKey: string, options?: NotificationOptions): NotificationHandle;
|
|
40
|
+
success(messageKey: string, options?: NotificationOptions): NotificationHandle;
|
|
41
|
+
warning(messageKey: string, options?: NotificationOptions): NotificationHandle;
|
|
42
|
+
error(messageKey: string, options?: NotificationOptions): NotificationHandle;
|
|
43
|
+
/**
|
|
44
|
+
* Очередь не показанных уведомлений в порядке поступления.
|
|
45
|
+
*
|
|
46
|
+
* Между изменениями возвращает **ту же** ссылку: снимок читает `useSyncExternalStore`,
|
|
47
|
+
* который на новом массиве при каждом вызове падает с «The result of getSnapshot should
|
|
48
|
+
* be cached».
|
|
49
|
+
*/
|
|
50
|
+
pending(): readonly Notification[];
|
|
51
|
+
/** Снимает уведомление из очереди. Неизвестный идентификатор — не ошибка. */
|
|
52
|
+
dismiss(id: string): void;
|
|
53
|
+
/** Очередь изменилась: добавили или сняли. */
|
|
54
|
+
observe(cb: () => void): Disposable;
|
|
55
|
+
}
|
|
56
|
+
export declare const NotificationsServiceToken: import('../index.js').ServiceToken<NotificationsService>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ключ настроек плагина каталога.
|
|
3
|
+
*
|
|
4
|
+
* Одна функция на всё приложение: адрес не должен разъехаться между тем, кто пишет настройку,
|
|
5
|
+
* и тем, кто рисует её форму. Сам вид службы настроек для плагина живёт в оболочке билдера.
|
|
6
|
+
*
|
|
7
|
+
* @module @reformer/builder-plugin-api/services/plugin-settings
|
|
8
|
+
*/
|
|
9
|
+
/** Ключ настроек плагина каталога. Одна функция на всё приложение: адрес не должен разъехаться. */
|
|
10
|
+
export declare function pluginSettingsKey(pluginId: string): string;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Capability } from '../primitives/capability.js';
|
|
2
|
+
/** Состояние строки каталога: найден-выключен, работает, не грузится. */
|
|
3
|
+
export type ManagedPluginState = 'disabled' | 'enabled' | 'failed';
|
|
4
|
+
/** Плагин каталога в объёме, нужном тому, кто им распоряжается. */
|
|
5
|
+
export interface ManagedPlugin {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly version?: string;
|
|
9
|
+
readonly state: ManagedPluginState;
|
|
10
|
+
/** Помечен «в разработке»: файлы наблюдаются, плагин перезагружается после правки. */
|
|
11
|
+
readonly dev: boolean;
|
|
12
|
+
/** Слой, из которого взят плагин: каталог проекта или установленное из npm. */
|
|
13
|
+
readonly layer?: 'project' | 'installed';
|
|
14
|
+
/** Почему `failed`. Текста достаточно: код разбора нужен спискам оболочки, а не отсюда. */
|
|
15
|
+
readonly problem?: {
|
|
16
|
+
readonly message: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface PluginsCatalogService {
|
|
20
|
+
/** Снимок списка. Живого списка здесь нет намеренно: подписка — дело того, кто рисует. */
|
|
21
|
+
list(): readonly ManagedPlugin[];
|
|
22
|
+
/** Загружает и активирует. Для упавшего это и есть «попробовать снова». */
|
|
23
|
+
enable(id: string): Promise<boolean>;
|
|
24
|
+
/** Снимает вклады, помнит решение человека. */
|
|
25
|
+
disable(id: string): void;
|
|
26
|
+
/** Снимает вклады, перечитывает файлы, поднимает заново. */
|
|
27
|
+
reload(id: string): Promise<boolean>;
|
|
28
|
+
/** Ставит или снимает пометку «в разработке». */
|
|
29
|
+
setDev(id: string, on: boolean): void;
|
|
30
|
+
/** Перечитывает каталог: так в списке появляется только что созданный плагин. */
|
|
31
|
+
refresh(): Promise<unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Ставит плагин из npm, спросив имя пакета у человека.
|
|
34
|
+
*
|
|
35
|
+
* Необязателен, и это названная деградация: сборка без установки (профиль без неё,
|
|
36
|
+
* окружение без OPFS) обязана работать, а тот, кто рисует список, — не показывать
|
|
37
|
+
* действие, которое ничего не сделает. Имя пакета спрашивает ОБОЛОЧКА: диалоги — её
|
|
38
|
+
* служба, и плагин не должен получать её ради одного поля ввода.
|
|
39
|
+
*/
|
|
40
|
+
install?(): Promise<void>;
|
|
41
|
+
/** Убирает установленный плагин целиком. Плагина из каталога проекта не касается. */
|
|
42
|
+
uninstall?(id: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Переключает установленный плагин на другую уже скачанную версию.
|
|
45
|
+
*
|
|
46
|
+
* Откат существует ради одного случая, зато обязательного: новая версия сломала работу.
|
|
47
|
+
* Прошлые версии остаются на диске, поэтому операция не ходит в сеть и работает без неё.
|
|
48
|
+
*/
|
|
49
|
+
rollback?(id: string): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Возможность «каталог плагинов». Привилегированная: право `plugins.manage`.
|
|
53
|
+
*
|
|
54
|
+
* Провайдер — оболочка. Версия `1.0.0` — исходная; растит её тот, кто меняет интерфейс.
|
|
55
|
+
*/
|
|
56
|
+
export declare const PluginsCatalogCapability: Capability<PluginsCatalogService>;
|
|
57
|
+
/** Токен службы — ТОТ ЖЕ объект: возможность расширяет токен, второго реестра нет. */
|
|
58
|
+
export declare const PluginsCatalogServiceToken: Capability<PluginsCatalogService>;
|