@appaflytech/zeyrek-ai-mcp 0.0.31 → 0.0.32

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 (205) hide show
  1. package/.env.example +0 -15
  2. package/README.md +5 -5
  3. package/dist/config.js +0 -37
  4. package/dist/index.js +0 -2
  5. package/dist/knowledge/backendConstraints.js +1 -18
  6. package/dist/knowledge/boxSections.js +184 -0
  7. package/dist/knowledge/componentCatalog.js +233 -568
  8. package/dist/knowledge/componentEvents.js +21 -141
  9. package/dist/knowledge/layoutSummary.js +2 -140
  10. package/dist/knowledge/normalize.js +67 -236
  11. package/dist/knowledge/outlines.js +0 -36
  12. package/dist/knowledge/policy.js +4 -18
  13. package/dist/knowledge/reservedTables.js +0 -79
  14. package/dist/knowledge/rules.js +21 -366
  15. package/dist/knowledge/schemaGuard.js +0 -11
  16. package/dist/knowledge/styleResolve.js +38 -55
  17. package/dist/knowledge/themeResolve.js +3 -3
  18. package/dist/observability/trace.js +3 -6
  19. package/dist/platform/diagnostics.js +4 -10
  20. package/dist/platform/domSummary.js +1 -1
  21. package/dist/platform/errors.js +10 -162
  22. package/dist/platform/http.js +8 -29
  23. package/dist/platform/responses.js +5 -39
  24. package/dist/platform/{capture/capture.js → screenshot.js} +519 -105
  25. package/dist/platform/secrets.js +1 -17
  26. package/dist/platform/strictArguments.js +12 -68
  27. package/dist/platform/tokenVault.js +4 -187
  28. package/dist/resources/examples/layout-app-shell.json +707 -229
  29. package/dist/resources/examples/middleware-authenticate.json +1 -1
  30. package/dist/resources/examples/page-detail-profile.json +1 -2
  31. package/dist/resources/examples/page-dynamic-form.json +2 -3
  32. package/dist/resources/examples/page-flex-sections.json +1 -1
  33. package/dist/resources/examples/page-html-embed.json +1 -1
  34. package/dist/resources/examples/workflow-basic.json +2 -8
  35. package/dist/resources/guides/component.md +5 -92
  36. package/dist/resources/guides/entity.md +8 -50
  37. package/dist/resources/guides/expressions.md +5 -14
  38. package/dist/resources/guides/functions.md +1 -1
  39. package/dist/resources/guides/getting-started.md +1 -38
  40. package/dist/resources/guides/layout.md +58 -55
  41. package/dist/resources/guides/merge.md +3 -37
  42. package/dist/resources/guides/microservice.md +2 -87
  43. package/dist/resources/guides/middleware.md +4 -68
  44. package/dist/resources/guides/page.md +75 -456
  45. package/dist/resources/guides/theme.md +2 -8
  46. package/dist/resources/guides/translation.md +1 -1
  47. package/dist/resources/guides/workflow.md +1 -58
  48. package/dist/resources/rules.js +5 -11
  49. package/dist/resources/schema-fingerprint.json +5 -7
  50. package/dist/resources/schemas/CreateEntityCommand.json +0 -118
  51. package/dist/resources/schemas/CreateMicroserviceCommand.json +1 -13
  52. package/dist/resources/schemas/CreateQueryCommand.json +0 -4
  53. package/dist/resources/schemas/CreateWorkflowCommand.json +1 -146
  54. package/dist/resources/schemas/DataJobDto.json +1 -6
  55. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -21
  56. package/dist/resources/schemas/MicroserviceDto.json +3 -15
  57. package/dist/resources/schemas/PreviewMicroserviceCommand.json +1 -10
  58. package/dist/resources/schemas/PreviewWorkflowCommand.json +1 -25
  59. package/dist/resources/schemas/StepDto.json +1 -25
  60. package/dist/resources/schemas/UpdateEntityCommand.json +0 -118
  61. package/dist/resources/schemas/UpdateMicroserviceCommand.json +1 -13
  62. package/dist/resources/schemas/UpdateQueryCommand.json +0 -4
  63. package/dist/resources/schemas/UpdateViewCommand.json +2 -0
  64. package/dist/resources/schemas/UpdateWorkflowCommand.json +1 -146
  65. package/dist/server.js +1 -27
  66. package/dist/tools/access.js +2 -369
  67. package/dist/tools/applications.js +3 -60
  68. package/dist/tools/common.js +0 -7
  69. package/dist/tools/components.js +14 -118
  70. package/dist/tools/datasources.js +3 -3
  71. package/dist/tools/dependencies.js +1 -1
  72. package/dist/tools/deployments.js +3 -38
  73. package/dist/tools/designSchemaPatch.js +18 -34
  74. package/dist/tools/dtos.js +5 -36
  75. package/dist/tools/entities.js +12 -79
  76. package/dist/tools/externalComponents.js +5 -26
  77. package/dist/tools/flows.js +14 -122
  78. package/dist/tools/folders.js +1 -1
  79. package/dist/tools/imports.js +2 -5
  80. package/dist/tools/layouts.js +17 -50
  81. package/dist/tools/merges.js +2 -2
  82. package/dist/tools/microservices.js +25 -77
  83. package/dist/tools/pages.js +112 -465
  84. package/dist/tools/platformInfo.js +8 -27
  85. package/dist/tools/projects.js +9 -71
  86. package/dist/tools/rows.js +13 -69
  87. package/dist/tools/schemaOps.js +1 -61
  88. package/dist/tools/screenWrite.js +8 -37
  89. package/dist/tools/screens.js +5 -95
  90. package/dist/tools/templates.js +1 -26
  91. package/dist/tools/translations.js +1 -1
  92. package/dist/tools/variables.js +5 -11
  93. package/dist/tools/workflows.js +5 -10
  94. package/package.json +1 -1
  95. package/dist/knowledge/access.js +0 -802
  96. package/dist/knowledge/case.js +0 -41
  97. package/dist/knowledge/connectDataBind.js +0 -819
  98. package/dist/knowledge/connectDataDefinition.js +0 -341
  99. package/dist/knowledge/connectDataExecute.js +0 -93
  100. package/dist/knowledge/connectDataRules.js +0 -128
  101. package/dist/knowledge/decision.js +0 -121
  102. package/dist/knowledge/expressionPrelude.js +0 -59
  103. package/dist/knowledge/microserviceParameters.js +0 -58
  104. package/dist/knowledge/mining.js +0 -94
  105. package/dist/knowledge/mobileComponentCatalog.js +0 -859
  106. package/dist/knowledge/mobileComponentEvents.js +0 -239
  107. package/dist/knowledge/platform/lint.js +0 -385
  108. package/dist/knowledge/platform/mobile.js +0 -142
  109. package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
  110. package/dist/knowledge/platform/mobileRules.js +0 -231
  111. package/dist/knowledge/platform/mobileSpacing.js +0 -82
  112. package/dist/knowledge/platform/mobileTabs.js +0 -108
  113. package/dist/knowledge/platform/nativeBoxModel.js +0 -44
  114. package/dist/knowledge/platform/profile.js +0 -25
  115. package/dist/knowledge/platform/resolve.js +0 -122
  116. package/dist/knowledge/platform/web.js +0 -39
  117. package/dist/knowledge/process.js +0 -510
  118. package/dist/knowledge/rowFilter.js +0 -43
  119. package/dist/knowledge/styleResolveNative.js +0 -527
  120. package/dist/platform/argumentAliases.js +0 -128
  121. package/dist/platform/bodyFile.js +0 -103
  122. package/dist/platform/capture/actions.js +0 -333
  123. package/dist/platform/capture/browser.js +0 -1
  124. package/dist/platform/capture/console-log.js +0 -122
  125. package/dist/platform/capture/index.js +0 -11
  126. package/dist/platform/capture/readiness.js +0 -103
  127. package/dist/platform/capture/summary.js +0 -77
  128. package/dist/platform/capture/target.js +0 -5
  129. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  130. package/dist/platform/capture/targets/studio-web.js +0 -5
  131. package/dist/platform/impersonation.js +0 -45
  132. package/dist/platform/jsonArray.js +0 -24
  133. package/dist/platform/schemaReadMemory.js +0 -60
  134. package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
  135. package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
  136. package/dist/resources/examples/bpm-satinalma.json +0 -376
  137. package/dist/resources/examples/connect-data-convert-verify.json +0 -107
  138. package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
  139. package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
  140. package/dist/resources/examples/connect-data-query-params.json +0 -50
  141. package/dist/resources/examples/connect-data-table-entity.json +0 -147
  142. package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
  143. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -243
  144. package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
  145. package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
  146. package/dist/resources/examples/mobile-form-screen.json +0 -365
  147. package/dist/resources/examples/mobile-list-detail-form.json +0 -672
  148. package/dist/resources/guides/access.md +0 -810
  149. package/dist/resources/guides/bpm.md +0 -691
  150. package/dist/resources/guides/case.md +0 -153
  151. package/dist/resources/guides/decision.md +0 -185
  152. package/dist/resources/guides/mobile-layout.md +0 -193
  153. package/dist/resources/guides/mobile.md +0 -495
  154. package/dist/resources/read.js +0 -41
  155. package/dist/resources/schemas/AccessExplanationDto.json +0 -144
  156. package/dist/resources/schemas/AccessMatrixDto.json +0 -170
  157. package/dist/resources/schemas/AccessPermissionDto.json +0 -57
  158. package/dist/resources/schemas/AccessPolicyDto.json +0 -223
  159. package/dist/resources/schemas/AccessResourceDto.json +0 -86
  160. package/dist/resources/schemas/AppSessionDto.json +0 -53
  161. package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
  162. package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
  163. package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
  164. package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
  165. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
  166. package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
  167. package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
  168. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
  169. package/dist/resources/schemas/DecisionDto.json +0 -302
  170. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
  171. package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
  172. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
  173. package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
  174. package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
  175. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
  176. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
  177. package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
  178. package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
  179. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
  180. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
  181. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
  182. package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
  183. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
  184. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
  185. package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
  186. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
  187. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
  188. package/dist/tools/accessOperations.js +0 -135
  189. package/dist/tools/accessPolicies.js +0 -170
  190. package/dist/tools/accessRuntime.js +0 -203
  191. package/dist/tools/bpm.js +0 -343
  192. package/dist/tools/bpmGovernance.js +0 -266
  193. package/dist/tools/bpmOperations.js +0 -230
  194. package/dist/tools/bpmReporting.js +0 -154
  195. package/dist/tools/bpmRouting.js +0 -150
  196. package/dist/tools/bpmRuntime.js +0 -396
  197. package/dist/tools/case.js +0 -178
  198. package/dist/tools/caseRuntime.js +0 -89
  199. package/dist/tools/connectData.js +0 -449
  200. package/dist/tools/connectors.js +0 -193
  201. package/dist/tools/decisions.js +0 -206
  202. package/dist/tools/mobile.js +0 -221
  203. package/dist/tools/modules.js +0 -48
  204. package/dist/tools/organizationStructure.js +0 -137
  205. package/dist/tools/profileWrite.js +0 -92
