@reformer/builder 3.0.0-beta.7 → 3.0.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/bin/reformer-builder.mjs +1 -1
  2. package/dist/assets/css/index-CHjtwIsF.css +1 -0
  3. package/dist/assets/i18n/en-uNov8AYL.js +1 -0
  4. package/dist/assets/i18n/ru-BNkTKaU6.js +1 -0
  5. package/dist/assets/js/index-C4LjLCAZ.js +57 -0
  6. package/dist/assets/monaco/html-DT-eqvPn.js +1 -0
  7. package/dist/assets/monaco/javascript-CIJHG94Q.js +1 -0
  8. package/dist/assets/monaco/{jsonMode-C3DAkvde.js → jsonMode-rEmNPnut.js} +3 -3
  9. package/dist/assets/monaco/{monaco-runtime-DNdOZY7f.js → monaco-runtime-Dqtu7Dpv.js} +137 -137
  10. package/dist/assets/monaco/typescript-Bp6doald.js +1 -0
  11. package/dist/assets/monaco/xml-D8D5UF1F.js +1 -0
  12. package/dist/assets/monaco/yaml-DsiyZy1w.js +1 -0
  13. package/dist/assets/plugins/{ai-jKAVkXuU.js → ai-CFoGZBd-.js} +36 -36
  14. package/dist/assets/plugins/{ai-byok-DgeZQTZb.js → ai-byok-a7JlkizL.js} +1 -1
  15. package/dist/assets/plugins/ai-knowledge-docs-BcbN7Ar1.js +1 -0
  16. package/dist/assets/plugins/ai-knowledge-index-CncxmxEf.js +1 -0
  17. package/dist/assets/plugins/codegen-DPh2ynzq.js +520 -0
  18. package/dist/assets/plugins/{editor-markdown-MarkdownPreview-DyHZvj8H.js → editor-markdown-MarkdownPreview-CjVpNIV5.js} +3 -3
  19. package/dist/assets/plugins/editor-markdown-McTrLzET.js +2 -0
  20. package/dist/assets/plugins/editor-monaco-7BM478IS.js +14 -0
  21. package/dist/assets/plugins/editor-schema-DOoRcy16.js +4 -0
  22. package/dist/assets/plugins/files-WhQya3nC.js +2 -0
  23. package/dist/assets/plugins/plain-4ISpXJVh.js +78 -0
  24. package/dist/assets/plugins/plugin-manager-Ek0Ph0Jj.js +1 -0
  25. package/dist/assets/plugins/preview-BSh_puVw.js +1 -0
  26. package/dist/assets/plugins/preview-runtime-B8NzDg53.js +3 -0
  27. package/dist/assets/plugins/templates-BE9B0S3J.js +2 -0
  28. package/dist/assets/vendor/{ajv-CCplthOF.js → ajv-N5zGp_lm.js} +1 -1
  29. package/dist/assets/vendor/calendar-base-BW48REpD-BYc4qqRC.js +1 -0
  30. package/dist/assets/vendor/carousel-BDyy29mt.js +1 -0
  31. package/dist/assets/vendor/chart-Cbp9J5YJ.js +52 -0
  32. package/dist/assets/vendor/collapsible-base-DZxAKbAF-DtQ4867U.js +1 -0
  33. package/dist/assets/vendor/drawer-BdLrIIeu.js +3 -0
  34. package/dist/assets/vendor/highlight.js/{common-g0-hl6Ud.js → common-B96EybDa.js} +1 -1
  35. package/dist/assets/vendor/index-BTAoX623.js +6 -0
  36. package/dist/assets/vendor/index-D8ACoUqy.js +51 -0
  37. package/dist/assets/vendor/input-otp-BoPlZ6dt.js +20 -0
  38. package/dist/assets/vendor/lucide-react/arrow-left-BlVPt6Ag.js +1 -0
  39. package/dist/assets/vendor/lucide-react/arrow-right-I5ntlq0-.js +1 -0
  40. package/dist/assets/vendor/lucide-react/calendar-L-57WZlQ.js +1 -0
  41. package/dist/assets/vendor/lucide-react/eye-DVTIIHcH.js +1 -0
  42. package/dist/assets/vendor/lucide-react/file-code-corner-DUfMS_yi.js +1 -0
  43. package/dist/assets/vendor/lucide-react/folder-tree-COyCkaDl.js +1 -0
  44. package/dist/assets/vendor/lucide-react/minus-zJRYKuAo.js +1 -0
  45. package/dist/assets/vendor/lucide-react/plus-B0WG2JcM.js +1 -0
  46. package/dist/assets/vendor/lucide-react/rotate-ccw-BSYk0mux.js +1 -0
  47. package/dist/assets/vendor/lucide-react/wrench-mybFdWHD.js +1 -0
  48. package/dist/assets/vendor/message-base-B5jT1FuY-BvDKjuSs.js +1 -0
  49. package/dist/assets/vendor/message-scroller-B2tlOtxT.js +1 -0
  50. package/dist/assets/vendor/reformer-builder-stack-reformer/node-token-VfZdCqcs.js +1 -0
  51. package/dist/assets/vendor/reformer-builder-stack-reformer/paths-DeGLVPUt.js +1 -0
  52. package/dist/assets/{js/rules-CM1OzesO.js → vendor/reformer-builder-stack-reformer/rules-CQSVDlmo.js} +1 -1
  53. package/dist/assets/vendor/reformer-builder-stack-reformer/selectors-CjNSFsK9.js +1 -0
  54. package/dist/assets/vendor/reformer-builder-toolkit/marker-DiOaKX-e.js +4 -0
  55. package/dist/assets/vendor/reformer-cdk/define-steps-CyGUrx9p-vcI1WbRz.js +1 -0
  56. package/dist/assets/vendor/reformer-cdk/file-upload-D8FOieMN.js +1 -0
  57. package/dist/assets/vendor/reformer-cdk/form-array-DlFEb40E.js +1 -0
  58. package/dist/assets/vendor/reformer-cdk/form-wizard-DDLs_-Ya.js +1 -0
  59. package/dist/assets/vendor/reformer-cdk/index-CeCSv2Go.js +1 -0
  60. package/dist/assets/vendor/reformer-cdk/{list-BrqYwhrQ.js → list-DkqJWU70.js} +1 -1
  61. package/dist/assets/vendor/reformer-form-registry/{index-s1IAa6Lm.js → index-DflpiFcm.js} +1 -1
  62. package/dist/assets/vendor/reformer-form-registry/loader-BK2c_fCA-BtIEWzon.js +2 -0
  63. package/dist/assets/vendor/reformer-form-registry/react-BiEQRau3.js +1 -0
  64. package/dist/assets/vendor/reformer-renderer-json/{validate-C5Gll2Yt.js → validate-DXzHWMfT.js} +1 -1
  65. package/dist/assets/vendor/reformer-ui-kit/alert-base-WOl_V-qI-2ZIfaT1o.js +1 -0
  66. package/dist/assets/vendor/reformer-ui-kit/calendar-Bm2DDJDU.js +1 -0
  67. package/dist/assets/vendor/reformer-ui-kit/calendar-base.props-CqesU7CZ-tpDaVQbq.js +1 -0
  68. package/dist/assets/vendor/reformer-ui-kit/combobox-Dm4bFCVg.js +1 -0
  69. package/dist/assets/vendor/reformer-ui-kit/combobox-tree.props-BEQhnapq-DQmsBcYk.js +1 -0
  70. package/dist/assets/vendor/reformer-ui-kit/component-catalog-BEv0Zf-R.js +1 -0
  71. package/dist/assets/vendor/reformer-ui-kit/date-picker-CkVXt6Uh.js +1 -0
  72. package/dist/assets/vendor/reformer-ui-kit/date-picker-base.props-WBloFrDq-QhVYMCMG.js +1 -0
  73. package/dist/assets/vendor/reformer-ui-kit/input-otp-base.props-D1xRJiuO-DBKxHsz1.js +1 -0
  74. package/dist/assets/vendor/reformer-ui-kit/meta-YyKXxsBK.js +1 -0
  75. package/dist/assets/vendor/reformer-ui-kit/sidebar-CMzt3bAb.js +1 -0
  76. package/dist/assets/vendor/reformer-ui-kit/skeleton-base-C-lIzi0D-BjmjAmE9.js +1 -0
  77. package/dist/assets/vendor/reformer-ui-kit/toggle-group-multi.props-7kNpujN6-jLENMOcN.js +1 -0
  78. package/dist/assets/vendor/reformer-ui-kit/tree-node-schema-xHyN0QCr-CLbM_Aw_.js +1 -0
  79. package/dist/assets/vendor/render-DutGx1TC.js +46 -0
  80. package/dist/assets/vendor/sheet-base-Bdh947IC-CH2UsjIt.js +1 -0
  81. package/dist/assets/vendor/typescript/{typescript-Dp5hP5cS.js → typescript-BejA4q8A.js} +1 -1
  82. package/dist/index.html +2 -2
  83. package/package.json +6 -2
  84. package/runtime-config.schema.json +23 -1
  85. package/dist/assets/css/index-DgRudQqc.css +0 -1
  86. package/dist/assets/i18n/en-DHElWsPO.js +0 -1
  87. package/dist/assets/i18n/ru-DXsuKRv9.js +0 -1
  88. package/dist/assets/js/index-BSeq6-8S.js +0 -67
  89. package/dist/assets/js/index-CQvmAVe0.js +0 -115
  90. package/dist/assets/js/selectors-BiPlGN2c.js +0 -1
  91. package/dist/assets/monaco/html-R9lQ-L9C.js +0 -1
  92. package/dist/assets/monaco/javascript-COUjr2au.js +0 -1
  93. package/dist/assets/monaco/typescript-CVSiBX9O.js +0 -1
  94. package/dist/assets/monaco/xml-ee1lph4p.js +0 -1
  95. package/dist/assets/monaco/yaml-DXPc9WLc.js +0 -1
  96. package/dist/assets/plugins/ai-knowledge-docs-DCjqodcj.js +0 -1
  97. package/dist/assets/plugins/ai-knowledge-index-bUfNPqlZ.js +0 -1
  98. package/dist/assets/plugins/codegen-B0riFOHC.js +0 -416
  99. package/dist/assets/plugins/editor-markdown-oiBrRpM4.js +0 -2
  100. package/dist/assets/plugins/editor-schema-CVPAk-MV.js +0 -4
  101. package/dist/assets/plugins/plugin-manager-BmjjSqYy.js +0 -1
  102. package/dist/assets/plugins/templates-DNeIl0cD.js +0 -2
  103. package/dist/assets/vendor/collapsible-base-DZxAKbAF-h07cIL_F.js +0 -1
  104. package/dist/assets/vendor/index-jGqhTST4.js +0 -6
  105. package/dist/assets/vendor/lucide-react/eye-COs0olKf.js +0 -1
  106. package/dist/assets/vendor/lucide-react/file-code-corner-BMVX-Qf1.js +0 -1
  107. package/dist/assets/vendor/lucide-react/rotate-ccw-D0mVnqJN.js +0 -1
  108. package/dist/assets/vendor/lucide-react/wrench-BX6KiYsu.js +0 -1
  109. package/dist/assets/vendor/message-base-B5jT1FuY-GU8TkaN4.js +0 -1
  110. package/dist/assets/vendor/reformer-cdk/async-boundary-DPu-1Ifi.js +0 -1
  111. package/dist/assets/vendor/reformer-cdk/define-steps-CyGUrx9p-B_03D9I7.js +0 -1
  112. package/dist/assets/vendor/reformer-cdk/file-upload-C_DEa-OT.js +0 -1
  113. package/dist/assets/vendor/reformer-cdk/form-array-DRkRfAUh.js +0 -1
  114. package/dist/assets/vendor/reformer-cdk/form-wizard-DFqFjH7E.js +0 -1
  115. package/dist/assets/vendor/reformer-cdk/index-BXFomK5m.js +0 -1
  116. package/dist/assets/vendor/reformer-form-registry/loader-BK2c_fCA-D59m3JOQ.js +0 -2
  117. package/dist/assets/vendor/reformer-form-registry/react-B8lbN6s4.js +0 -1
  118. package/dist/assets/vendor/reformer-ui-kit/alert-base-WOl_V-qI-CYoSap05.js +0 -1
  119. package/dist/assets/vendor/reformer-ui-kit/component-catalog-BKjWf5Yx.js +0 -1
  120. /package/dist/assets/{js → vendor/reformer-builder-toolkit}/naming-9aaM0Wbc.js +0 -0
