@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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +206 -0
  3. package/dist/index.d.ts +147 -0
  4. package/dist/index.js +76 -0
  5. package/dist/internal.d.ts +78 -0
  6. package/dist/internal.js +289 -0
  7. package/dist/permissions-BWlsUVPs.js +551 -0
  8. package/dist/plugin/bundled-modules.d.ts +25 -0
  9. package/dist/plugin/layout.d.ts +27 -0
  10. package/dist/plugin/manifest-parser.d.ts +54 -0
  11. package/dist/plugin/manifest.d.ts +320 -0
  12. package/dist/plugin/messages-bundle.d.ts +24 -0
  13. package/dist/plugin/permissions.d.ts +48 -0
  14. package/dist/plugin/plugin-exports.d.ts +10 -0
  15. package/dist/plugin/runtime-modules.d.ts +20 -0
  16. package/dist/plugin/storage.d.ts +70 -0
  17. package/dist/plugin/types.d.ts +136 -0
  18. package/dist/primitives/capability.d.ts +72 -0
  19. package/dist/primitives/command.d.ts +262 -0
  20. package/dist/primitives/disposable.d.ts +23 -0
  21. package/dist/primitives/event.d.ts +38 -0
  22. package/dist/primitives/extension-point.d.ts +53 -0
  23. package/dist/primitives/module-path.d.ts +21 -0
  24. package/dist/primitives/resource.d.ts +159 -0
  25. package/dist/primitives/semver.d.ts +93 -0
  26. package/dist/primitives/service.d.ts +68 -0
  27. package/dist/primitives/when-context.d.ts +69 -0
  28. package/dist/primitives/when-expr.d.ts +177 -0
  29. package/dist/resource-clipboard-Bdk_Is5N.js +381 -0
  30. package/dist/runtime-modules-CiUDFMIn.js +597 -0
  31. package/dist/services/context-keys.d.ts +52 -0
  32. package/dist/services/diagnostics/fixes.d.ts +40 -0
  33. package/dist/services/diagnostics/service.d.ts +34 -0
  34. package/dist/services/diagnostics/types.d.ts +148 -0
  35. package/dist/services/document-models.d.ts +20 -0
  36. package/dist/services/documents.d.ts +94 -0
  37. package/dist/services/host-messages.d.ts +10 -0
  38. package/dist/services/i18n.d.ts +43 -0
  39. package/dist/services/modules.d.ts +49 -0
  40. package/dist/services/notifications.d.ts +56 -0
  41. package/dist/services/plugin-settings.d.ts +10 -0
  42. package/dist/services/plugins-catalog.d.ts +58 -0
  43. package/dist/services/preview.d.ts +163 -0
  44. package/dist/services/prompt.d.ts +111 -0
  45. package/dist/services/resource-clipboard.d.ts +28 -0
  46. package/dist/services/selection.d.ts +46 -0
  47. package/dist/services/settings.d.ts +44 -0
  48. package/dist/services/theme.d.ts +15 -0
  49. package/dist/services/validation/types.d.ts +98 -0
  50. package/dist/services/workspace-files.d.ts +84 -0
  51. package/dist/services/workspace-resources.d.ts +41 -0
  52. package/dist/services/workspace-save.d.ts +18 -0
  53. package/dist/tooling.d.ts +28 -0
  54. package/dist/tooling.js +35 -0
  55. package/dist/ui/contributions/decorations.d.ts +55 -0
  56. package/dist/ui/contributions/editors.d.ts +58 -0
  57. package/dist/ui/contributions/plugin-settings.d.ts +54 -0
  58. package/dist/ui/keyboard/keybinding-rules.d.ts +48 -0
  59. package/dist/ui/keyboard/keybindings.d.ts +55 -0
  60. package/dist/ui/keyboard/keymap.d.ts +81 -0
  61. package/dist/ui/keyboard/scope.d.ts +38 -0
  62. package/dist/ui/menu/editor-menu.d.ts +25 -0
  63. package/dist/ui/menu/menu.d.ts +228 -0
  64. package/dist/ui/menu/palette.d.ts +36 -0
  65. package/dist/ui/menu/resource-menu.d.ts +45 -0
  66. package/dist/ui/slots.d.ts +113 -0
  67. package/dist/ui/useActiveDocument.d.ts +5 -0
  68. package/dist/ui/useLocale.d.ts +9 -0
  69. package/dist/ui/useTranslate.d.ts +4 -0
  70. package/dist/workspace/document.d.ts +42 -0
  71. package/dist/workspace/model/editor-view-states.d.ts +29 -0
  72. package/dist/workspace/model/model-document.d.ts +86 -0
  73. package/dist/workspace/model/provider.d.ts +140 -0
  74. package/dist/workspace/model/text-editor-focus.d.ts +22 -0
  75. package/dist/workspace/resource-names.d.ts +92 -0
  76. package/dist/workspace/write-options.d.ts +36 -0
  77. package/package.json +69 -0