@@ -1,231 +0,0 @@
1
- import { MOBILE_COMPONENT_NOTES, mobileComponentKnowledge } from '../mobileComponentCatalog.js';
2
- import { STYLE_GROUP_FIELDS } from '../styleResolve.js';
3
- export const MOBILE_RULES = {
4
- 'MOB-001': {
5
- id: 'MOB-001',
6
- severity: 'warn',
7
- sourceRef: 'zeyrek-frontend/packages/ng-apps-ui-native/src/renderer (NativeRenderer blocks okumaz; sıra dizi indeksinden)',
8
- summary: 'Mobil sayfada blok (12 sütun ızgara) ya da grid/cssgrid yerleşimi — çizer yok sayar'
9
- },
10
- 'MOB-002': {
11
- id: 'MOB-002',
12
- severity: 'warn',
13
- sourceRef: 'zeyrek-frontend/packages/ng-apps-ui-native/src/style/compose-native-style.ts (yalnız tipli gruplar derlenir)',
14
- summary: "Mobil sayfada CSS-only alan (className, tooltip, zIndex, serbest style, hoverStyle, em/rem/calc ölçü, surfaceStyle'ın tanımadığı alt anahtar)"
15
- },
16
- 'MOB-003': {
17
- id: 'MOB-003',
18
- severity: 'warn',
19
- sourceRef: 'zeyrek-backend PageSchemaValidator unknown-type (mobil uygulama mobil kataloğa karşı doğrulanır)',
20
- summary: 'Mobil katalogda olmayan bileşen tipi — backend 422 unknown-type ile reddeder'
21
- },
22
- 'MOB-004': {
23
- id: 'MOB-004',
24
- severity: 'warn',
25
- sourceRef: 'plans/mobil-uygulama-expo/05-mobil-ayarlar-ve-gezinme.md §2 (D14)',
26
- summary: "Mobil layout/sayfada web kabuğu (navigations, sidebar, header) — app-bar, sekmeler ayarı ve drawer widget'ı var"
27
- },
28
- 'MOB-005': {
29
- id: 'MOB-005',
30
- severity: 'info',
31
- sourceRef: 'zeyrek-frontend/packages/ng-apps-ui-native/src/runtime/runtime-tasks.ts',
32
- summary: "Mobil uygulamada download paylaşım/açma sayfası açar; setcookie storage'a eşlenir"
33
- },
34
- 'MOB-006': {
35
- id: 'MOB-006',
36
- severity: 'warn',
37
- sourceRef: 'zeyrek-backend/docs/harici-componentler (protokol v1 tarayıcı .mjs; mobil v2 Faz 3); plans/mobil-plantcare-acigi f-20 K7',
38
- summary: "Harici bileşen mobil uygulamada desteklenmiyor — çağrı platforma gitmez; geçici yol 'html' bileşeni"
39
- },
40
- 'MOB-007': {
41
- id: 'MOB-007',
42
- severity: 'warn',
43
- sourceRef: 'plans/mobil-uygulama-expo/05-mobil-ayarlar-ve-gezinme.md §2.2, §2.6 (K13)',
44
- summary: "Sekme ayarı tutarsız ya da layout/sayfada eski tab-bar/drawer-menu düğümü"
45
- },
46
- 'MOB-008': {
47
- id: 'MOB-008',
48
- severity: 'warn',
49
- sourceRef: 'zeyrek-frontend/apps/mobile-runtime/src/navigation/navigation.ts (hrefFor); zeyrek-backend FlowDtoValidator',
50
- summary: "redirect.presentation kümede değil — push | modal | replace dışı değer backend'de 422, çizer push'a düşer"
51
- },
52
- 'MOB-011': {
53
- id: 'MOB-011',
54
- severity: 'warn',
55
- sourceRef: 'zeyrek-backend FilePathMapper.MapFileProperties (okunan FILE alanı { type: ref, value: <dosya id>, absolute_path }); zeyrek-frontend ng-apps-ui-native image-logic.ts resolveImageSource (plans/mobil-kosu-acik-yuksekler f-01)',
56
- summary: "Görsel kaynağı ifadesi '.value' ile bitiyor — kayıttan okunan FILE alanında bu dosya kimliğidir (GUID), görsel çizilmez"
57
- },
58
- 'MOB-012': {
59
- id: 'MOB-012',
60
- severity: 'info',
61
- sourceRef: 'zeyrek-frontend/packages/ng-apps-ui-native/src/components/image/image-logic.ts (imageFrameStyle)',
62
- summary: "Mobil görselin boyu ne kabuktan (fixed + ölçü, fill) ne orandan (aspectRatio + heightType auto + belli genişlik) geliyor — 96 dp taban boyla çizilir"
63
- },
64
- 'MOB-013': {
65
- id: 'MOB-013',
66
- severity: 'info',
67
- sourceRef: 'zeyrek-frontend/packages/ng-apps-ui-native/src/components/button/index.tsx (accessibleLabel: ariaLabel → text → ikon adı)',
68
- summary: "İkon boyunda (size: icon) düğmenin adı yok — ne ariaLabel ne text; ekran okuyucu ikonun ligatür adını (notifications) okur"
69
- },
70
- 'MOB-014': {
71
- id: 'MOB-014',
72
- severity: 'warn',
73
- sourceRef: 'docs/adr/0004-state-saklama-turu.md; zeyrek-frontend/packages/ng-apps-flow/src/machine/state-persistence.ts (depoyu barındırıcı verir; web Runtime.svelte vermez)',
74
- summary: "State saklama türü (storage: device | secure) uygulamanın platformunda uygulanmıyor — kayda yazılır, state bellekte çalışır"
75
- },
76
- 'MOB-015': {
77
- id: 'MOB-015',
78
- severity: 'warn',
79
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S1; zeyrek-frontend/apps/studio/src/features/mobile/mobile-native-canvas.functions.ts (topSafeAreaMissing); apps/mobile-runtime PageScreen.tsx (host payı uygulamaz, plan D15)',
80
- summary: 'Üst güvenli alan tek yerde değil: kabuksuz sayfada/kabukta eksik ya da kabuk verirken sayfada ikinci pay'
81
- },
82
- 'MOB-016': {
83
- id: 'MOB-016',
84
- severity: 'warn',
85
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S3; zeyrek-frontend/apps/mobile-runtime/src/runtime/PageScreen.tsx (sayfa her zaman ScrollView içinde)',
86
- summary: "Kaydırma tek yerde değil: kök `size: grow`, gerekçesiz ya da iç içe dikey scroll-view"
87
- },
88
- 'MOB-017': {
89
- id: 'MOB-017',
90
- severity: 'warn',
91
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S12',
92
- summary: 'Ekranda tek app-bar yok: kabuk verirken sayfada ikinci app-bar ya da app-bar ilk çizilen öğe değil'
93
- },
94
- 'MOB-018': {
95
- id: 'MOB-018',
96
- severity: 'info',
97
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S13',
98
- summary: 'Boş kap: çocuksuz, görünürlüğe bağlı olmayan bırakılabilir kap ekranda boş şerit bırakır'
99
- },
100
- 'MOB-019': {
101
- id: 'MOB-019',
102
- severity: 'warn',
103
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S6/S8; zeyrek-frontend ng-apps-screen-builder spacing.ts + ng-apps-ui-native renderer.functions.ts nodeSpacingStyle (ayna: nativeBoxModel.ts)',
104
- summary: 'Kenar kayması: sütun akışındaki öğe kardeşlerinden içeride/dışarıda başlıyor (zeminsiz kap ya da sarmalayıcı içeriği iter)'
105
- },
106
- 'MOB-020': {
107
- id: 'MOB-020',
108
- severity: 'warn',
109
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S8/S9; renderer.functions.ts containerDirection (yazılmamış yön satır)',
110
- summary: "Genişlik tutarsızlığı: sütunda fill olmayan tam genişlik öğesi ya da form alanı taşıyan satır kabı"
111
- },
112
- 'MOB-021': {
113
- id: 'MOB-021',
114
- severity: 'info',
115
- sourceRef: 'zeyrek-mcp guides/mobile-layout.md §Sözleşme S5/S7/S11',
116
- summary: 'Ölçek dışı değer: özel boşluk ya da sayısal gap 0/4/8/16/24/32 dışında, ham yarıçap, px yazı boyu'
117
- }
118
- };
119
- /**
120
- * MOB-011: dosya nesnesini görsel olarak çizen prop'lar (mobil `resolveImageSource` tüketicileri).
121
- * Hedefin tipi bilinmiyorsa (var olan düğüme `set_binding`) prop adı yeter — `IMAGE_SOURCE_PROP_NAMES`.
122
- */
123
- export const IMAGE_SOURCE_PROPS = {
124
- image: ['src'],
125
- avatar: ['src'],
126
- 'list-item': ['leadingImage'],
127
- card: ['image']
128
- };
129
- export const IMAGE_SOURCE_PROP_NAMES = new Set(Object.values(IMAGE_SOURCE_PROPS).flat());
130
- const TEMPLATE = /\{\{([\s\S]*?)\}\}/g;
131
- const MEMBER_PATH = /^[A-Za-z_$][\w$]*(?:\??\.[A-Za-z_$][\w$]*|\[\s*(?:\d+|'[^']*'|"[^"]*")\s*\])+$/;
132
- /**
133
- * MOB-011'in desen denetimi. Gateway sayfa şemasından bir alanın FILE olduğunu BİLEMEZ (alan tipi
134
- * entity'de, ifade yalnız bir yol) — bu yüzden kural metinseldir ve uyarı düzeyindedir: en az üç
135
- * parçalı bir üye yolu (`item.foto.value`, `pages.x.params.kayit.foto.value`) `.value` ile bitiyorsa
136
- * ilk eşleşen `{{ }}` şablonunu döner. İki parçalı yol (`urlInput.value` — bileşenin kendi değeri) ve
137
- * `.value.value` (dosya alanının base64'ü: `fileInput1.value.value`) eşleşmez.
138
- */
139
- export function fileIdImageExpression(template) {
140
- for (const match of template.matchAll(TEMPLATE)) {
141
- const body = (match[1] ?? '').trim();
142
- if (!MEMBER_PATH.test(body))
143
- continue;
144
- const segments = body.match(/[A-Za-z_$][\w$]*|\[[^\]]*\]/g) ?? [];
145
- if (segments.length >= 3 && segments[segments.length - 1] === 'value' && segments[segments.length - 2] !== 'value')
146
- return match[0];
147
- }
148
- return undefined;
149
- }
150
- /** `redirect` adımının tanıdığı sunum biçimleri (b-01 `StepArgument.Presentation`). */
151
- export const REDIRECT_PRESENTATIONS = new Set(['push', 'modal', 'replace']);
152
- /**
153
- * Bileşen dalgaları (`plans/mobil-uygulama-expo/01-mimari-tasarim.md` §11). MOB-003 bir web bileşeninin
154
- * mobilde NE ZAMAN geleceğini söyler; `web-only` hiç gelmeyecekler ve karşılıkları.
155
- *
156
- * Mobil pakete giren bileşen Dalga 2/3 listesinden DÜŞER: yayında olduğunu mobil sözlükteki kaydı
157
- * söyler (`mobileComponentKnowledge`, parite testiyle `components.json`'a kilitli). Katalog A
158
- * (2026-09-24) sekiz web ikizini buradan indirdi: `radio`, `checkboxgroup`, `slider`, `tabs`, `badge`,
159
- * `avatar`, `progress`, `collapsible-container`; Katalog C (09) Dalga 3'ten `video`, `signature`, `chart`,
160
- * `fileInput` ve `filebutton`ı, Dalga 2'den `datepicker` ve `timepicker`ı (`fileUpload`un sürükle-bırak alanı
161
- * dokunmatikte yok: web'e özgü, karşılığı iki dosya alanı); dil dalgası (plans/mobil-coklu-dil F1, 2026-09-25)
162
- * Dalga 2'den `language-selector`ı; faz 10b (2026-09-27) Dalga 3'ten `datatable`ı; plans/mobil-plantcare-acigi f-11
163
- * (2026-09-27) listede olmayan `daterangepicker`i doğrudan pakete aldı; f-20 (2026-09-28) Dalga 3'ten `html`ı (mobilde
164
- * geçici çözüm kapısı, K7); f-12 (2026-09-28) listede olmayan `eventcalendar`ı (web ikizi, ay/hafta/gün); f-14 (2026-09-28)
165
- * Dalga 3'ten `timeline`ı ve listede olmayan `dropdown-button`ı (web ikizleri) ile mobile özgü `skeleton` ve `photo-viewer`ı. Dalga 1
166
- * listesi artık yalnız `mobileNotes`'un bilgi satırıdır — MOB-003'te yayındaki bileşeni sözlük tanır
167
- * (`box-section` Dalga 1'de ama pakette yok).
168
- */
169
- export const MOBILE_COMPONENT_WAVES = Object.fromEntries([
170
- ...['container', 'box-section', 'form', 'slot', 'text', 'icon', 'image', 'divider', 'spacer', 'button', 'textinput', 'textarea', 'numberinput', 'password', 'checkbox', 'switch', 'dropdown', 'repeater', 'card', 'emptystate', 'form-validation-errors', 'modal', 'drawer', 'app-bar'].map(slug => [slug, 1]),
171
- ...['box', 'phoneinput', 'statcard', 'detailview', 'page-header', 'autocomplete'].map(slug => [slug, 2]),
172
- ...['kanban', 'texteditor', 'stepper', 'tree-view'].map(slug => [slug, 3])
173
- ]);
174
- export const MOBILE_WEB_ONLY = {
175
- iframe: "'webview' (src ya da html; bağlantılar varsayılan olarak sistem tarayıcısında açılır)",
176
- sidebar: "'drawer' widget'ı + app-bar.menuTarget",
177
- navigations: 'Ayarlar › Sekmeler (application_update properties.mobile.tabs)',
178
- header: "'app-bar'",
179
- 'layout-shell': "tek slot'lu sıradan layout + 'app-bar'",
180
- 'layout-region': "tek slot'lu sıradan layout",
181
- 'auth-layout': "tek slot'lu sıradan layout",
182
- popover: "'modal' widget'ı",
183
- 'theme-toggle': "uygulama içi tema ayarı: 'choice-chips' (variant: segmented, Sistem/Açık/Koyu) → storage adımı name: 'zeyrek:theme-mode', value: system | light | dark; barındırıcı temayı anında değiştirir, cihazda kalıcı (seçim yazılmadıysa cihaz teması)",
184
- pagination: "'repeater' + daha fazla yükle düğmesi",
185
- breadcrumb: "yığın gezinmesi (app-bar geri düğmesi)",
186
- fileUpload: "'fileInput' (alan) ya da 'filebutton' (düğme) — dokunmatikte sürükle-bırak yok; ikisi de aynı base64 değeri yazar"
187
- };
188
- const STYLE_REPLACEMENTS = {
189
- className: "yerine surfaceStyle (zemin, kenar, köşe, gölge) ve typographyStyle tipli gruplarını kullanın",
190
- tooltip: "dokunmatikte üzerine gelme yok — düğümü 'tooltip' bileşenine sarın (dokunuşla açılır) ya da açıklamayı metin olarak koyun",
191
- tooltipPosition: "dokunmatikte üzerine gelme yok — 'tooltip' bileşeninde balonun yanı `side` prop'udur",
192
- zIndex: "görselin üstüne rozet/hap/etiket/açıklama bindirmek için 'stack' (ilk çocuk taban, ötekiler üst katman; katman olarak fill×fill bir container koyup kendi hizasıyla köşeye yerleştirin), ekrana sabit içerik (FAB, alt eylem çubuğu, üst şerit) için 'floating-container' (anchor 9 nokta, offsetX/offsetY, fullWidth), kaydırırken üstte kalan başlık için scroll-view çocuğunda states.isSticky, sayfayı örten katman için 'modal' ya da 'drawer' widget'ı",
193
- style: "serbest CSS nesnesi React Native'de çizilmez — surfaceStyle ve typographyStyle tipli gruplarına taşıyın; position/zIndex ile ekrana sabitlemek yerine 'floating-container' kullanın",
194
- hoverStyle: 'dokunmatikte üzerine gelme durumu yok'
195
- };
196
- export function styleReplacement(key) {
197
- if (key.startsWith('surfaceStyle.')) {
198
- const fields = (STYLE_GROUP_FIELDS.surfaceStyle ?? []).map(field => `\`${field}\``).join(', ');
199
- return `yüzey grubunun alanları ${fields} (döndürme derece, ölçek yüzde — 100 aynı boy, kaydırma px)`;
200
- }
201
- return STYLE_REPLACEMENTS[key] ?? 'mobil çizer bu alanı okumaz';
202
- }
203
- export function missingComponentAdvice(slug) {
204
- // Yayındaki bileşen: katalog senkronu bu uygulamaya henüz yazmamış olabilir — "gelecek" demek yanlış olur.
205
- if (Object.hasOwn(mobileComponentKnowledge, slug))
206
- return `'${slug}' mobil pakette var ama bu uygulamanın kataloğunda henüz yok — components-sync mobil kataloğu yazdı mı (component_list)? Yazmadıysa backend 422 unknown-type döner`;
207
- const wave = Object.hasOwn(MOBILE_COMPONENT_WAVES, slug) ? MOBILE_COMPONENT_WAVES[slug] : undefined;
208
- if (wave === 2)
209
- return `'${slug}' web'de var, mobilde Dalga 2 (F6 sonrası) — şimdilik Dalga 1 bileşenleriyle kurun (component_list)`;
210
- if (wave === 3)
211
- return `'${slug}' web'de var, mobilde Faz 3 (ayrı iş) — bu planda mobil karşılığı yok`;
212
- const alternative = Object.hasOwn(MOBILE_WEB_ONLY, slug) ? MOBILE_WEB_ONLY[slug] : undefined;
213
- if (alternative)
214
- return `'${slug}' web'e özgüdür, mobilde gelmeyecek — ${alternative}`;
215
- return `'${slug}' mobil katalogda yok — component_list ile mobil uygulamanın bileşenlerini görün`;
216
- }
217
- /**
218
- * `component_get` mobil uygulamada (G4): kayıt mobil kataloğun satırıdır, davranış notları web
219
- * runtime'ından (`knowledge`), bileşene özgü farklar mobil sözlükten (`mobileKnowledge`) gelir; bu
220
- * liste BÜTÜN mobil bileşenlere geçen notlardır — kural kodlu üç not + `MOBILE_COMPONENT_NOTES`.
221
- */
222
- export function mobileComponentNotes(slug) {
223
- const wave = slug === undefined ? undefined : MOBILE_COMPONENT_WAVES[slug];
224
- return [
225
- "Yerleşim yalnız flex: `layout` prop'u mobil şemalarda yoktur (grid/cssgrid yok), blocks/size yok sayılır, sıra dizi indeksidir; ölçü appearance ile verilir (widthType/heightType — MOB-001).",
226
- "Görünüm tipli gruplarla: surfaceStyle ve typographyStyle React Native stiline derlenir; ham CSS `style` prop'u `html` dışında hiçbir mobil şemada yoktur (`html`'in metin `style`'ı kendi belgesine kapsamlı girer), className, `tooltip` alanı (ipucu için `tooltip` bileşeni), zIndex ve hoverStyle çizilmez (MOB-002). Karşılığı olmayan değer sessizce düşmez, uyarıya yazılır; düğümün gerçek stili: page_runtime_get(resolveStyles) → nativeStyle.",
227
- "Basılabilir bileşen role=\"button\" taşır; page_screenshot click onu kabuğun içinde bulur.",
228
- ...MOBILE_COMPONENT_NOTES,
229
- ...(wave === undefined ? [] : [`Mobil bileşen dalgası: ${wave} (plans/mobil-uygulama-expo §11).`])
230
- ];
231
- }
@@ -1,82 +0,0 @@
1
- import { MOBILE_TRANSPARENT_WRAPPER_TYPES } from '../mobileComponentCatalog.js';
2
- import { PAGE_CONTAINER_ELEMENT_ID } from '../normalize.js';
3
- /**
4
- * Boşluğunu runtime'ın kendisi çözen tipler: kabuk parçaları ve katmanlar margin'siz çizilir
5
- * (`ng-apps-ui-native` `FLUSH_SPACING_TYPES`, `@ng-apps/screen-builder` `HIDE_SPACING_TYPES`). `tooltip`
6
- * f-01'den beri runtime'da da muaf, ama burada bilerek yok: mobil runtime uygulamaya gömülüdür ve f-01'den
7
- * önce derlenmiş uygulamada açık `none` hizayı yine korur.
8
- */
9
- const RUNTIME_FLUSH_TYPES = ['safe-area', 'scroll-view', 'app-bar', 'auth-layout', 'modal', 'drawer'];
10
- export const emptyMobileSpacingFix = () => ({ margin: [], wrappers: [], legacyParents: [] });
11
- /**
12
- * Mizanpaj sözleşmesi S5/S6 (plans/mobil-mizanpaj-dili 02, K3-b): mobilde kardeşler arası boşluk yalnız
13
- * ebeveynin `gap`'inden gelir. Runtime margin tipi yazılmamış düğüme 4 dp verir ve bu her iç içe katmanda
14
- * birikir; yeni düğüme `marginType: 'none'` yazılır. Kardeşleri varsayılan margin'le duran (eski) bir
15
- * kaba eklenen düğüme dokunulmaz — yeni düğüm eskilerden 4 dp kayardı. Saydam sarmalayıcı (`tooltip`)
16
- * içeriğini içeri itmesin diye padding'siz ve tam genişlik yazılır. Açıkça yazılmış değer korunur.
17
- */
18
- export function applyMobileSpacingDefaults(nodes, existingSiblings, fix, parentId = '') {
19
- const list = asNodes(nodes);
20
- // Boşluğunu runtime'ın çözdüğü kardeş (kabuksuz sayfanın `safe_area_top`'u gibi) hizaya karar vermez.
21
- const followsNone = existingSiblings
22
- .filter(sibling => !RUNTIME_FLUSH_TYPES.includes(String(sibling.type ?? '')))
23
- .every(sibling => appearanceOf(sibling).marginType === 'none');
24
- if (!followsNone && list.length > 0 && !fix.legacyParents.includes(parentId))
25
- fix.legacyParents.push(parentId);
26
- for (const node of list) {
27
- const type = String(node.type ?? '');
28
- const appearance = appearanceOf(node);
29
- const id = String(node.elementId ?? type);
30
- if (followsNone && !RUNTIME_FLUSH_TYPES.includes(type) && appearance.marginType === undefined) {
31
- node.appearance = { ...appearance, marginType: 'none' };
32
- fix.margin.push(id);
33
- }
34
- if (MOBILE_TRANSPARENT_WRAPPER_TYPES.includes(type) && (appearance.paddingType === undefined || appearance.widthType === undefined)) {
35
- node.appearance = {
36
- ...appearanceOf(node),
37
- ...(appearance.paddingType === undefined ? { paddingType: 'none' } : {}),
38
- ...(appearance.widthType === undefined ? { widthType: 'fill' } : {})
39
- };
40
- fix.wrappers.push(id);
41
- }
42
- applyMobileSpacingDefaults(node.children, [], fix, id);
43
- }
44
- }
45
- /** `add_component` op'larının (batch içindekiler dâhil) yeni düğümlerine aynı kural; kardeşler kayıtlı ağaçtan. */
46
- export function applyMobileSpacingToOps(ops, savedSchema, fix) {
47
- for (const op of ops) {
48
- if (op.op === 'batch')
49
- applyMobileSpacingToOps(asNodes(op.ops), savedSchema, fix);
50
- if (op.op !== 'add_component' || !op.component || typeof op.component !== 'object')
51
- continue;
52
- const saved = asNodes(savedSchema);
53
- const requested = typeof op.parent === 'string' ? op.parent : 'root';
54
- // Kök ekleme sayfada `page_container`'a gider (yazımda `retargetRootAdds`, kuru koşuda platform).
55
- const parentId = requested === 'root' && findNode(saved, PAGE_CONTAINER_ELEMENT_ID) ? PAGE_CONTAINER_ELEMENT_ID : requested;
56
- const siblings = parentId === 'root' ? saved : asNodes(findNode(saved, parentId)?.children);
57
- applyMobileSpacingDefaults([op.component], siblings, fix, parentId);
58
- }
59
- }
60
- export function mobileSpacingNote(fix) {
61
- return [
62
- ...(fix.margin.length > 0 ? [`mobil: margin tipi yazılmamış ${fix.margin.length} düğüme marginType:'none' yazıldı (${fix.margin.slice(0, 8).join(', ')}${fix.margin.length > 8 ? ', …' : ''}) — kardeşler arası boşluk yalnız ebeveynin gap'inden gelir; runtime'ın varsayılan 4 dp margin'i iç içe katmanlarda birikir (mizanpaj sözleşmesi S5). Bilerek boşluk istediğin düğüme marginType yaz`] : []),
63
- ...(fix.wrappers.length > 0 ? [`mobil: saydam sarmalayıcıya (${fix.wrappers.join(', ')}) paddingType:'none' ve widthType:'fill' yazıldı — padding'i içeriğini kardeşlerinden içeri iterdi (S6)`] : []),
64
- ...(fix.legacyParents.length > 0 ? [`mobil: kardeşleri varsayılan margin'le duran kapta (${fix.legacyParents.join(', ')}) yeni düğümün margin'ine dokunulmadı — eskilerle aynı hizada kalsın diye. Kabı sözleşmeye taşımak için bütün çocuklarına marginType:'none' yazın`] : [])
65
- ];
66
- }
67
- function asNodes(value) {
68
- return Array.isArray(value) ? value.filter((item) => !!item && typeof item === 'object') : [];
69
- }
70
- function appearanceOf(node) {
71
- return node.appearance && typeof node.appearance === 'object' ? node.appearance : {};
72
- }
73
- function findNode(nodes, elementId) {
74
- for (const node of nodes) {
75
- if (node.elementId === elementId)
76
- return node;
77
- const found = findNode(asNodes(node.children), elementId);
78
- if (found)
79
- return found;
80
- }
81
- return undefined;
82
- }
@@ -1,108 +0,0 @@
1
- export const MAX_MOBILE_TABS = 5;
2
- const STYLES = new Set(['default', 'floating', 'custom']);
3
- function record(value) {
4
- return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
5
- }
6
- function text(value) {
7
- return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
8
- }
9
- /** Öğenin sayfa id'si: `{ page }` ya da düz metin (`items: ['id']`). */
10
- function entryPage(entry) {
11
- const item = record(entry);
12
- return item ? text(item.page) : text(entry);
13
- }
14
- /** `Application.properties.mobile.tabs` — ham değer, doğrulanmamış. */
15
- export function readMobileTabs(properties) {
16
- return record(record(properties)?.mobile)?.tabs;
17
- }
18
- /**
19
- * Ham sekme ayarını çizilebilir biçime getirir; çizilecek çubuk yoksa `null` (yığın).
20
- *
21
- * - Nesne değilse, `enabled !== true` ise ya da geçerli öğe kalmadıysa → `null`.
22
- * - `style` bilinmiyorsa `default`; `showLabels` boolean değilse `true`.
23
- * - Öğe `{ page }` ya da düz sayfa id'sidir; sayfası yoksa düşer; `pages` verildiyse orada olmayan
24
- * sayfa düşer; tekrar eden sayfa (ilki kalır) atılır; `MAX_MOBILE_TABS`'tan sonrası kırpılır.
25
- * `label`/`icon` boş metinse yazılmaz.
26
- * - Görünüm alanı yoktur: çubuk temadan çizilir; eski kayıtların `appearance`'ı okunmaz.
27
- * - `customWidgetId` yalnız `custom` türde ve metinse yazılır.
28
- */
29
- export function normalizeMobileTabs(tabs, pages) {
30
- const source = record(tabs);
31
- if (!source || source.enabled !== true)
32
- return null;
33
- const known = pages ? new Set(pages.map(page => page.id)) : undefined;
34
- const seen = new Set();
35
- const items = [];
36
- for (const entry of Array.isArray(source.items) ? source.items : []) {
37
- const item = record(entry);
38
- const page = entryPage(entry);
39
- if (!page || seen.has(page) || (known && !known.has(page)))
40
- continue;
41
- seen.add(page);
42
- const label = text(item?.label);
43
- const icon = text(item?.icon);
44
- items.push({ page, ...(label ? { label } : {}), ...(icon ? { icon } : {}) });
45
- if (items.length === MAX_MOBILE_TABS)
46
- break;
47
- }
48
- if (items.length === 0)
49
- return null;
50
- const style = (typeof source.style === 'string' && STYLES.has(source.style) ? source.style : 'default');
51
- const customWidgetId = style === 'custom' ? text(source.customWidgetId) : undefined;
52
- return {
53
- enabled: true,
54
- style,
55
- items,
56
- ...(customWidgetId ? { customWidgetId } : {}),
57
- showLabels: typeof source.showLabels === 'boolean' ? source.showLabels : true
58
- };
59
- }
60
- /**
61
- * MOB-007 denetimi: ham ayarın normalizasyonda neyi kaybedeceğini ve tutarsızlıklarını söyler.
62
- * Yazım yine platforma gider (D3); bulgular yalnız uyarıdır.
63
- */
64
- export function mobileTabsProblems(tabs, context = {}) {
65
- if (tabs === undefined || tabs === null)
66
- return [];
67
- const source = record(tabs);
68
- if (!source)
69
- return [`properties.mobile.tabs nesne olmalı (gelen: ${Array.isArray(tabs) ? 'dizi' : typeof tabs}) — sekme çubuğu çizilmez, uygulama yığınla açılır`];
70
- const problems = [];
71
- const rawItems = Array.isArray(source.items) ? source.items : undefined;
72
- if (source.enabled !== undefined && typeof source.enabled !== 'boolean')
73
- problems.push(`enabled boolean olmalı (gelen: ${JSON.stringify(source.enabled)}) — true olmayan her değer sekmeleri kapatır`);
74
- if (source.style !== undefined && !(typeof source.style === 'string' && STYLES.has(source.style)))
75
- problems.push(`style '${String(source.style)}' tanınmıyor (default | floating | custom) — 'default' çizilir`);
76
- if (source.items !== undefined && !rawItems)
77
- problems.push('items dizi olmalı — hiçbir sekme çizilmez');
78
- const items = rawItems ?? [];
79
- const pageIds = items.map(entryPage);
80
- if (source.enabled === true && items.length === 0)
81
- problems.push("enabled:true ama items boş — çubuk çizilmez; en az bir sayfa ekleyin ya da enabled:false yazın");
82
- if (items.length > MAX_MOBILE_TABS)
83
- problems.push(`${items.length} sekme var, en çok ${MAX_MOBILE_TABS} çizilir — fazlası kırpılır (${pageIds.slice(MAX_MOBILE_TABS).filter(Boolean).join(', ')})`);
84
- const missingPage = pageIds.filter(id => !id).length;
85
- if (missingPage > 0)
86
- problems.push(`${missingPage} öğede page (sayfa id'si) yok — o öğeler düşer`);
87
- const duplicates = pageIds.filter((id, index) => id && pageIds.indexOf(id) !== index);
88
- if (duplicates.length > 0)
89
- problems.push(`aynı sayfa birden çok sekmede: ${[...new Set(duplicates)].join(', ')} — tekrarlar atılır`);
90
- if (context.pages) {
91
- const known = new Set(context.pages.map(page => page.id));
92
- const unknown = pageIds.filter((id) => Boolean(id) && !known.has(id));
93
- if (unknown.length > 0)
94
- problems.push(`var olmayan sayfa: ${[...new Set(unknown)].join(', ')} — page_list ile id'leri doğrulayın; bu öğeler düşer (item.page slug değil sayfa id'sidir)`);
95
- }
96
- const normalized = normalizeMobileTabs(tabs, context.pages ?? null);
97
- if (normalized && context.homepageId && normalized.items[0]?.page !== context.homepageId) {
98
- problems.push(`açılış sayfası (${context.homepageId}) ilk sekme değil — uygulama açılış sayfasıyla başlar ama çubukta başka sekme seçili görünür; açılış sayfasını items'ın başına alın`);
99
- }
100
- if (normalized?.style === 'custom') {
101
- const widgetId = normalized.customWidgetId;
102
- if (!widgetId)
103
- problems.push("style:'custom' ama customWidgetId yok — özel sekme çubuğu widget'ı seçilmeli (component_list kind:'widget')");
104
- else if (context.widgetIds && !context.widgetIds.has(widgetId))
105
- problems.push(`customWidgetId '${widgetId}' bu mobil uygulamanın widget'ı değil — çubuk yerine uyarı çizilir`);
106
- }
107
- return problems;
108
- }
@@ -1,44 +0,0 @@
1
- import { MOBILE_DROPPABLE_TYPES } from '../mobileComponentCatalog.js';
2
- /**
3
- * Mobil runtime'ın kutu modelinin aynası (MOB-019): bir düğümün sol dış boşluğu ve çocuklarını içeri iten sol
4
- * iç boşluğu. Kaynak `@ng-apps/screen-builder` `spacing.ts` (`resolveSpacing`, sabitler, `HIDE_SPACING_TYPES`),
5
- * `constants.ts` (`NO_PADDING_TYPES`) ve `ng-apps-ui-native` `renderer.functions.ts` (`nodeSpacingStyle`,
6
- * `FLUSH_SPACING_TYPES`). Ayna bayatlarsa `test/native-inset-parity.test.ts` kırmızıya düşer.
7
- */
8
- export const RUNTIME_NORMAL_MARGIN = 4;
9
- export const RUNTIME_NORMAL_PADDING = 10;
10
- export const FLUSH_SPACING_TYPES = ['safe-area', 'scroll-view', 'app-bar', 'tooltip'];
11
- export const HIDE_SPACING_TYPES = ['auth-layout', 'modal', 'drawer'];
12
- export const NO_PADDING_TYPES = ['auth-layout', 'modal', 'drawer'];
13
- export const SHELL_ROOT_TYPES = ['layout', 'layout-shell'];
14
- /** `widthType` yazılmasa da tam genişlik çizilen tipler (`renderer.functions.ts` `FULL_WIDTH_TYPES`, MOB-020). */
15
- export const FULL_WIDTH_TYPES = ['app-bar'];
16
- /** Düğümün sol dış boşluğu (dp). `isWrapper`, katmanlar ve kabuk kökü dış boşluk almaz. */
17
- export function nativeMarginLeft(node) {
18
- const states = (node.states ?? {});
19
- const type = String(node.type ?? '');
20
- if (states.isWrapper || HIDE_SPACING_TYPES.includes(type) || states.isShell || SHELL_ROOT_TYPES.includes(type))
21
- return 0;
22
- return sideValue(node.appearance, 'margin', FLUSH_SPACING_TYPES.includes(type), RUNTIME_NORMAL_MARGIN);
23
- }
24
- /** Bırakılabilir düğümün çocuklarına verdiği sol iç boşluk (dp); `isWrapper` bunu SIFIRLAMAZ (01'de ölçüldü). */
25
- export function nativePaddingLeft(node) {
26
- const states = (node.states ?? {});
27
- const type = String(node.type ?? '');
28
- const droppable = states.isDroppable ?? MOBILE_DROPPABLE_TYPES.includes(type);
29
- if (!droppable || NO_PADDING_TYPES.includes(type) || states.isShell || SHELL_ROOT_TYPES.includes(type))
30
- return 0;
31
- return sideValue(node.appearance, 'padding', FLUSH_SPACING_TYPES.includes(type), RUNTIME_NORMAL_PADDING);
32
- }
33
- /** `resolveSpacing`: tip yoksa (ya da boşsa) `normal`; `custom` kenar değerini, yoksa tek değeri okur. */
34
- function sideValue(appearance, layer, flush, normal) {
35
- const written = appearance?.[`${layer}Type`];
36
- const type = typeof written === 'string' && written !== '' ? written : flush ? 'none' : 'normal';
37
- if (type === 'normal')
38
- return normal;
39
- if (type !== 'custom')
40
- return 0;
41
- const values = appearance?.[`${layer}Values`];
42
- const left = Number(values?.left ?? appearance?.[`${layer}Value`] ?? 0);
43
- return Number.isFinite(left) ? left : 0;
44
- }
@@ -1,25 +0,0 @@
1
- /**
2
- * Değişken kaydının `storage` alanının alabildiği değerler (`docs/adr/0004-state-saklama-turu.md`):
3
- * `device` cihaz deposu, `secure` güvenli depo. Alanın yokluğu bellektir — `memory` kayda yazılmaz.
4
- */
5
- export const STATE_STORAGE_KINDS = ['device', 'secure'];
6
- /**
7
- * Motorun kendi register ettiği adımlar (`@ng-apps/flow` `flow-engine.ts` initialize) — iki
8
- * platformda da koşar. `end` ve `query` hiçbir barındırıcıda yoktur (normalizasyon `end`'i atar).
9
- */
10
- export const ENGINE_STEP_TYPES = ['start', 'setter', 'code', 'condition', 'microservice', 'validation', 'flow-trigger', 'function'];
11
- /**
12
- * Eski adım tipi → koşan karşılığı. `navigate` ile `redirect`'in argümanı aynıdır; web `navigate`'i
13
- * register etmez, yeni mobil runtime onu `redirect` takma adı olarak kaydeder — iki platformda da
14
- * `redirect` kesin üstündür.
15
- */
16
- export const STEP_ALIASES = Object.freeze({ navigate: 'redirect' });
17
- /** Tipli stil grupları iki platformda da çizilir (web CSS'e, mobil RN stiline derler). */
18
- export const TYPED_STYLE_GROUPS = ['surfaceStyle', 'typographyStyle', 'sectionStyle', 'headerStyle', 'valueStyle'];
19
- /** Bulguyu mevcut `layoutWarnings[]` satır biçimine çevirir (`PAGE-010 (uyarı) — …` kalıbı). */
20
- export function findingLine(finding) {
21
- const level = finding.severity === 'info' ? 'bilgi' : 'uyarı';
22
- const target = finding.target ? ` [${finding.target}]` : '';
23
- const guide = finding.guide ? ` (${finding.guide})` : '';
24
- return `${finding.code} (${level})${target} — ${finding.message}${guide}`;
25
- }
@@ -1,122 +0,0 @@
1
- import { mobileProfile } from './mobile.js';
2
- import { webProfile } from './web.js';
3
- export const APPLICATION_TYPE_TTL_MS = 10 * 60_000;
4
- const caches = new WeakMap();
5
- function cacheOf(platform) {
6
- let cache = caches.get(platform);
7
- if (!cache) {
8
- cache = new Map();
9
- caches.set(platform, cache);
10
- }
11
- return cache;
12
- }
13
- /** Backend `ApplicationType` JSON'da açıklama metniyle ('web' | 'mobile') döner; eski sayısal biçim de okunur. */
14
- export function readApplicationPlatform(value) {
15
- if (value === 1 || (typeof value === 'string' && value.toLowerCase() === 'mobile'))
16
- return 'mobile';
17
- if (value === 0 || (typeof value === 'string' && value.toLowerCase() === 'web'))
18
- return 'web';
19
- return undefined;
20
- }
21
- export function profileFor(platform) {
22
- return platform === 'mobile' ? mobileProfile : webProfile;
23
- }
24
- function factsOf(record) {
25
- const platform = readApplicationPlatform(record.type);
26
- const id = typeof record.id === 'string' ? record.id : undefined;
27
- if (!platform || !id)
28
- return undefined;
29
- const homepage = record.homepage && typeof record.homepage === 'object' ? record.homepage.id : undefined;
30
- const homepageId = typeof record.homepageId === 'string' ? record.homepageId : typeof homepage === 'string' ? homepage : undefined;
31
- const properties = record.properties && typeof record.properties === 'object' && !Array.isArray(record.properties)
32
- ? record.properties
33
- : undefined;
34
- return {
35
- id,
36
- platform,
37
- ...(typeof record.slug === 'string' ? { slug: record.slug } : {}),
38
- ...(typeof record.name === 'string' ? { name: record.name } : {}),
39
- ...(typeof record.projectSlug === 'string' ? { projectSlug: record.projectSlug } : {}),
40
- ...(homepageId ? { homepageId } : {}),
41
- ...(properties ? { properties } : {})
42
- };
43
- }
44
- function fresh(entry) {
45
- return entry !== undefined && Date.now() - entry.at < APPLICATION_TYPE_TTL_MS;
46
- }
47
- export async function resolveApplication(platform, applicationId) {
48
- const cache = cacheOf(platform);
49
- const cached = cache.get(applicationId);
50
- if (fresh(cached))
51
- return cached.facts;
52
- try {
53
- const payload = await platform.org('GET', `/applications/${applicationId}`);
54
- const facts = factsOf(((payload?.data ?? payload) ?? {}));
55
- if (facts)
56
- cache.set(applicationId, { facts, at: Date.now() });
57
- return facts;
58
- }
59
- catch {
60
- return undefined;
61
- }
62
- }
63
- export async function resolveProfile(platform, applicationId) {
64
- const application = await resolveApplication(platform, applicationId);
65
- return application
66
- ? { profile: profileFor(application.platform), known: true, application }
67
- : { profile: webProfile, known: false };
68
- }
69
- const SLUG_LOOKUP_PAGE = 50;
70
- /**
71
- * `page_screenshot` ve `page_runtime_get` uygulamayı slug ile tanır. Org listesi `searchTerm` ile
72
- * daraltılır ve slug + proje slug'ı BİREBİR eşleşen kayıt alınır (arama ILIKE'tır, `shop` `shop-2`'yi
73
- * de getirir). B1'den beri liste tip filtresi verilmeyince iki tipi de döner. Aynı slug'ı çok proje
74
- * kullanıyorsa (`mobile`, `admin`) aranan kayıt ilk sayfanın dışında kalabilir: sayfa doluysa ve
75
- * eşleşme yoksa arama proje kimliğiyle tekrarlanır — (proje, slug) tekildir.
76
- */
77
- export async function resolveProfileBySlug(platform, projectSlug, applicationSlug) {
78
- const cache = cacheOf(platform);
79
- const key = `slug:${projectSlug}/${applicationSlug}`;
80
- const cached = cache.get(key);
81
- if (fresh(cached))
82
- return { profile: profileFor(cached.facts.platform), known: true, application: cached.facts };
83
- try {
84
- const search = async (query) => {
85
- const payload = await platform.org('GET', '/applications', { query: { searchTerm: applicationSlug, pageLength: SLUG_LOOKUP_PAGE, ...query } });
86
- return Array.isArray(payload?.data) ? payload.data : [];
87
- };
88
- const matchIn = (rows) => rows.find(row => row.slug === applicationSlug && (row.projectSlug === undefined || row.projectSlug === projectSlug));
89
- const rows = await search({});
90
- let match = matchIn(rows);
91
- if (!match && rows.length >= SLUG_LOOKUP_PAGE) {
92
- const project = await platform.org('GET', `/p/${projectSlug}`);
93
- const projectId = (project?.data ?? project)?.id;
94
- if (typeof projectId === 'string')
95
- match = matchIn(await search({ projectId }));
96
- }
97
- const facts = match ? factsOf(match) : undefined;
98
- if (!facts)
99
- return { profile: webProfile, known: false };
100
- cache.set(key, { facts, at: Date.now() });
101
- return { profile: profileFor(facts.platform), known: true, application: facts };
102
- }
103
- catch {
104
- return { profile: webProfile, known: false };
105
- }
106
- }
107
- /** Yazma araçları uygulamayı değiştirdiğinde (tip, slug, properties) kaydı düşürür. */
108
- export function forgetApplication(platform, applicationId) {
109
- const cache = cacheOf(platform);
110
- if (applicationId === undefined) {
111
- cache.clear();
112
- return;
113
- }
114
- for (const [key, entry] of cache) {
115
- if (key === applicationId || entry.facts.id === applicationId)
116
- cache.delete(key);
117
- }
118
- }
119
- /** Yanıta eklenen alan: tip biliniyorsa `applicationType`, bilinmiyorsa hiçbir şey. */
120
- export function applicationTypeField(resolved) {
121
- return resolved.known ? { applicationType: resolved.profile.platform } : {};
122
- }