@@ -0,0 +1,520 @@
1
+ import{cv as F,dg as de,bJ as K,bK as V,bI as B,cx as ce,cw as y,cg as W,cp as me,c5 as pe,cB as ue,cC as fe,cb as he,Y as x,Z as d,cI as ge,aS as ye,aw as M,aX as ve,bR as be,bT as xe,bU as we,bV as Ne,aK as A,bz as ke,c3 as Se,c7 as Te,cV as je}from"../js/index-C4LjLCAZ.js";import{i as J,a as Re,w as q}from"../vendor/reformer-builder-toolkit/marker-DiOaKX-e.js";import{p as Ee,w as Oe,a as Fe,b as G,c as Ce,e as Ie,d as Pe}from"../vendor/index-D8ACoUqy.js";import{a as Me,r as U}from"../vendor/render-DutGx1TC.js";import{a as ze}from"../vendor/reformer-builder-stack-reformer/paths-DeGLVPUt.js";import{o as L,u as X}from"../vendor/reformer-ui-kit/alert-base-WOl_V-qI-2ZIfaT1o.js";import{F as Ae}from"../vendor/lucide-react/file-code-corner-DUfMS_yi.js";import"../vendor/reformer-builder-stack-reformer/rules-CQSVDlmo.js";import"../vendor/reformer-builder-toolkit/naming-9aaM0Wbc.js";class S extends Error{constructor(){super("источник не принимает запись"),this.name="SourceReadOnlyError"}}async function $e(e,t,r,n){return H(e,e.resolve(t,r),n)}async function H(e,t,r){const n=e.sourceOf(t);if(n===null||!n.write)throw new S;const i=[],o=[],a=[],l=[];for(const s of r){const u=e.resolve(t,...s.path.split("/"));try{if(s.cls==="user"&&await e.exists(u)){if(!s.regenerable){o.push({path:s.path,reason:"authored"});continue}const f=await e.readText(u);if(!J(f)){o.push({path:s.path,reason:"edited"});continue}}await e.writeText(u,s.content),i.push(s.path),l.push(u)}catch(f){a.push({path:s.path,message:f instanceof Error?f.message:String(f)})}}const c=e.save===void 0||l.length===0?null:await e.save(l);return{dir:t,written:i,skipped:o,failed:a,saved:c}}const _e="./form-schema.schema.json";function De(e){const{$schema:t,version:r,...n}=e.schema,i={$schema:t??_e,version:r??"1.0",...n};return`${JSON.stringify(i,null,2)}
2
+ `}const Ke=`// api.ts — заготовка бэкенда (submit). Реализуйте реальные запросы. Пишется один раз.
3
+
4
+ import type { <%= it.names.TypeName %> } from './types';
5
+
6
+ export type ApiResult<T> = { success: true; data: T } | { success: false; error: string };
7
+
8
+ const API_DELAY = 600;
9
+
10
+ function wait(ms: number): Promise<void> {
11
+ return new Promise((resolve) => setTimeout(resolve, ms));
12
+ }
13
+
14
+ /** POST — отправка формы. TODO: заменить на реальный запрос. */
15
+ export async function submitForm(values: <%= it.names.TypeName %>): Promise<ApiResult<{ id: string }>> {
16
+ await wait(API_DELAY);
17
+ // eslint-disable-next-line no-console
18
+ console.info('[<%= it.names.dir %>] submit', values);
19
+ return { success: true, data: { id: String(Date.now()) } };
20
+ }
21
+ `,Ve=`// data-sources.ts — значения $dataSource. МОК: опции из синтеза, замените реальными.
22
+ // Пишется один раз и при регенерации не затирается.
23
+
24
+ <% if (it.dataSources.options.length > 0) { -%>
25
+ import type { SelectOption } from './types';
26
+
27
+ <% } -%>
28
+ <%~ it.blocks([
29
+ it.dataSources.options
30
+ .map((d) => \`export const \${d.name}: SelectOption[] = \${it.json(d.value)};\`)
31
+ .join('\\n\\n'),
32
+ it.dataSources.scalars.map((d) => \`export const \${d.name} = \${d.literal};\`).join('\\n'),
33
+ it.dataSources.labels
34
+ .map((name) => \`export const \${name} = (_item: unknown, index: number): string =>\\n '#' + (index + 1); // TODO: подпись элемента\`)
35
+ .join('\\n'),
36
+ ]) %>
37
+ `,Be=`// model.ts — начальные значения (из мока) и фабрика модели. Регенерируется.
38
+
39
+ import { createModel, type FormModel } from '@reformer/core';
40
+ import type { <%= it.names.TypeName %> } from './types';
41
+
42
+ export function createInitialValues(): <%= it.names.TypeName %> {
43
+ return <%= it.json(it.mock.model, 2) %> as <%= it.names.TypeName %>;
44
+ }
45
+
46
+ export function <%= it.names.modelFactory %>(
47
+ initial?: Partial<<%= it.names.TypeName %>>
48
+ ): FormModel<<%= it.names.TypeName %>> {
49
+ return createModel<<%= it.names.TypeName %>>({ ...createInitialValues(), ...initial });
50
+ }
51
+ `,We=`// index.tsx — сборка формы одним проходом: createJsonForm → JsonFormRenderer (проп form).
52
+ // Здесь же запись реестра форм. Регенерируется билдером; правки будут перезаписаны.
53
+
54
+ import { useState } from 'react';
55
+ import type { FormEntry } from '@reformer/form-registry';
56
+ import {
57
+ JsonFormRenderer,
58
+ JsonRendererProvider,
59
+ createJsonForm,
60
+ useJsonForm,
61
+ type JsonFormSchema,
62
+ } from '@reformer/renderer-json';
63
+ import rawSchema from './renderer.schema.json';
64
+ import { createRegistry } from './registry';
65
+ import { <%= it.names.modelFactory %> } from './model';
66
+ import { formBehavior } from './form.behavior';
67
+ import { createJsonRenderBehavior } from './renderer.behavior';
68
+ import type { <%= it.names.TypeName %> } from './types';
69
+
70
+ type SubmitResult = { message: string; ok: boolean };
71
+
72
+ // В чистом JSON операторы типизируются как \`string\` — приведение к схеме модели формы.
73
+ const typedSchema = rawSchema as unknown as JsonFormSchema<<%= it.names.TypeName %>>;
74
+
75
+ export default function <%= it.names.pageComponent %>() {
76
+ const [result, setResult] = useState<SubmitResult | null>(null);
77
+
78
+ // Сборка ОДНИМ вызовом: model + form + registry + behavior + render-behavior из одной схемы.
79
+ // useJsonForm (ленивый useState) зовёт фабрику ровно один раз, поэтому ссылка на поведение
80
+ // стабильна, а колбэк хоста (onResult) безопасно замыкается прямо здесь.
81
+ const jsonForm = useJsonForm(() =>
82
+ createJsonForm<<%= it.names.TypeName %>>({
83
+ schema: typedSchema,
84
+ registry: createRegistry(),
85
+ model: <%= it.names.modelFactory %>(),
86
+ behavior: formBehavior,
87
+ renderBehavior: (form, model) =>
88
+ createJsonRenderBehavior(form, model, {
89
+ onResult: (message, ok) => setResult({ message, ok }),
90
+ }),
91
+ })
92
+ );
93
+
94
+ return (
95
+ <div className="mx-auto max-w-3xl p-6">
96
+ <header className="mb-6">
97
+ <h1 className="text-2xl font-bold"><%= it.names.title %></h1>
98
+ </header>
99
+
100
+ {result && (
101
+ <div
102
+ role="status"
103
+ data-testid="submit-result"
104
+ className={
105
+ 'mb-4 rounded-md border p-3 text-sm ' +
106
+ (result.ok
107
+ ? 'border-green-300 bg-green-50 text-green-800'
108
+ : 'border-red-300 bg-red-50 text-red-800')
109
+ }
110
+ >
111
+ {result.message}
112
+ </div>
113
+ )}
114
+
115
+ <JsonRendererProvider settings={{ registry: jsonForm.registry }}>
116
+ <JsonFormRenderer<<%= it.names.TypeName %>> form={jsonForm} validateSchema={import.meta.env.DEV} />
117
+ </JsonRendererProvider>
118
+ </div>
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Запись формы «<%= it.names.title %>» в реестре форм.
124
+ *
125
+ * Регистрация в приложении — одна строка:
126
+ * \`\`\`ts
127
+ * import { getFormRegistry } from '@reformer/form-registry';
128
+ * import { <%= it.names.entryConst %> } from './pages/demo/<%= it.names.dir %>';
129
+ *
130
+ * getFormRegistry().register(<%= it.names.entryConst %>);
131
+ * \`\`\`
132
+ *
133
+ * После этого форма монтируется где угодно: \`<FormOutlet id="<%= it.names.exampleId %>" />\`, либо через
134
+ * слот или маршрут, если заполнить \`placement\`.
135
+ */
136
+ export const <%= it.names.entryConst %>: FormEntry<<%= it.names.TypeName %>> = {
137
+ id: '<%= it.names.exampleId %>',
138
+ version: '1.0.0',
139
+ // Кто зарегистрировал: по этому полю различаются одинаковые id из разных микрофронтов.
140
+ owner: 'app', // TODO: имя вашего приложения-хоста
141
+
142
+ // Данные — единственная часть, которую можно доставить по сети.
143
+ schema: { kind: 'inline', value: typedSchema },
144
+
145
+ // Код — только из бандла.
146
+ registry: { kind: 'inline', value: createRegistry() },
147
+ model: { kind: 'inline', value: <%= it.names.modelFactory %> },
148
+ behavior: { kind: 'inline', value: formBehavior },
149
+ // Адаптер, а не прямая ссылка: у \`createJsonRenderBehavior\` третий параметр — настройки места
150
+ // (\`{ onResult }\`), а реестр третьим отдаёт правила валидации и только четвёртым — настройки
151
+ // хоста. Без переходника это не компилируется, а \`onResult\` не доезжает никогда.
152
+ renderBehavior: {
153
+ kind: 'inline',
154
+ value: (form, model, _validation, options) =>
155
+ createJsonRenderBehavior(
156
+ form,
157
+ model,
158
+ options as { onResult?: (m: string, ok: boolean) => void }
159
+ ),
160
+ },
161
+
162
+ // Где показывать. Пусто — форма доступна только по id; заполните, чтобы показывать её
163
+ // в слоте хоста или на маршруте.
164
+ placement: { slots: [], routes: ['<%= it.names.routePath %>'] },
165
+
166
+ meta: {
167
+ name: '<%= it.names.title %>',
168
+ tags: ['renderer-json', 'form-registry'],
169
+ },
170
+ };
171
+ `,Je="# <%= it.names.title %>\n\nСгенерированная форма (renderer-json). Рендерится и работает сразу на синтетических данных —\n«доведение» сводится к реализации методов в ваших файлах.\n\n## Встраивание\n\nСкопируйте папку в `src/pages/demo/<%= it.names.dir %>/` и зарегистрируйте форму:\n\n```tsx\n<%~ include('codegen.snippet', it) -%>\n```\n\n## Файлы\n\nНабор — канон раскладки renderer-json (`@reformer/mcp` docs/llms/06-form-directory-layout.md §1),\nплоский: без `lib/` и `components/steps/`, запись реестра форм — в `index.tsx`.\n\n- **Регенерируемые** (перезаписываются при повторной генерации): <%= it.files.filter((f) => f.cls === 'derived').map((f) => '`' + f.path + '`').join(', ') %>.\n- **Ваши** (пишутся один раз, не затираются): <%= it.files.filter((f) => f.cls === 'user').map((f) => '`' + f.path + '`').join(', ') %>.\n\nСхема лежит в `renderer.schema.json` — допустимый вариант канона («схема как данные»), выбранный\nради того, чтобы форма открывалась обратно в билдере. Цена — пути `$model(...)` не проверяются на\nкомпиляции: опечатка внутри них останется до рантайма, и никто её не поймает. Нужна проверка —\nпереложите схему в `renderer.schema.ts` литералом `defineJsonSchema<<%= it.names.TypeName %>>({ ... })`;\nправить её в билдере после этого будет нельзя.\n\nКомпоненты импортируются из `<%= it.kit.importSpecifier %>` — того кита, который был\nактивен при генерации (`<%= it.kit.label %>`).\n\n## Методы для реализации\n\n- `api.ts` → `submitForm(values)` — отправка на реальный бэкенд (сейчас `console.info` и успех).\n<% if (it.selectors.sections.length > 0) { -%>\n- `renderer.behavior.ts` → раскомментируйте `hideWhen` для секций: <%= it.selectors.sections.map((s) => '`' + s.selector + '`').join(', ') %>.\n<% } -%>\n<% if (it.dataSources.labels.length > 0) { -%>\n- `data-sources.ts` → подписи элементов массивов: <%= it.dataSources.labels.map((x) => '`' + x + '`').join(', ') %>.\n<% } -%>\n<% if (it.dataSources.options.length > 0) { -%>\n- `data-sources.ts` → замените синтетические опции реальными словарями или загрузчиками.\n<% } -%>\n- `validation.ts` → допишите правила (сейчас — только `required`).\n- `form.behavior.ts` → вычисляемые поля и условное включение (по желанию).\n",qe=`// types.ts — тип формы (выведен из схемы и мока). Регенерируется.
172
+
173
+ export type SelectOption = { value: string; label: string };
174
+
175
+ export type <%= it.names.TypeName %> = <%= it.types.text %>;
176
+ `,Ge=`<% if (it.rules.validationCode !== null) { -%>
177
+ <%~ it.rules.validationCode -%>
178
+ <% } else if (it.stepValidation !== null) { -%>
179
+ <% const sv = it.stepValidation; -%>
180
+ <% const anyRequired = sv.rest.length > 0 || sv.steps.some((s) => s.required.length > 0); -%>
181
+ // validation.ts — валидация модели по шагам визарда. МОК: required выведены из схемы,
182
+ // допишите правила. Пишется один раз и при регенерации не затирается.
183
+
184
+ import { type FormModel } from '@reformer/core';
185
+ <% if (anyRequired) { -%>
186
+ import { apply, validate, defineValidationSchema, validateModel } from '@reformer/core/validation';
187
+ import { required } from '@reformer/core/validators';
188
+ <% } else { -%>
189
+ import { apply, defineValidationSchema, validateModel } from '@reformer/core/validation';
190
+ <% } -%>
191
+ import type { <%= it.names.TypeName %> } from './types';
192
+
193
+ type Root = <%= it.names.TypeName %>;
194
+ <% sv.steps.forEach((step, i) => { %>
195
+ /** Шаг <%= i + 1 %><%= step.selector === null ? '' : ' — ' + step.selector %>. «Далее» проверяет только эти правила. */
196
+ <% if (step.required.length > 0) { -%>
197
+ export const <%= step.name %> = defineValidationSchema<Root>(({ model }) => {
198
+ <% for (const path of step.required) { -%>
199
+ validate(model.$.<%= path %>, [required({ message: 'Обязательное поле' })]);
200
+ <% } -%>
201
+ });
202
+ <% } else { -%>
203
+ export const <%= step.name %> = defineValidationSchema<Root>(() => {
204
+ // TODO: правила шага
205
+ });
206
+ <% } -%>
207
+ <% }) %>
208
+ /** Полная проверка (отправка): правила всех шагов<%= sv.rest.length > 0 ? ' и поля вне шагов' : '' %>. */
209
+ <% if (sv.rest.length > 0) { -%>
210
+ export const formValidation = defineValidationSchema<Root>(({ model }) => {
211
+ apply(<%= sv.steps.map((s) => s.name).join(', ') %>);
212
+ <% for (const path of sv.rest) { -%>
213
+ validate(model.$.<%= path %>, [required({ message: 'Обязательное поле' })]);
214
+ <% } -%>
215
+ });
216
+ <% } else { -%>
217
+ export const formValidation = defineValidationSchema<Root>(() => {
218
+ apply(<%= sv.steps.map((s) => s.name).join(', ') %>);
219
+ });
220
+ <% } -%>
221
+
222
+ /** Под-схемы по порядку шагов: индекс — номер шага минус один. */
223
+ const stepValidations = [<%= sv.steps.map((s) => s.name).join(', ') %>];
224
+
225
+ /**
226
+ * Пошаговый контракт визарда (\`FormWizard\` → \`config\`). \`touch: true\` обязателен: киты показывают
227
+ * ошибку только у тронутого поля, и без него остановленный шаг выглядел бы как неработающая кнопка.
228
+ */
229
+ export function makeValidationConfig(model: FormModel<Root>) {
230
+ return {
231
+ validateStep: (step: number): Promise<boolean> => {
232
+ const schema = stepValidations[step - 1];
233
+ return schema === undefined
234
+ ? Promise.resolve(true)
235
+ : validateModel(model, schema, { touch: true });
236
+ },
237
+ validateAll: (): Promise<boolean> => validateModel(model, formValidation, { touch: true }),
238
+ };
239
+ }
240
+ <% } else { -%>
241
+ // validation.ts — валидация модели. МОК: required выведены из схемы, допишите правила.
242
+ // Пишется один раз и при регенерации не затирается.
243
+
244
+ import { type FormModel } from '@reformer/core';
245
+ <% if (it.required.length > 0) { -%>
246
+ import { validate, defineValidationSchema, validateModel } from '@reformer/core/validation';
247
+ import { required } from '@reformer/core/validators';
248
+ <% } else { -%>
249
+ import { defineValidationSchema, validateModel } from '@reformer/core/validation';
250
+ <% } -%>
251
+ import type { <%= it.names.TypeName %> } from './types';
252
+
253
+ type Root = <%= it.names.TypeName %>;
254
+
255
+ <% if (it.required.length > 0) { -%>
256
+ export const formValidation = defineValidationSchema<Root>(({ model }) => {
257
+ <% for (const path of it.required) { -%>
258
+ validate(model.$.<%= path %>, [required({ message: 'Обязательное поле' })]);
259
+ <% } -%>
260
+ });
261
+ <% } else { -%>
262
+ export const formValidation = defineValidationSchema<Root>(() => {
263
+ // TODO: правила валидации
264
+ });
265
+ <% } -%>
266
+
267
+ /** Пошаговый контракт визарда. Полная проверка — validateModel(model, formValidation). */
268
+ export function makeValidationConfig(model: FormModel<Root>) {
269
+ return {
270
+ validateStep: (_step: number): Promise<boolean> => validateModel(model, formValidation),
271
+ validateAll: (): Promise<boolean> => validateModel(model, formValidation),
272
+ };
273
+ }
274
+ <% } -%>
275
+ `,Ue=`<% if (it.rules.behaviorCode !== null) { -%>
276
+ <%~ it.rules.behaviorCode -%>
277
+ <% } else { -%>
278
+ // form.behavior.ts — реактивное поведение модели (вычисляемые поля, enableWhen, copyFrom).
279
+ // МОК: заготовка, реализуйте по необходимости. Пишется один раз.
280
+
281
+ import { defineFormBehavior } from '@reformer/core/behaviors';
282
+ import type { <%= it.names.TypeName %> } from './types';
283
+
284
+ export const formBehavior = defineFormBehavior<<%= it.names.TypeName %>>(() => {});
285
+
286
+ // --- ПРИМЕР ↓ замените объявление выше на такое и оставьте нужные строки ---------------
287
+ // import { defineFormBehavior, compute, computeFrom, copyFrom, enableWhen } from '@reformer/core/behaviors';
288
+ //
289
+ // export const formBehavior = defineFormBehavior<<%= it.names.TypeName %>>(({ model }) => {
290
+ // // model.field — ЗНАЧЕНИЕ поля, model.$.field — его сигнал. Операторы принимают сигналы.
291
+ // compute(model.$.total, () => (model.price ?? 0) * (model.qty ?? 0));
292
+ // computeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price * qty);
293
+ // enableWhen(model.$.city, () => model.country !== null);
294
+ // copyFrom(model.$.shippingAddress, model.$.billingAddress, { when: () => model.sameAddress });
295
+ // });
296
+ // --- конец примера ---------------------------------------------------------------------
297
+ <% } -%>
298
+ `,Le=`// renderer.wizard.tsx — шим под $component(Wizard) и тело шага. Регенерируется.
299
+
300
+ /* eslint-disable @typescript-eslint/no-explicit-any */
301
+ import type { ReactNode } from 'react';
302
+ import { <%= it.wizard.symbol %>, type FormWizardStep } from '<%= it.wizard.importFrom %>';
303
+ import type { FormProxy } from '@reformer/core';
304
+ import { RenderNodeComponent, type RenderNode } from '@reformer/renderer-react';
305
+ import type { <%= it.names.TypeName %> } from './types';
306
+
307
+ /**
308
+ * Пошаговая проверка визарда. Структурно, а не типом кита: контракт \`config\` один у любого
309
+ * кита на cdk-визарде, а импорт типа привязал бы шим к конкретному пакету.
310
+ */
311
+ export interface WizardValidationConfig {
312
+ validateStep?: (step: number) => boolean | Promise<boolean>;
313
+ validateAll?: () => boolean | Promise<boolean>;
314
+ }
315
+
316
+ /** Узел шага после конвертации: \`title\`/\`icon\` лежат в его \`componentProps\`. */
317
+ interface StepNode {
318
+ componentProps?: { title?: string; icon?: string; [key: string]: unknown };
319
+ [key: string]: unknown;
320
+ }
321
+
322
+ export interface WizardProps {
323
+ /** Приходит от рендерера (см. \`__selfManagedChildren\`). */
324
+ form?: FormProxy<<%= it.names.TypeName %>>;
325
+ /** Узлы шагов из \`componentProps.steps\`. */
326
+ steps?: StepNode[];
327
+ className?: string;
328
+ /**
329
+ * Проверка шагов — приходит от renderer.behavior.ts через \`patchProps\`. Без неё «Далее»
330
+ * не проверяет шаг: визард пропустил бы пустые обязательные поля.
331
+ */
332
+ config?: WizardValidationConfig;
333
+ /** Вешается снаружи — renderer.behavior.ts через onComponentEvent(node, 'onSubmit'). */
334
+ onSubmit?: (values: <%= it.names.TypeName %>) => void | Promise<void>;
335
+ }
336
+
337
+ /**
338
+ * Визард: узлы шагов из схемы — в шаги кита. Отрисовку тела шага даём пропом
339
+ * \`renderStepBody\`: кит намеренно не зависит от \`@reformer/renderer-react\`.
340
+ */
341
+ export function Wizard({ form, steps = [], className, config, onSubmit }: WizardProps): ReactNode {
342
+ const wizardSteps: FormWizardStep<<%= it.names.TypeName %>, RenderNode<<%= it.names.TypeName %>>>[] = steps.map(
343
+ (node, i) => ({
344
+ number: i + 1,
345
+ title: node.componentProps?.title ?? \`Шаг \${i + 1}\`,
346
+ icon: node.componentProps?.icon,
347
+ body: node as any,
348
+ })
349
+ );
350
+
351
+ return (
352
+ <<%= it.wizard.symbol %><<%= it.names.TypeName %>, RenderNode<<%= it.names.TypeName %>>>
353
+ form={form as FormProxy<<%= it.names.TypeName %>>}
354
+ className={className}
355
+ steps={wizardSteps}
356
+ config={config ?? {}}
357
+ renderStepBody={(body, wizardForm) => <RenderNodeComponent node={body} form={wizardForm} />}
358
+ onSubmit={onSubmit ? () => onSubmit(form?.getValue() as <%= it.names.TypeName %>) : undefined}
359
+ />
360
+ );
361
+ }
362
+
363
+ // Контракт с рендерером: получить \`form\` пропом и сырые \`steps\`, без обхода детей.
364
+ (Wizard as any).__selfManagedChildren = true;
365
+
366
+ export interface StepProps {
367
+ className?: string;
368
+ children?: ReactNode;
369
+ }
370
+
371
+ /**
372
+ * Тело шага — компонент под \`$component(Step)\`. Маркер: \`title\`/\`icon\` из его
373
+ * \`componentProps\` снимает \`Wizard\` выше, сюда доезжает только вёрстка.
374
+ */
375
+ export function <%= it.wizard.stepName %>({ className, children }: StepProps): ReactNode {
376
+ return <div className={className}>{children}</div>;
377
+ }
378
+ `,Xe=`// registry.ts — привязка $component/$dataSource к реализациям. Регенерируется.
379
+
380
+ <% if (it.registry.hasPlaceholder) { -%>
381
+ import type { ReactNode } from 'react';
382
+ <% } -%>
383
+ import { <%= it.registry.kitSymbols.join(', ') %> } from '<%= it.kit.importSpecifier %>';
384
+ import { defineRegistry, FIELD_WRAPPER } from '@reformer/renderer-json';
385
+ <% if (it.wizard !== null) { -%>
386
+ import { <% if (it.wizard.hasStep) { %><%= it.wizard.stepName %>, <% } %>Wizard } from './renderer.wizard';
387
+ <% } -%>
388
+ <% if (it.registry.dataSourceNames.length > 0) { -%>
389
+ import { <%= it.registry.dataSourceNames.join(', ') %> } from './data-sources';
390
+ <% } -%>
391
+ <% if (it.registry.hasPlaceholder) { -%>
392
+
393
+ /** Заглушка для компонента без прямого соответствия в ките (замените реальным). */
394
+ const Placeholder = ({ children }: { children?: ReactNode }): ReactNode => children ?? null;
395
+ <% } -%>
396
+
397
+ export function createRegistry() {
398
+ return defineRegistry((reg) => {
399
+ reg.component(FIELD_WRAPPER, <%= it.registry.fieldWrapper %>);
400
+ <% if (it.wizard !== null) { -%>
401
+ // Визард и тело шага — из шима renderer.wizard.tsx.
402
+ <% for (const name of it.wizard.hostNames) { -%>
403
+ reg.component('<%= name %>', Wizard);
404
+ <% } -%>
405
+ <% if (it.wizard.hasStep) { -%>
406
+ reg.component('<%= it.wizard.stepName %>', <%= it.wizard.stepName %>);
407
+ <% } -%>
408
+ <% } -%>
409
+ <% for (const c of it.registry.components) { -%>
410
+ <% if (c.placeholder) { -%>
411
+ reg.component('<%= c.name %>', Placeholder); // TODO: <%= c.reason %>
412
+ <% } else { -%>
413
+ reg.component('<%= c.name %>', <%= c.symbol %>);
414
+ <% } -%>
415
+ <% } -%>
416
+ <% if (it.registry.dataSourceNames.length > 0) { %>
417
+ <% for (const name of it.registry.dataSourceNames) { -%>
418
+ reg.dataSource('<%= name %>', <%= name %>);
419
+ <% } -%>
420
+ <% } -%>
421
+ });
422
+ }
423
+ `,He=`// renderer.behavior.ts — рантайм-обвязка (submit, условная видимость, события узлов).
424
+
425
+ import { <%= it.renderBehavior.imports.join(', ') %>, type RenderBehaviorFn } from '@reformer/renderer-react';
426
+ import { validateModel } from '@reformer/core/validation';
427
+ import type { FormModel, FormProxy } from '@reformer/core';
428
+ <% if (it.stepValidation !== null) { -%>
429
+ import { formValidation, makeValidationConfig } from './validation';
430
+ <% } else { -%>
431
+ import { formValidation } from './validation';
432
+ <% } -%>
433
+ import { submitForm } from './api';
434
+ import type { <%= it.names.TypeName %> } from './types';
435
+
436
+ export type RenderBehaviorOptions = { onResult?: (message: string, ok: boolean) => void };
437
+
438
+ export function createJsonRenderBehavior(
439
+ form: FormProxy<<%= it.names.TypeName %>>,
440
+ model: FormModel<<%= it.names.TypeName %>>,
441
+ options: RenderBehaviorOptions = {}
442
+ ): RenderBehaviorFn<<%= it.names.TypeName %>> {
443
+ const { onResult } = options;
444
+ return (schema) => {
445
+ void form; // используется в условиях hideWhen (form.<поле>.value.value)
446
+ <% if (it.renderBehavior.voidHideWhen) { -%>
447
+ void hideWhen;
448
+ <% } -%>
449
+
450
+ const <%= it.renderBehavior.target %> = schema.node('<%= it.selectors.submitSelector %>');
451
+ <% if (it.renderBehavior.isWizard) { -%>
452
+
453
+ <% if (it.stepValidation !== null) { -%>
454
+ // Визард — self-managed компонент: форму и пошаговую проверку ему передаём явно.
455
+ // Без \`config\` «Далее» не проверяет шаг вовсе и пропускает пустые обязательные поля.
456
+ onInit(<%= it.renderBehavior.target %>, () =>
457
+ <%= it.renderBehavior.target %>.patchProps({ form, config: makeValidationConfig(model) })
458
+ );
459
+ <% } else { -%>
460
+ // Визард — self-managed компонент: форму ему передаём явно.
461
+ onInit(<%= it.renderBehavior.target %>, () => <%= it.renderBehavior.target %>.patchProps({ form }));
462
+ <% } -%>
463
+ <% } -%>
464
+
465
+ onComponentEvent(<%= it.renderBehavior.target %>, '<%= it.selectors.submitEvent %>', async () => {
466
+ // \`touch: true\` обязателен: киты показывают ошибку только у ТРОНУТОГО поля
467
+ // (\`invalid && (touched || dirty)\`). Без него неудачная отправка выглядела бы так,
468
+ // будто кнопка не работает: форма не отправлена, а почему — нигде не сказано.
469
+ if (!(await validateModel(model, formValidation, { touch: true }))) {
470
+ onResult?.('Проверьте заполнение формы', false);
471
+ return;
472
+ }
473
+ const res = await submitForm(model.get());
474
+ onResult?.(res.success ? 'Форма отправлена' : res.error, res.success);
475
+ });
476
+ <% if (it.renderBehavior.rules.length > 0) { %>
477
+ // Правила render-слоя (из правил формы — правьте здесь или в панели правил):
478
+ <% for (const rule of it.renderBehavior.rules) { -%>
479
+ <%~ it.indent(rule.lines, 4) %>
480
+ <% } -%>
481
+ <% } -%>
482
+ <% if (it.renderBehavior.scaffold.length > 0) { %>
483
+ // Условная видимость секций — раскомментируйте и впишите условие:
484
+ <% for (const s of it.renderBehavior.scaffold) { -%>
485
+ // hideWhen(schema.node('<%= s.selector %>'), () => /* TODO: условие для «<%= s.label %>» */ false);
486
+ <% } -%>
487
+ <% } -%>
488
+ };
489
+ }
490
+ `,Y=`// ── Способ 1 (рекомендуемый): через реестр форм — одна строка на регистрацию.
491
+ // Всё остальное (схема, реестр компонентов, модель, поведение) описано записью реестра
492
+ // в index.tsx (<%= it.names.entryConst %>) — билдер перегенерирует её при изменениях.
493
+ import { getFormRegistry } from '@reformer/form-registry';
494
+ import { <%= it.names.entryConst %> } from './pages/demo/<%= it.names.dir %>';
495
+
496
+ getFormRegistry().register(<%= it.names.entryConst %>);
497
+
498
+ // Дальше форму можно смонтировать где угодно, зная только её id:
499
+ // <FormOutlet id="<%= it.names.exampleId %>" />
500
+
501
+ // ── Способ 2: как обычную страницу, если реестр не используется.
502
+ import <%= it.names.pageComponent %> from './pages/demo/<%= it.names.dir %>';
503
+
504
+ // пункт в списке примеров:
505
+ { id: '<%= it.names.exampleId %>', path: '<%= it.names.routePath %>', title: '<%= it.names.title %>', description: '' },
506
+
507
+ // маршрут внутри <Routes>:
508
+ <Route path="<%= it.names.routePath %>" element={<<%= it.names.pageComponent %> />} />
509
+ `,Z="codegen.snippet";Me(Z,Y);function Ye(e){return U(Z,Y,{names:e}).replace(/\n$/,"")}const k="---";function b(e){return{ok:!1,message:e}}function j(e,t){if(e!==void 0)return typeof e!="string"||e.trim()===""?new Error(`«${t}» должно быть непустой строкой`):e.trim()}function Ze(e){const t=e.replace(/^\uFEFF/,"");if(!t.startsWith(`${k}
510
+ `)&&!t.startsWith(`${k}\r
511
+ `))return b("файл должен начинаться со строки `---` и заголовка за ней");const r=t.indexOf(`
512
+ `)+1,n=t.indexOf(`
513
+ ${k}`,r);if(n<0)return b("заголовок не закрыт строкой `---`");const i=t.slice(r,n),o=t.indexOf(`
514
+ `,n+1),a=o<0?"":t.slice(o+1);let l;try{l=JSON.parse(i)}catch(p){return b(`заголовок не разбирается как JSON: ${p.message}`)}if(typeof l!="object"||l===null||Array.isArray(l))return b("заголовок должен быть объектом JSON");const c=l,s=j(c.id,"id");if(s instanceof Error)return b(s.message);if(s===void 0)return b("в заголовке нет «id»");const u=j(c.path,"path");if(u instanceof Error)return b(u.message);if(u===void 0)return b("в заголовке нет «path»");const f=c.cls;if(f!=="derived"&&f!=="user")return b("«cls» должно быть «derived» или «user»");const v=c.order;if(v!==void 0&&(typeof v!="number"||!Number.isFinite(v)))return b("«order» должно быть числом");const m=c.regenerable;if(m!==void 0&&typeof m!="boolean")return b("«regenerable» должно быть true или false");for(const p of["title","overrides","applies"]){const g=j(c[p],p);if(g instanceof Error)return b(g.message)}return{ok:!0,body:a,meta:{id:s,path:u,cls:f,...v===void 0?{}:{order:v},...m===void 0?{}:{regenerable:m},...typeof c.title=="string"?{title:c.title.trim()}:{},...typeof c.overrides=="string"?{overrides:c.overrides.trim()}:{},...typeof c.applies=="string"?{applies:c.applies.trim()}:{}}}}function Qe(e,t){const n=[["id",e.id],...e.overrides===void 0?[]:[["overrides",e.overrides]],["path",e.path],["cls",e.cls],...e.order===void 0?[]:[["order",e.order]],...e.regenerable===void 0?[]:[["regenerable",e.regenerable]],...e.title===void 0?[]:[["title",e.title]],...e.applies===void 0?[]:[["applies",e.applies]]].map(([i,o])=>` ${JSON.stringify(i)}: ${JSON.stringify(o)}`).join(`,
515
+ `);return`${k}
516
+ {
517
+ ${n}
518
+ }
519
+ ${k}
520
+ ${t}`}function et(e){return e===""||e.startsWith("/")||e.includes("\\")?!1:!e.split("/").some(t=>t===".."||t==="."||t==="")}function tt(e,t){const r=[],n=[],i=new Map;for(const o of e){const a=o.emit!==void 0,l=o.template!==void 0;if(a===l){r.push({targetId:o.id,path:o.path,reason:a?"both-bodies":"no-body",message:a?"цель объявила и emit, и template":"цель не объявила ни emit, ни template"});continue}if(!et(o.path)){r.push({targetId:o.id,path:o.path,reason:"escaping-path",message:"путь выходит за каталог модуля"});continue}let c=!0;try{c=o.applies===void 0?!0:o.applies(t)}catch(u){r.push({targetId:o.id,path:o.path,reason:"threw",message:Q(u)});continue}if(!c)continue;const s=i.get(o.path);if(s!==void 0){r.push({targetId:o.id,path:o.path,reason:"duplicate-path",message:`файл уже печатает цель «${s}»`});continue}i.set(o.path,o.id),n.push(o)}return{selected:n,problems:r}}function Q(e){return e instanceof Error?e.message:String(e)}function nt(e,t,r){if(e.template!==void 0){const n=e.view?.(t),i=n===void 0?r:Ce(r,n);return U(e.id,e.template,i)}if(e.emit!==void 0)return e.emit(t);throw new Error(`цель «${e.id}» без тела дошла до печати`)}async function z(e,t,r){const n=Ee(t),{selected:i,problems:o}=tt(e,n),a=i.map(m=>({path:m.path,cls:m.cls})),l=Oe(n,a),c=Fe(G(n),a),s=[],u=[];for(const m of i)try{s.push({path:m.path,content:nt(m,l,c),cls:m.cls,regenerable:m.regenerable===!0,targetId:m.id,origin:m.origin??"builtin"})}catch(p){u.push({targetId:m.id,path:m.path,reason:"threw",message:Q(p)})}const f=r===void 0?null:await r(s),v=s.map((m,p)=>{const g=f?.[p]??m.content,w=(m.cls==="derived"||m.regenerable)&&Re(m.path)?q(g):g;return{...m,content:w}});return{dir:l.names.dir,files:v,problems:[...o,...u],context:l,view:c}}function ee(e){const t=e.ref.name,r=t.indexOf(".");return r<=0?t:t.slice(0,r)}function te(e){const t=e.model();if(F(t))return t;try{const r=JSON.parse(e.getText());return F(r)?r:null}catch{return null}}async function ne(e){const{host:t,targets:r,documentId:n,store:i}=e,o=t.documentOf(n);if(o===null){i.patch({phase:"idle",errorKey:"error.no-document"});return}const a=te(o);if(a===null){i.patch({phase:"idle",errorKey:"error.not-a-schema"});return}const l=t.kit();if(l===null){i.patch({phase:"idle",errorKey:"error.no-kit"});return}const c=(e.formName??"").trim()||ee(o);i.patch({phase:"running",errorKey:null,delivery:null});const s=await z(r,{schema:a,formName:c,kit:{kit:l,catalog:t.catalog()},rules:t.rulesOf?.(n)??void 0},t.format),u=[...e.problems??[],...s.problems],f=s.files.map(m=>({path:m.path,cls:m.cls,targetId:m.targetId,origin:m.origin})),v=Ye(s.context.names);try{const m=await $e(t,t.parentOf(n),s.dir,s.files);i.patch({phase:"idle",formName:c,files:f,snippet:v,problems:u,view:s.view,delivery:m,errorKey:null})}catch(m){if(i.patch({phase:"idle",formName:c,files:f,snippet:v,problems:u,view:s.view,delivery:null,errorKey:m instanceof S?"error.read-only":"error.failed"}),!(m instanceof S))throw m}}const rt=Object.freeze({id:"codegen.target"}),h=de.id,C="codegen.generateInto",R="resource/context/codegen",I="renderer.schema.json",ot=[".schema.json",".form.json"];function it(e){return e===I||ot.some(t=>e.endsWith(t))}function at(e){return[...e.filter(r=>r.kind==="file"&&it(r.name))].sort((r,n)=>r.name===n.name?0:r.name===I?-1:n.name===I?1:r.name.localeCompare(n.name))}async function st(e,t){if(e.list===void 0)return null;const r=await e.list(t).catch(()=>null);if(r===null)return null;for(const n of at(r)){const i=e.documentOf(n.id);if(i!==null){const a=te(i);if(a!==null)return{ref:n,schema:a};continue}const o=await e.readText(n.id).catch(()=>null);if(o!==null)try{const a=JSON.parse(o);if(F(a))return{ref:n,schema:a}}catch{}}return null}function lt(e){const t=e.indexOf(".");return t<=0?e:e.slice(0,t)}function E(e,t){if(typeof e!="object"||e===null)return;const r=e[t];return typeof r=="string"&&r!==""?r:void 0}function dt(e){return{dir:E(e,"dir"),targetId:E(e,"targetId"),formName:E(e,"formName")}}async function ct(e,t){const{host:r}=e,n=t.dir;if(n===void 0)return{kind:"no-directory"};if(r.list===void 0)return{kind:"no-listing"};const i=await st(r,n);if(i===null)return{kind:"no-schema"};const o=r.kit();if(o===null)return{kind:"no-kit"};const a=(t.formName??"").trim()||lt(i.ref.name),l=await z(e.targets(),{schema:i.schema,formName:a,kit:{kit:o,catalog:r.catalog()},rules:r.rulesOf?.(i.ref.id)??void 0},r.format),c=t.targetId===void 0?l.files:l.files.filter(s=>s.targetId===t.targetId);if(c.length===0&&t.targetId!==void 0)return{kind:"not-applicable",targetId:t.targetId};try{return{kind:"delivered",delivery:await H(r,n,c),formName:a}}catch(s){return s instanceof S?{kind:"read-only"}:{kind:"failed",message:s instanceof Error?s.message:String(s)}}}function mt(e,t){if(e!==null)switch(t.kind){case"no-directory":e.warning(y(h,"notify.no-directory"));return;case"no-listing":e.error(y(h,"notify.no-listing"));return;case"no-schema":e.warning(y(h,"notify.no-schema"));return;case"no-kit":e.error(y(h,"notify.no-kit"));return;case"not-applicable":e.info(y(h,"notify.not-applicable"));return;case"read-only":e.error(y(h,"notify.read-only"));return;case"failed":e.error(y(h,"notify.failed"),{params:{message:t.message}});return;case"delivered":{const{written:r,skipped:n,failed:i}=t.delivery;if(i.length>0){e.error(y(h,"notify.partial"),{params:{written:r.length,failed:i.length}});return}if(r.length===0){e.info(y(h,"notify.nothing-written"),{params:{skipped:n.length}});return}e.success(y(h,"notify.written"),{params:{written:r.length,skipped:n.length}});return}}}function pt(e,t){return[{id:C,titleKey:"command.generateInto",async run(r){const n=await ct(e,dt(r));if(mt(t,n),n.kind==="delivered"&&n.delivery.written.length===1){const i=n.delivery.written[0];e.host.openResource?.(e.host.resolve(n.delivery.dir,...i.split("/")))}return n.kind==="delivered"}}]}const ut=K(e=>e.ref===null||e.ref.kind==="directory");function $(e){return e!==null&&e.kind==="directory"?e.name:void 0}function ft(e){return[{id:"codegen.context.submenu",value:{kind:"submenu",menu:V,submenu:R,titleKey:"menu.generate",group:"4_generate",enabledWhen:ut}},{id:"codegen.context.all",value:{kind:"item",menu:R,command:C,group:"1_all",titleKey:"menu.generate.all",argsOf:B(t=>({dir:t.dir,formName:$(t.ref)}))}},{id:"codegen.context.targets",value:{kind:"dynamic",menu:R,group:"2_targets",items:(t,r)=>{const n=ce(r);if(n===null)return[];const i=$(n.ref);return e().map(o=>({id:o.id,command:C,args:{dir:n.dir,targetId:o.id,formName:i},titleKey:o.titleKey,title:o.titleKey===void 0?o.path:void 0}))}}}]}const re=[".ui_builder","codegen"],ht=".eta",gt=Object.freeze({targets:[],problems:[]});function T(e,t){return{targetId:e,path:e,reason:"template-invalid",message:t}}function yt(e){const t=new Function("it",`return (${e});`);return r=>t(G(r))===!0}function vt(e,t){const r=Ze(t);if(!r.ok)return T(e,r.message);const{meta:n,body:i}=r;let o;if(n.applies!==void 0)try{o=yt(n.applies)}catch(a){return T(e,`«applies» не компилируется: ${a.message}`)}return{id:n.id,path:n.path,cls:n.cls,template:i,origin:"user",...n.order===void 0?{}:{order:n.order},...n.title===void 0?{}:{title:n.title},...n.overrides===void 0?{}:{overrides:n.overrides},...n.regenerable===void 0?{}:{regenerable:n.regenerable},...o===void 0?{}:{applies:o}}}function bt(e){return"reason"in e}async function xt(e){const t=e.projectRoot?.()??null;if(t===null||e.list===void 0)return gt;const r=e.resolve(t,...re),i=(await e.list(r).catch(()=>[])).filter(s=>s.kind!=="directory"&&s.name.endsWith(ht)).sort((s,u)=>s.name.localeCompare(u.name)),o=[],a=[];for(const s of i){const u=await e.readText(s.id).catch(()=>null);if(u===null){a.push(T(s.name,"файл не читается"));continue}const f=vt(s.name,u);bt(f)?a.push(f):o.push(f)}const l=new Set,c=[];for(const s of o){if(l.has(s.id)){a.push(T(s.path,`цель с id «${s.id}» уже объявлена другим файлом`));continue}l.add(s.id),c.push(s)}return{targets:c,problems:a}}function wt(e){const t=new Set(e.flatMap(r=>r.overrides===void 0?[]:[r.overrides]));return t.size===0?e:e.filter(r=>!t.has(r.id))}function _(e){const r=e.slice(e.lastIndexOf(".")+1).replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"");return r===""?"target":r}async function Nt(e,t,r){let n=`${r}.eta`;for(let i=2;await e.exists(e.resolve(t,n));i+=1)n=`${r}-${i}.eta`;return n}async function kt(e,t){const{host:r}=e,n=e.targets().find(l=>l.id===t);if(n===void 0||n.template===void 0)return{kind:"not-a-template",targetId:t};const i=r.projectRoot?.()??null;if(i===null)return{kind:"no-project"};const o=r.resolve(i,...re),a=r.sourceOf(o);if(a===null||!a.write)return{kind:"read-only"};try{const l=await Nt(r,o,_(n.id)),c=r.resolve(o,l),s=n.order,u=Qe({id:`user.${_(n.id)}`,overrides:n.id,path:n.path,cls:n.cls,...s===void 0?{}:{order:s},...n.regenerable===void 0?{}:{regenerable:n.regenerable}},n.template);return await r.writeText(c,u),await r.save?.([c]),{kind:"written",id:c,name:l}}catch(l){return{kind:"failed",message:l instanceof Error?l.message:String(l)}}}function St(e){return typeof e=="object"&&e!==null&&"root"in e?e:null}async function Tt(e,t){const r=e.documentOf(t),n=St(r?.model());if(r===null||n===null)return{kind:"no-schema"};const i=ze(r.ref.path),o=e.resolveFromRoot;if(i===null||o===void 0)return{kind:"no-target"};if(e.sourceOf(t)?.write!==!0)return{kind:"no-target"};const a=o(t,i),l=await e.readText(a);return l!==null&&!J(l)?{kind:"edited",path:i,id:a}:(await e.writeText(a,q(Ie(n))),await e.save?.([a]),{kind:"written",path:i,id:a})}const jt=W({id:"reformer.kit.catalog",version:"1.0.0"}),Rt=Object.freeze([]),Et=W({id:"reformer.codegen.printer",version:"1.0.0"});function Ot(e,t={}){const r=e.services.require(me),n=e.services.require(pe),i=()=>e.services.get(jt);return{useTranslate:function(){return he(e.i18n)},useActiveDocument:function(){return fe(r)},documentOf:o=>r.documentOf(o)??null,sourceOf:o=>r.hasProject()?{write:n.canWrite(o)}:null,catalog:()=>i()?.catalog()??Rt,kit:()=>i()?.descriptor()??null,onDidChangeKit:o=>i()?.onDidChange(o)??{dispose:()=>{}},parentOf:n.parentOf,resolve:n.resolve,resolveFromRoot:n.fromRoot,projectRoot:n.projectRoot,exists:n.exists,list:n.list,readText:n.readText,writeText:(o,a)=>r.writeText(o,a),openResource:o=>{r.open(o,{preview:!1}).catch(a=>{console.error(`[codegen] открыть «${o}» не удалось`,a)})},save:async o=>await e.services.get(ue)?.save(o)??!1,...t}}const Ft={"panel.title":"Export form","command.generate":"Export form to code","form.name":"Form name","form.name.hint":"Directory, type and route names are derived from it.","kit.active":"Kit: {label} ({package})","action.generate":"Generate","action.running":"Generating…","files.title":"Module files","files.derived":"overwritten","files.user":"yours","empty.no-document":"No open document","empty.no-document.detail":"Open a form schema to generate its code.","empty.not-run":"Nothing generated yet","empty.not-run.detail":"The module layout appears after the first run.","result.written":"Files written: {count}","result.skipped":"Skipped (your edits kept): {count}","result.failed":"Not written: {count}","result.saved":"Pushed to the source","result.unsaved":"Kept in the working copy — save the project","skip.authored":"yours, never regenerated","skip.edited":"hand-edited — the marker does not match","problem.threw":"target failed: {message}","problem.duplicate-path":"{message}","problem.escaping-path":"path escapes the module directory","problem.no-body":"target prints nothing: neither emit nor template","problem.both-bodies":"target declares both emit and template — keep one","problem.template-invalid":"{message}","command.refresh-targets":"Reload codegen templates","command.eject-template":"Eject template into project","file.origin.user":"from project","panel.view-data":"Template data (it)","problems.title":"Target failures","snippet.title":"Registration in the app","snippet.copy":"Copy","snippet.copied":"Copied","error.no-document":"The document was closed while generating.","error.not-a-schema":"This document is not a form schema.","error.no-kit":"No kit selected: there is no way to know where to import components from.","error.read-only":"The source refuses writes — there is nowhere to put the module.","error.failed":"Writing the module failed.","command.create-fixture":"Create preview fixture","command.generateInto":"Generate the form module into a directory","menu.generate":"Generate","menu.generate.all":"The whole module","target.schema":"Form schema","target.types":"Types","target.model":"Model","target.registry":"Component registry","target.index":"Entry point","target.wizard":"Wizard shim","target.data-sources":"Data sources","target.render-behavior":"UI behavior","target.form-behavior":"Form behavior","target.validation":"Validation schema","target.api":"Backend","target.readme":"README","notify.eject-failed":"Eject failed: {message}","notify.eject-no-project":"No project open: nowhere to eject","notify.eject-not-a-template":"This file is printed by code, not a template","notify.eject-read-only":"Source does not accept writes","notify.eject-written":"Template ejected: {name}","notify.failed":"Generation failed: {message}","notify.no-directory":"No directory chosen: there is nowhere to generate into.","notify.no-kit":"No kit selected: there is no way to know where to import components from.","notify.no-listing":"The directory listing is unavailable — there is nowhere to look for a schema.","notify.no-schema":"This directory holds no form schema: there is nothing to generate from.","notify.not-applicable":"This file does not apply to that form — nothing to print.","notify.nothing-written":"Nothing written: {skipped} of your files were left untouched.","notify.partial":"Files written: {written}, failed: {failed}.","notify.read-only":"The source refuses writes — there is nowhere to put what was generated.","notify.targets-refreshed":"Codegen templates reloaded: {count}","notify.written":"Files written: {written}, yours skipped: {skipped}."},Ct={"panel.title":"Экспорт формы","command.generate":"Экспортировать форму в код","form.name":"Имя формы","form.name.hint":"Из него выводятся имя каталога, тип и маршрут.","kit.active":"Кит: {label} ({package})","action.generate":"Сгенерировать","action.running":"Генерируем…","files.title":"Файлы модуля","files.derived":"перезаписывается","files.user":"ваш","empty.no-document":"Нет открытого документа","empty.no-document.detail":"Откройте схему формы, чтобы сгенерировать её код.","empty.not-run":"Прогона ещё не было","empty.not-run.detail":"Состав модуля станет виден после генерации.","result.written":"Записано файлов: {count}","result.skipped":"Пропущено (ваши правки не тронуты): {count}","result.failed":"Не записано: {count}","result.saved":"Отправлено в источник","result.unsaved":"Осталось в рабочей копии — сохраните проект","skip.authored":"ваш файл, регенерации не подлежит","skip.edited":"правлен руками — маркер не сходится","problem.threw":"цель отказала: {message}","problem.duplicate-path":"{message}","problem.escaping-path":"путь выходит за каталог модуля","problem.no-body":"цель не печатает ничего: нет ни emit, ни template","problem.both-bodies":"цель объявила и emit, и template — оставьте одно","problem.template-invalid":"{message}","command.refresh-targets":"Перечитать шаблоны генерации","command.eject-template":"Выгрузить шаблон в проект","file.origin.user":"из проекта","panel.view-data":"Данные шаблона (it)","problems.title":"Отказы целей","snippet.title":"Регистрация в приложении","snippet.copy":"Скопировать","snippet.copied":"Скопировано","error.no-document":"Документ закрыли, пока шла генерация.","error.not-a-schema":"Этот документ не разбирается в схему формы.","error.no-kit":"Кит не выбран: неизвестно, откуда импортировать компоненты.","error.read-only":"Источник не принимает запись — сгенерированное сохранить некуда.","error.failed":"Записать модуль не удалось.","command.create-fixture":"Создать фикстуру предпросмотра","command.generateInto":"Сгенерировать код формы в каталог","menu.generate":"Сгенерировать","menu.generate.all":"Весь модуль","target.schema":"Схема формы","target.types":"Типы","target.model":"Модель","target.registry":"Реестр компонентов","target.index":"Точка входа","target.wizard":"Шим визарда","target.data-sources":"Справочники","target.render-behavior":"Поведение UI","target.form-behavior":"Поведение формы","target.validation":"Схема валидации","target.api":"Бэкенд","target.readme":"README","notify.eject-failed":"Выгрузить не удалось: {message}","notify.eject-no-project":"Проект не открыт: выгружать некуда","notify.eject-not-a-template":"Этот файл печатается кодом, а не шаблоном","notify.eject-read-only":"Источник не принимает запись","notify.eject-written":"Шаблон выгружен: {name}","notify.failed":"Сгенерировать не удалось: {message}","notify.no-directory":"Не выбран каталог: генерировать некуда.","notify.no-kit":"Кит не выбран: неизвестно, откуда импортировать компоненты.","notify.no-listing":"Содержимое каталога недоступно — искать схему негде.","notify.no-schema":"В этом каталоге нет схемы формы: генерировать не из чего.","notify.not-applicable":"Этот файл к такой форме не относится — печатать нечего.","notify.nothing-written":"Ничего не записано: ваших файлов {skipped} — они не тронуты.","notify.partial":"Записано файлов: {written}, не записано: {failed}.","notify.read-only":"Источник не принимает запись — сгенерированное сохранить некуда.","notify.targets-refreshed":"Шаблоны генерации перечитаны: {count}","notify.written":"Записано файлов: {written}, пропущено ваших: {skipped}."},It=Object.freeze({ru:Ct,en:Ft}),Pt=Object.freeze({phase:"idle",formName:"",files:[],snippet:"",problems:[],delivery:null,errorKey:null,view:null});function Mt(){let e=Pt;const t=new Set;return{get:()=>e,patch(r){e={...e,...r};for(const n of[...t])n()},subscribe(r){return t.add(r),{dispose:()=>{t.delete(r)}}}}}function zt(){const e=new Map;let t=null;return{storeFor(r){const n=e.get(r);if(n!==void 0)return n;const i=Mt();return e.set(r,i),i},active:()=>t,setActive(r){t=r},dispose(){e.clear(),t=null}}}const O=Object.freeze([{id:"codegen.schema",titleKey:"target.schema",path:"renderer.schema.json",cls:"derived",order:10,emit:De},{id:"codegen.types",titleKey:"target.types",path:"types.ts",cls:"derived",order:20,template:qe},{id:"codegen.model",titleKey:"target.model",path:"model.ts",cls:"derived",order:30,template:Be},{id:"codegen.registry",titleKey:"target.registry",path:"registry.ts",cls:"derived",order:40,template:Xe},{id:"codegen.index",titleKey:"target.index",path:"index.tsx",cls:"derived",order:50,template:We},{id:"codegen.wizard",titleKey:"target.wizard",path:"renderer.wizard.tsx",cls:"derived",order:60,applies:e=>Pe(e)!==null,template:Le},{id:"codegen.data-sources",titleKey:"target.data-sources",path:"data-sources.ts",cls:"user",order:70,template:Ve},{id:"codegen.render-behavior",titleKey:"target.render-behavior",path:"renderer.behavior.ts",cls:"user",regenerable:!0,order:80,template:He},{id:"codegen.form-behavior",titleKey:"target.form-behavior",path:"form.behavior.ts",cls:"user",regenerable:!0,order:90,template:Ue},{id:"codegen.validation",titleKey:"target.validation",path:"validation.ts",cls:"user",regenerable:!0,order:100,template:Ge},{id:"codegen.api",titleKey:"target.api",path:"api.ts",cls:"user",order:110,template:Ke},{id:"codegen.readme",titleKey:"target.readme",path:"README.md",cls:"derived",order:120,template:Je}]);function At({host:e,sessions:t,targets:r,onEject:n,problems:i}){const o=e.useTranslate(),a=e.useActiveDocument();return x.useEffect(()=>{t.setActive(a)},[t,a]),a===null?d.jsx(oe,{title:o("empty.no-document"),detail:o("empty.no-document.detail")}):d.jsx(_t,{host:e,sessions:t,targets:r,onEject:n,problems:i,documentId:a},a)}function $t(e){return x.useSyncExternalStore(t=>{const r=e.subscribe(t);return()=>{r.dispose()}},()=>e.get())}function _t({host:e,sessions:t,targets:r,documentId:n,onEject:i,problems:o}){const a=e.useTranslate(),l=t.storeFor(n),c=$t(l),s=e.documentOf(n),u=e.kit(),[f,v]=x.useState(()=>c.formName||(s===null?"":ee(s))),m=x.useCallback(()=>{ne({host:e,targets:r(),documentId:n,store:l,formName:f,problems:o?.()})},[e,r,n,l,f,o]),p=c.phase==="running";return d.jsxs("div",{className:"flex h-full min-h-0 flex-col gap-3 p-3",children:[d.jsxs("div",{className:"flex flex-col gap-1.5",children:[d.jsx(ge,{htmlFor:"codegen-form-name",children:a("form.name")}),d.jsx(ye,{id:"codegen-form-name","data-testid":"input-formName",value:f,onChange:g=>v(g.target.value)}),d.jsx("span",{className:"text-muted-foreground text-[11px]",children:a("form.name.hint")})]}),u===null?null:d.jsx("span",{className:"text-muted-foreground text-[11px]",children:a("kit.active",{label:u.label,package:u.package})}),d.jsx(M,{size:"sm",disabled:p,onClick:m,"data-testid":"button-generate",children:a(p?"action.running":"action.generate")}),c.errorKey===null?null:d.jsx(L,{variant:"destructive",children:d.jsx(X,{children:a(c.errorKey)})}),d.jsx(ve,{}),d.jsx(be,{className:"min-h-0 flex-1",children:d.jsx(Kt,{state:c,t:a,onEject:i})})]})}function Dt({view:e,t}){const[r,n]=x.useState(!1);return d.jsxs("section",{className:"flex flex-col gap-1",children:[d.jsxs(M,{size:"sm",variant:"ghost",className:"justify-start px-0",onClick:()=>{n(i=>!i)},children:[r?"▾":"▸"," ",t("panel.view-data")]}),r?d.jsx("pre",{className:"bg-muted max-h-64 overflow-auto rounded-md p-2 font-mono text-[11px]",children:JSON.stringify(e,null,2)}):null]})}function Kt({state:e,t,onEject:r}){if(e.files.length===0)return d.jsx(oe,{title:t("empty.not-run"),detail:t("empty.not-run.detail")});const n=e.delivery,i=new Set(n?.written??[]),o=new Map((n?.skipped??[]).map(a=>[a.path,a.reason]));return d.jsxs("div",{className:"flex flex-col gap-3",children:[d.jsxs("section",{className:"flex flex-col gap-1",children:[d.jsx("h3",{className:"text-foreground text-[12px] font-semibold",children:t("files.title")}),e.files.map(a=>{const l=o.get(a.path);return d.jsxs(xe,{size:"sm",variant:"muted",children:[d.jsxs(we,{children:[d.jsx(Ne,{className:"font-mono text-[12px]",children:a.path}),l===void 0?null:d.jsx("span",{className:"text-muted-foreground text-[11px]",children:t(`skip.${l}`)})]}),a.origin!=="user"?null:d.jsx(A,{variant:"outline",children:t("file.origin.user")}),d.jsx(A,{variant:i.has(a.path)?"default":"secondary",children:t(`files.${a.cls}`)}),r===void 0?null:d.jsx(M,{size:"sm",variant:"ghost",title:t("command.eject-template"),onClick:()=>{r(a.targetId)},children:"⤓"})]},a.path)})]}),n===null?null:d.jsxs("section",{className:"flex flex-col gap-0.5 text-[11.5px]",children:[d.jsx("span",{children:t("result.written",{count:n.written.length})}),n.skipped.length===0?null:d.jsx("span",{children:t("result.skipped",{count:n.skipped.length})}),n.failed.length===0?null:d.jsx("span",{className:"text-destructive",children:t("result.failed",{count:n.failed.length})}),d.jsx("span",{className:"text-muted-foreground",children:n.saved===!0?t("result.saved"):t("result.unsaved")})]}),e.problems.length===0?null:d.jsxs("section",{className:"flex flex-col gap-1",children:[d.jsx("h3",{className:"text-foreground text-[12px] font-semibold",children:t("problems.title")}),e.problems.map(a=>d.jsx(L,{variant:"destructive",children:d.jsxs(X,{className:"font-mono text-[11px] whitespace-pre-wrap",children:[a.path," — ",t(`problem.${a.reason}`,{message:a.message})]})},`${a.targetId}:${a.path}`))]}),e.view===null?null:d.jsx(Dt,{view:e.view,t}),e.snippet===""?null:d.jsxs("section",{className:"flex flex-col gap-1",children:[d.jsx("h3",{className:"text-foreground text-[12px] font-semibold",children:t("snippet.title")}),d.jsx("pre",{className:"bg-muted overflow-x-auto rounded p-2 font-mono text-[11px]",children:e.snippet})]})]})}function oe({title:e,detail:t}){return d.jsx("div",{className:"flex h-full items-center justify-center p-6",children:d.jsxs("div",{className:"border-border max-w-sm rounded-md border border-dashed p-4 text-center",children:[d.jsx("div",{className:"text-foreground text-[13px] font-medium",children:e}),d.jsx("div",{className:"text-muted-foreground mt-1 text-[12px]",children:t})]})})}const Vt="codegen.panel",ie="codegen.generate",Bt="codegen.create-fixture",Wt="codegen.refresh-targets",ae="codegen.eject-template",Jt=1e3,qt="panel.right",Gt=new Set(["form.schema","application/json"]),Ut=()=>x.createElement(Ae,{className:"size-4"});function P(e){return e.activeResourceKind!==null&&Gt.has(e.activeResourceKind)}function Lt(e,t,r,n,i,o){return{id:Vt,slot:n,titleKey:"panel.title",icon:Ut,when:P,order:20,Body:()=>x.createElement(At,{host:e,sessions:t,targets:r,onEject:i,problems:o})}}function D(e){if(typeof e!="object"||e===null)return null;const t=e.documentId;return typeof t=="string"?t:null}function Xt(e){return[{id:"codegen.context.generate",value:{kind:"item",menu:V,command:ie,group:"4_generate",when:K(t=>t.ref!==null&&e.documentOf(t.ref.id)!==null),argsOf:B(t=>({documentId:t.ref?.id}))}}]}function Ht(e,t,r,n=()=>[]){return[{id:ie,titleKey:"command.generate",enabled:P,run(i){const o=D(i)??t.active();if(o===null)return;const a=t.storeFor(o);ne({host:e,targets:r(),documentId:o,store:a,formName:a.get().formName,problems:n()})}},{id:Bt,titleKey:"command.create-fixture",enabled:P,run(i){const o=D(i)??t.active();o!==null&&Tt(e,o).then(a=>{en(e,a)})}}]}function Yt(e,t,r,n){return[{id:Wt,titleKey:"command.refresh-targets",run(){r().then(i=>{n?.info(y(h,"notify.targets-refreshed"),{params:{count:i}})})}},{id:ae,titleKey:"command.eject-template",run(i){const o=Zt(i);o!==null&&kt({host:e,targets:t},o).then(async a=>{Qt(n,a),a.kind==="written"&&(await r(),e.openResource?.(a.id))})}}]}function Zt(e){if(typeof e!="object"||e===null)return null;const t=e.targetId;return typeof t=="string"?t:null}function Qt(e,t){if(e!==null)switch(t.kind){case"written":e.success(y(h,"notify.eject-written"),{params:{name:t.name}});return;case"no-project":e.warning(y(h,"notify.eject-no-project"));return;case"not-a-template":e.info(y(h,"notify.eject-not-a-template"));return;case"read-only":e.error(y(h,"notify.eject-read-only"));return;case"failed":e.error(y(h,"notify.eject-failed"),{params:{message:t.message}});return}}function en(e,t){if(t.kind==="written"){e.openResource?.(t.id);return}console.info("[codegen] фикстура не создана:",t.kind)}function pn(e={}){const t=e.targetPoint??rt,r=e.slot??qt,n=zt();return ke({id:h,activate(i){const o=e.host??Ot(i,e.gaps);for(const[p,g]of Object.entries(It))i.i18n.contribute(p,g);i.subscriptions.push(i.services.register(Et,{print:async(p,g,N)=>{const w=o.kit();return w===null?[]:(await z(O,{schema:p,formName:g,rules:N?.rules,mock:N?.mock,kit:{kit:w,catalog:o.catalog()}})).files.map(({path:se,content:le})=>({path:se,content:le}))}}));const a=()=>wt(i.extensions.get(t).map(p=>p.value));let l=[],c=[];const s=()=>{for(const p of l)p.dispose();l=[]},u=async()=>{s();const p=await xt(o);c=p.problems;for(const g of p.targets){const N=O.find(w=>w.id===g.overrides)?.order;l.push(i.extensions.contribute(t,g,{id:`user:${g.id}`,order:g.order??N??Jt}))}return p.targets.length};i.subscriptions.push({dispose:s}),u(),i.subscriptions.push(o.onDidChangeKit(()=>{u()}));for(const p of O)i.subscriptions.push(i.extensions.contribute(t,p,{id:p.id,order:p.order}));for(const p of Ht(o,n,a,()=>c))i.subscriptions.push(i.commands.register(p));const f={host:o,targets:a},v=i.services.get(Se)??null;for(const p of Yt(o,a,u,v))i.subscriptions.push(i.commands.register(p));for(const p of pt(f,v))i.subscriptions.push(i.commands.register(p));for(const p of[...Xt(o),...ft(a)])i.subscriptions.push(i.extensions.contribute(Te,p.value,{id:p.id}));const m=Lt(o,n,a,r,p=>{i.commands.get(ae)?.run({targetId:p})},()=>c);i.subscriptions.push(i.extensions.contribute(je,m,{id:m.id}))},deactivate(){n.dispose()}})}export{O as BUILTIN_TARGETS,R as CODEGEN_CONTEXT_SUBMENU,It as CODEGEN_MESSAGES,Vt as CODEGEN_PANEL_ID,h as CODEGEN_PLUGIN_ID,rt as CodegenTargetPoint,qt as DEFAULT_CODEGEN_SLOT,ie as GENERATE_COMMAND_ID,C as GENERATE_INTO_COMMAND_ID,jt as KitCapability,S as SourceReadOnlyError,Ht as codegenCommands,pt as codegenContextCommands,ft as codegenContextMenuItems,Xt as codegenDocumentMenuItems,Lt as codegenPanel,Ot as codegenWorkspace,pn as createCodegenPlugin,ee as defaultFormName,H as deliverInto,$e as deliverModule,st as findSchemaIn,ct as generateInto,dt as generateIntoArgs,z as generateModule,mt as notifyOutcome,P as panelVisible,ne as runCodegen,at as schemaCandidates,te as schemaOf};