@@ -0,0 +1,140 @@
1
+ import { Disposable } from '../../primitives/disposable.js';
2
+ import { ResourceRef } from '../../primitives/resource.js';
3
+ /**
4
+ * Адрес узла внутри модели.
5
+ *
6
+ * Для Host — непрозрачная строка. Домен выдаёт восемь символов base36 и кладёт их в `$nodeId`,
7
+ * но проверять это здесь означало бы, что платформа знает формат: следующий провайдер
8
+ * с другой схемой идентификаторов не смог бы существовать, ничего при этом не нарушив.
9
+ */
10
+ export type NodeId = string;
11
+ /**
12
+ * Проба содержимого — чтобы кандидаты читали ресурс ОДИН раз на всех.
13
+ *
14
+ * Форма совпадает с `EditorProbe` из вклада редактора (см. `plugin-and-shell.md`) намеренно:
15
+ * один и тот же объект передаётся и в `canOpen` редактора, и в {@link DocumentModelProvider.applies},
16
+ * а структурная совместимость держит их одним типом без общей зависимости.
17
+ */
18
+ export interface EditorProbe {
19
+ /** Текст ресурса; читается один раз и переиспользуется всеми кандидатами. */
20
+ text(): Promise<string>;
21
+ }
22
+ /**
23
+ * Описание правки модели.
24
+ *
25
+ * Сериализуемость обязательна: то же самое описание уходит в журнал операций (фундамент
26
+ * под совместную работу и под разбор хода ассистента), а значит в `params` не должно быть
27
+ * ни функций, ни ссылок на узлы модели — только данные.
28
+ */
29
+ export interface EditOp {
30
+ /** `'insert' | 'move' | 'set-prop' | …` — словарь принадлежит провайдеру, не ядру. */
31
+ readonly type: string;
32
+ readonly target?: NodeId;
33
+ readonly params?: Record<string, unknown>;
34
+ }
35
+ /** Результат применения операции к модели. */
36
+ export interface ApplyResult<M> {
37
+ readonly model: M;
38
+ /** Операция, отменяющая эту. Ядру нужна не для Ctrl+Z (там снимки), а для журнала. */
39
+ readonly inverse: EditOp;
40
+ /** Куда переехало выделение: узел мог сместиться или родиться. */
41
+ readonly focus?: NodeId;
42
+ }
43
+ /**
44
+ * Разбор, печать и правка одного формата.
45
+ *
46
+ * `parse`, `print` и `apply` — синхронные и чистые. Это не стилистика: на синхронности
47
+ * `apply` стоит гейт ассистента (ход проверяется до применения, а не после), а на чистоте —
48
+ * отмена через снимки: если бы `apply` мутировала модель, снимок перестал бы быть снимком.
49
+ *
50
+ * `apply` ОБЯЗАНА сохранять неизменённые поддеревья по ссылке. Разбор каждый раз даёт новый
51
+ * объект целиком, и именно поэтому документ с моделью не пересобирается из текста на каждое
52
+ * действие: structural sharing — то, на чём держится и отмена, и сравнение, и перерисовка.
53
+ */
54
+ export interface DocumentModelProvider<M> {
55
+ /** Уникален среди провайдеров; попадает в диагностику разбора. */
56
+ readonly id: string;
57
+ /**
58
+ * Берётся ли этот провайдер за такой ресурс.
59
+ *
60
+ * Решение по одному лишь расширению не годится: `.json` бывает и схемой формы, и конфигом
61
+ * пакета. Провайдеру, которому нужно содержимое, проба на пути открытия отдаёт его
62
+ * синхронно: оболочка кладёт туда уже прочитанный текст, и сузить тип можно `'peek' in probe`.
63
+ */
64
+ applies(ref: ResourceRef, probe: EditorProbe): boolean;
65
+ /** @throws если текст не разбирается — это НЕ авария, а состояние расхождения. */
66
+ parse(text: string): M;
67
+ print(model: M): string;
68
+ apply(model: M, op: EditOp): ApplyResult<M>;
69
+ /**
70
+ * Где в тексте лежит каждый узел модели: идентификатор узла → путь в дереве печати
71
+ * (ключи объектов и индексы массивов).
72
+ *
73
+ * Нужен текстовому редактору, чтобы подчеркнуть находку на узле, у которого в тексте нет
74
+ * своего идентификатора. Спрашивается у провайдера, а не выводится оболочкой: путь узла —
75
+ * знание о формате. Необязателен: без него такие находки остаются без места в тексте.
76
+ * Зовётся часто — на каждую публикацию находок, — поэтому ответ стоит запоминать по модели.
77
+ */
78
+ nodePaths?(model: M): ReadonlyMap<NodeId, readonly (string | number)[]>;
79
+ /**
80
+ * JSON Schema формата — для подсказок текстового редактора: имена ключей, допустимые
81
+ * значения, описания при наведении.
82
+ *
83
+ * Проверкой она НЕ служит: находки публикуют валидаторы в общий свод, и второй канал
84
+ * подчёркиваний от редактора был бы невидим платформе. `null` — подсказывать нечем
85
+ * (например, каталог, из которого схема строится, ещё не загружен).
86
+ *
87
+ * Необязателен. Зовётся на каждое открытие документа — ответ стоит запоминать.
88
+ */
89
+ jsonSchema?(): JsonSchemaHint | null;
90
+ /** Схема из {@link jsonSchema} устарела — её надо спросить заново. */
91
+ onDidChangeJsonSchema?(cb: () => void): Disposable;
92
+ /**
93
+ * Подсказки в строковом значении под курсором — то, чего JSON Schema выразить не может,
94
+ * потому что зависит от содержимого документа (пути модели, имена из самого файла).
95
+ *
96
+ * `model` — последняя разобранная модель: пока человек печатает, текст бывает неразборчив,
97
+ * а подсказка нужна именно тогда. Пустой список — «здесь подсказывать нечего».
98
+ */
99
+ completeString?(model: M, site: TextStringSite): readonly TextCompletion[];
100
+ }
101
+ /** JSON Schema, которой провайдер описывает свой формат. */
102
+ export interface JsonSchemaHint {
103
+ /**
104
+ * Идентификатор схемы. Стабилен, пока схема та же: по нему редактор решает,
105
+ * перерегистрировать её или нет.
106
+ */
107
+ readonly uri: string;
108
+ readonly schema: unknown;
109
+ }
110
+ /** Строковое значение в тексте документа, внутри которого стоит курсор. */
111
+ export interface TextStringSite {
112
+ /** Путь значения в дереве печати — ключи объектов и индексы массивов. */
113
+ readonly path: readonly (string | number)[];
114
+ /** Содержимое строки без кавычек, как оно записано в тексте (экранирование не снято). */
115
+ readonly value: string;
116
+ /** Позиция курсора внутри {@link value}. */
117
+ readonly offset: number;
118
+ }
119
+ /** Одна подсказка в строковом значении. */
120
+ export interface TextCompletion {
121
+ /** Что показать в списке. */
122
+ readonly label: string;
123
+ /** Пояснение справа от метки. */
124
+ readonly detail?: string;
125
+ /** Что вставить вместо {@link replace}. */
126
+ readonly insert: string;
127
+ /** Заменяемый участок ВНУТРИ `site.value`: полуинтервал `[start, end)`. */
128
+ readonly replace: {
129
+ readonly start: number;
130
+ readonly end: number;
131
+ };
132
+ }
133
+ /**
134
+ * Точка расширения провайдеров модели.
135
+ *
136
+ * Тип вклада — `DocumentModelProvider<unknown>`: ядро не параметризуется моделью, потому что
137
+ * держит их разом несколько и ни об одной ничего не знает. Типизированный доступ появляется
138
+ * там, где провайдер известен, — у самого плагина.
139
+ */
140
+ export declare const DocumentModelPoint: import('../../internal.js').ExtensionPoint<DocumentModelProvider<unknown>>;
@@ -0,0 +1,22 @@
1
+ import { ResourceId } from '../../primitives/resource.js';
2
+ import { Capability } from '../../primitives/capability.js';
3
+ export interface TextEditorFocusRegistry {
4
+ /** В фокусе ли текстовый редактор этого документа. */
5
+ isFocused(id: ResourceId): boolean;
6
+ /** Сообщает о смене фокуса. `false` снимает запись, а не хранит её: пустая карта дешевле. */
7
+ setFocused(id: ResourceId, focused: boolean): void;
8
+ /** Есть ли фокус хоть где-нибудь. Нужно диагностике и тестам. */
9
+ hasFocus(): boolean;
10
+ }
11
+ /**
12
+ * Возможность «кто сейчас печатает»: токен службы плюс версия контракта.
13
+ *
14
+ * Провайдер — оболочка (`services/host-capabilities`), а не редактор, и это то же решение,
15
+ * что у самого реестра: писать в него обязан КАЖДЫЙ текстовый редактор, поэтому принадлежать
16
+ * он не может ни одному. Регистрируется до активации плагинов, поэтому редактор вправе взять
17
+ * его `require` прямо в `activate` — правило «сервис ищется в момент использования»
18
+ * (`plugin/types.ts`) касается сервисов ЧУЖИХ плагинов, а не платформы.
19
+ */
20
+ export declare const TextEditorFocusCapability: Capability<TextEditorFocusRegistry>;
21
+ /** Токен службы — ТОТ ЖЕ объект: возможность расширяет токен, второго реестра нет. */
22
+ export declare const TextEditorFocusToken: Capability<TextEditorFocusRegistry>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Правила имён и целевых путей для операций над ресурсами — всё, что проверяется без источника.
3
+ *
4
+ * Отделено от исполнения (`resource-ops` оболочки билдера — правила уехали в пакет контракта,
5
+ * исполнение осталось там, где есть источник) по той же причине, по которой
6
+ * правила дерева отделены от его отрисовки: имя, которое браузер не примет, и каталог,
7
+ * вставляемый в самого себя, — это ошибки РЕШЕНИЯ, а не ввода-вывода, и проверять их
8
+ * обращением к файловой системе значило бы узнавать о них последними.
9
+ *
10
+ * ## Почему подбор уникального имени берёт готовый список
11
+ *
12
+ * В v1 `uniqueName` (`io/fs-ops.ts:275-285`) спрашивал файловую систему до тысячи раз подряд,
13
+ * причём каждая проверка стоила ДВУХ обращений (`existsIn` пробовал имя сначала как файл,
14
+ * потом как каталог). На локальном диске это незаметно, по сети — минуты. Здесь имя
15
+ * подбирается ПО СПИСКУ уровня, который вызывающий и так прочитал одним `list`, поэтому
16
+ * цена подбора — ноль обращений, и правило проверяется без файловой системы вовсе.
17
+ *
18
+ * @module shell/platform/workspace/resource-names
19
+ */
20
+ /**
21
+ * Почему имя не годится. Код, а не фраза: по коду интерфейс строит текст на своём языке,
22
+ * а тест сравнивает решение, а не перевод.
23
+ */
24
+ export type NameRejection =
25
+ /** Пустое имя или одни пробелы. */
26
+ 'empty'
27
+ /** Разделитель пути внутри имени: создаём ОДНУ запись, а не дерево. */
28
+ | 'separator'
29
+ /** `.` или `..` — переход по дереву, а не имя. */
30
+ | 'dots'
31
+ /** Символ, запрещённый файловыми системами (`\ / : * ? " < > |`) или управляющий. */
32
+ | 'forbidden-character'
33
+ /** Имя, зарезервированное Windows (`CON`, `PRN`, `NUL`, `COM1`…). */
34
+ | 'reserved'
35
+ /** Точка или пробел в конце: Windows молча их срежет, и имя окажется не тем. */
36
+ | 'trailing'
37
+ /** Длиннее предела одного сегмента пути. */
38
+ | 'too-long';
39
+ /**
40
+ * Предел длины сегмента.
41
+ *
42
+ * 255 — общий знаменатель ext4, APFS и NTFS. Ограничение проверяется по кодовым единицам
43
+ * UTF-16, а не по байтам: точная байтовая длина зависит от кодировки файловой системы,
44
+ * а завышенный запас здесь безопаснее заниженного.
45
+ */
46
+ export declare const MAX_NAME_LENGTH = 255;
47
+ /**
48
+ * Проверяет имя одной записи. `null` — имя годится.
49
+ *
50
+ * Проверка идёт по правилам САМОЙ СТРОГОЙ из целевых систем, а не текущей: проект,
51
+ * созданный в Linux, открывают в Windows, и имя `aux.ts` там не создастся вовсе. Отказать
52
+ * при вводе честнее, чем отдать проект, который у соседа не разворачивается.
53
+ */
54
+ export declare function validateResourceName(name: string): NameRejection | null;
55
+ /**
56
+ * Делит имя на основу и расширение так, как этого ждёт человек, разводящий копии.
57
+ *
58
+ * Точка ищется ПОСЛЕДНЯЯ, а не первая: у `schema.form.json` расширением человек считает
59
+ * `.json`, и копия обязана называться `schema.form-2.json`, а не `schema-2.form.json`
60
+ * (v1 брала первую точку и делала именно второе). Ведущая точка расширением не считается:
61
+ * `.gitignore` — это имя целиком, и `-2.gitignore` было бы другим файлом.
62
+ */
63
+ export declare function splitName(name: string): {
64
+ readonly stem: string;
65
+ readonly ext: string;
66
+ };
67
+ /**
68
+ * Свободное имя в уровне: `name`, иначе `name-2`, `name-3`…
69
+ *
70
+ * `taken` — имена, уже занятые в каталоге (обычно результат одного `list`). Сравнение
71
+ * без учёта регистра: на APFS и NTFS `Schema.json` и `schema.json` — одна запись, и копия,
72
+ * различающаяся только регистром, затёрла бы оригинал на половине машин команды.
73
+ *
74
+ * Предел подбора — {@link MAX_UNIQUE_ATTEMPTS}; дальше к основе приписывается переданный
75
+ * `salt`. Соль параметром, а не `Date.now()` внутри: правило обязано быть проверяемым,
76
+ * а функция, чей ответ зависит от часов, проверяется только приблизительно.
77
+ */
78
+ export declare function uniqueName(taken: Iterable<string>, name: string, salt?: string): string;
79
+ /**
80
+ * Сколько номеров перебирается, прежде чем имя разводится солью.
81
+ *
82
+ * Тысяча копий одного файла в одном каталоге — это не работа, а авария, и продолжать
83
+ * перебор дальше означало бы её маскировать.
84
+ */
85
+ export declare const MAX_UNIQUE_ATTEMPTS = 999;
86
+ /**
87
+ * Лежит ли путь внутри каталога (или является им самим) — по строкам, без обращения к источнику.
88
+ *
89
+ * Нужна ровно одному правилу, зато несущему: каталог нельзя скопировать или перенести
90
+ * внутрь самого себя, иначе обход не завершится вовсе.
91
+ */
92
+ export declare function isInside(path: string, dir: string): boolean;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Пометка правки: кто правит и в каком логическом шаге.
3
+ *
4
+ * Прав она не даёт и ничего не разрешает — она ПОДПИСЫВАЕТ. Запись идёт в рабочую копию
5
+ * одной дверью, у человека и у ассистента одинаковой, а различие между ними живёт в журнале:
6
+ * половина ценности аудита в том, что правку человека и правку машины видно порознь.
7
+ *
8
+ * @module @reformer/builder-plugin-api/workspace/write-options
9
+ */
10
+ /**
11
+ * Кто породил правку.
12
+ *
13
+ * Различие несущее: половина ценности аудита в том, что правку человека и правку машины
14
+ * видно порознь. Поэтому же записи с разным происхождением никогда не схлопываются.
15
+ */
16
+ export type JournalOrigin = 'user' | 'agent' | 'external';
17
+ export interface WriteOptions {
18
+ /**
19
+ * Кто правит. По умолчанию `'user'`: `writeText` без пометки зовут от имени человека,
20
+ * и в этом случае догадка верна.
21
+ *
22
+ * Словарь — целиком журнальный ({@link JournalOrigin}), а не сокращённый до «человек или
23
+ * машина»: рабочая область здесь ПЕРЕДАТОЧНОЕ звено, и сужать чужой словарь по дороге
24
+ * значило бы завести второй, который разъедется с первым.
25
+ */
26
+ readonly origin?: JournalOrigin;
27
+ /**
28
+ * Логический шаг, которому принадлежит правка: ход ассистента, мультикурсорная правка.
29
+ *
30
+ * Нужен для `Journal.undoTransaction` — отката шага целиком. Ход, приземлившийся ДВУМЯ
31
+ * записями (например, ход со второй попыткой), отменяется одним действием только если обе
32
+ * записи названы одним `txId`; без него отменять пришлось бы по одной, и промежуточное
33
+ * состояние формы человек увидел бы как результат.
34
+ */
35
+ readonly txId?: string;
36
+ }
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@reformer/builder-plugin-api",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "Public API surface for ReFormer Builder plugins: contracts, extension points and service tokens",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./tooling": {
15
+ "types": "./dist/tooling.d.ts",
16
+ "import": "./dist/tooling.js"
17
+ },
18
+ "./internal": {
19
+ "types": "./dist/internal.d.ts",
20
+ "import": "./dist/internal.js"
21
+ }
22
+ },
23
+ "sideEffects": false,
24
+ "scripts": {
25
+ "build": "vite build",
26
+ "build:stackblitz": "vite build",
27
+ "test": "node ../../scripts/run-vitest.mjs"
28
+ },
29
+ "keywords": [
30
+ "reformer",
31
+ "builder",
32
+ "plugin",
33
+ "plugin-api",
34
+ "typescript"
35
+ ],
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "author": "Alexandr Bukhtatyy",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/AlexandrBukhtatyy/ReFormer.git",
44
+ "directory": "packages/reformer-builder-plugin-api"
45
+ },
46
+ "homepage": "https://alexandrbukhtatyy.github.io/ReFormer/",
47
+ "bugs": {
48
+ "url": "https://github.com/AlexandrBukhtatyy/ReFormer/issues"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "files": [
54
+ "dist",
55
+ "README.md",
56
+ "LICENSE"
57
+ ],
58
+ "peerDependencies": {
59
+ "react": "^18.0.0 || ^19.0.0"
60
+ },
61
+ "devDependencies": {
62
+ "@types/node": "^24.10.1",
63
+ "typescript": "^5.9.3",
64
+ "vite": "^7.2.2",
65
+ "vite-plugin-dts": "^4.5.4",
66
+ "vitest": "^4.0.8",
67
+ "@types/react": "^19.2.7"
68
+ }
69
+ }