@appaflytech/zeyrek-ai-mcp 0.0.30 → 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.
- package/.env.example +0 -15
- package/README.md +5 -5
- package/dist/config.js +0 -37
- package/dist/index.js +0 -2
- package/dist/knowledge/backendConstraints.js +1 -18
- package/dist/knowledge/boxSections.js +184 -0
- package/dist/knowledge/componentCatalog.js +232 -562
- package/dist/knowledge/componentEvents.js +21 -141
- package/dist/knowledge/layoutSummary.js +2 -140
- package/dist/knowledge/normalize.js +67 -236
- package/dist/knowledge/outlines.js +0 -36
- package/dist/knowledge/policy.js +4 -18
- package/dist/knowledge/reservedTables.js +0 -79
- package/dist/knowledge/rules.js +21 -319
- package/dist/knowledge/schemaGuard.js +0 -11
- package/dist/knowledge/styleResolve.js +38 -55
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/observability/trace.js +3 -6
- package/dist/platform/diagnostics.js +4 -10
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/errors.js +10 -162
- package/dist/platform/http.js +8 -29
- package/dist/platform/responses.js +5 -39
- package/dist/platform/{capture/capture.js → screenshot.js} +519 -105
- package/dist/platform/secrets.js +1 -17
- package/dist/platform/strictArguments.js +12 -68
- package/dist/platform/tokenVault.js +4 -187
- package/dist/resources/examples/layout-app-shell.json +707 -229
- package/dist/resources/examples/page-detail-profile.json +1 -2
- package/dist/resources/examples/page-dynamic-form.json +2 -3
- package/dist/resources/examples/page-flex-sections.json +1 -1
- package/dist/resources/examples/page-html-embed.json +1 -1
- package/dist/resources/examples/workflow-basic.json +2 -8
- package/dist/resources/guides/component.md +4 -91
- package/dist/resources/guides/entity.md +8 -50
- package/dist/resources/guides/expressions.md +5 -14
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/getting-started.md +1 -38
- package/dist/resources/guides/layout.md +58 -55
- package/dist/resources/guides/microservice.md +2 -81
- package/dist/resources/guides/middleware.md +2 -44
- package/dist/resources/guides/page.md +75 -454
- package/dist/resources/guides/theme.md +2 -8
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +1 -58
- package/dist/resources/rules.js +5 -11
- package/dist/resources/schema-fingerprint.json +5 -7
- package/dist/resources/schemas/CreateEntityCommand.json +0 -118
- package/dist/resources/schemas/CreateMicroserviceCommand.json +1 -13
- package/dist/resources/schemas/CreateQueryCommand.json +0 -4
- package/dist/resources/schemas/CreateWorkflowCommand.json +1 -143
- package/dist/resources/schemas/DataJobDto.json +1 -6
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -21
- package/dist/resources/schemas/MicroserviceDto.json +3 -15
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +1 -10
- package/dist/resources/schemas/PreviewWorkflowCommand.json +1 -22
- package/dist/resources/schemas/StepDto.json +1 -22
- package/dist/resources/schemas/UpdateEntityCommand.json +0 -118
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +1 -13
- package/dist/resources/schemas/UpdateQueryCommand.json +0 -4
- package/dist/resources/schemas/UpdateViewCommand.json +2 -0
- package/dist/resources/schemas/UpdateWorkflowCommand.json +1 -143
- package/dist/server.js +1 -27
- package/dist/tools/access.js +2 -369
- package/dist/tools/applications.js +3 -60
- package/dist/tools/common.js +0 -7
- package/dist/tools/components.js +14 -118
- package/dist/tools/datasources.js +3 -3
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +2 -2
- package/dist/tools/designSchemaPatch.js +18 -34
- package/dist/tools/dtos.js +5 -36
- package/dist/tools/entities.js +12 -79
- package/dist/tools/externalComponents.js +5 -26
- package/dist/tools/flows.js +14 -122
- package/dist/tools/folders.js +1 -1
- package/dist/tools/imports.js +2 -5
- package/dist/tools/layouts.js +17 -50
- package/dist/tools/merges.js +1 -1
- package/dist/tools/microservices.js +25 -77
- package/dist/tools/pages.js +112 -465
- package/dist/tools/platformInfo.js +8 -27
- package/dist/tools/projects.js +9 -71
- package/dist/tools/rows.js +13 -69
- package/dist/tools/schemaOps.js +1 -61
- package/dist/tools/screenWrite.js +8 -37
- package/dist/tools/screens.js +5 -95
- package/dist/tools/templates.js +1 -26
- package/dist/tools/translations.js +1 -1
- package/dist/tools/variables.js +5 -11
- package/dist/tools/workflows.js +5 -10
- package/package.json +2 -2
- package/dist/knowledge/access.js +0 -802
- package/dist/knowledge/case.js +0 -41
- package/dist/knowledge/connectDataBind.js +0 -819
- package/dist/knowledge/connectDataDefinition.js +0 -341
- package/dist/knowledge/connectDataExecute.js +0 -93
- package/dist/knowledge/connectDataRules.js +0 -128
- package/dist/knowledge/decision.js +0 -121
- package/dist/knowledge/expressionPrelude.js +0 -59
- package/dist/knowledge/microserviceParameters.js +0 -58
- package/dist/knowledge/mining.js +0 -94
- package/dist/knowledge/mobileComponentCatalog.js +0 -859
- package/dist/knowledge/mobileComponentEvents.js +0 -239
- package/dist/knowledge/platform/lint.js +0 -385
- package/dist/knowledge/platform/mobile.js +0 -142
- package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
- package/dist/knowledge/platform/mobileRules.js +0 -231
- package/dist/knowledge/platform/mobileSpacing.js +0 -82
- package/dist/knowledge/platform/mobileTabs.js +0 -108
- package/dist/knowledge/platform/nativeBoxModel.js +0 -44
- package/dist/knowledge/platform/profile.js +0 -25
- package/dist/knowledge/platform/resolve.js +0 -122
- package/dist/knowledge/platform/web.js +0 -39
- package/dist/knowledge/process.js +0 -510
- package/dist/knowledge/rowFilter.js +0 -43
- package/dist/knowledge/styleResolveNative.js +0 -527
- package/dist/platform/argumentAliases.js +0 -128
- package/dist/platform/bodyFile.js +0 -103
- package/dist/platform/capture/actions.js +0 -333
- package/dist/platform/capture/browser.js +0 -1
- package/dist/platform/capture/console-log.js +0 -122
- package/dist/platform/capture/index.js +0 -11
- package/dist/platform/capture/readiness.js +0 -103
- package/dist/platform/capture/summary.js +0 -77
- package/dist/platform/capture/target.js +0 -5
- package/dist/platform/capture/targets/studio-mobile.js +0 -15
- package/dist/platform/capture/targets/studio-web.js +0 -5
- package/dist/platform/impersonation.js +0 -45
- package/dist/platform/jsonArray.js +0 -24
- package/dist/platform/schemaReadMemory.js +0 -60
- package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
- package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
- package/dist/resources/examples/bpm-satinalma.json +0 -376
- package/dist/resources/examples/connect-data-convert-verify.json +0 -107
- package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
- package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
- package/dist/resources/examples/connect-data-query-params.json +0 -50
- package/dist/resources/examples/connect-data-table-entity.json +0 -147
- package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
- package/dist/resources/examples/mobile-app-shell-drawer.json +0 -243
- package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
- package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
- package/dist/resources/examples/mobile-form-screen.json +0 -365
- package/dist/resources/examples/mobile-list-detail-form.json +0 -672
- package/dist/resources/guides/access.md +0 -796
- package/dist/resources/guides/bpm.md +0 -686
- package/dist/resources/guides/case.md +0 -153
- package/dist/resources/guides/decision.md +0 -185
- package/dist/resources/guides/mobile-layout.md +0 -193
- package/dist/resources/guides/mobile.md +0 -495
- package/dist/resources/read.js +0 -41
- package/dist/resources/schemas/AccessExplanationDto.json +0 -144
- package/dist/resources/schemas/AccessMatrixDto.json +0 -170
- package/dist/resources/schemas/AccessPermissionDto.json +0 -57
- package/dist/resources/schemas/AccessPolicyDto.json +0 -223
- package/dist/resources/schemas/AccessResourceDto.json +0 -86
- package/dist/resources/schemas/AppSessionDto.json +0 -53
- package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
- package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
- package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
- package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
- package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
- package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
- package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
- package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
- package/dist/resources/schemas/DecisionDto.json +0 -302
- package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
- package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
- package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
- package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
- package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
- package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
- package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
- package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
- package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
- package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
- package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
- package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
- package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
- package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
- package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
- package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
- package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
- package/dist/tools/accessOperations.js +0 -135
- package/dist/tools/accessPolicies.js +0 -170
- package/dist/tools/accessRuntime.js +0 -203
- package/dist/tools/bpm.js +0 -343
- package/dist/tools/bpmGovernance.js +0 -266
- package/dist/tools/bpmOperations.js +0 -230
- package/dist/tools/bpmReporting.js +0 -154
- package/dist/tools/bpmRouting.js +0 -150
- package/dist/tools/bpmRuntime.js +0 -396
- package/dist/tools/case.js +0 -178
- package/dist/tools/caseRuntime.js +0 -89
- package/dist/tools/connectData.js +0 -449
- package/dist/tools/connectors.js +0 -193
- package/dist/tools/decisions.js +0 -206
- package/dist/tools/mobile.js +0 -221
- package/dist/tools/modules.js +0 -48
- package/dist/tools/organizationStructure.js +0 -137
- package/dist/tools/profileWrite.js +0 -92
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MOBİLE ÖZGÜ olay yükleri. Mobil komponentlerin ÇOĞU web şemasını genişletir ve
|
|
3
|
-
* olayları web sözleşmesindedir (`componentEvents.ts`) — bu dosya yalnız web'de
|
|
4
|
-
* karşılığı OLMAYAN komponentler içindir (`app-bar` gibi kabuk komponentleri).
|
|
5
|
-
*
|
|
6
|
-
* Okuyucu önce buraya, sonra web sözlüğüne bakar; parity testi
|
|
7
|
-
* (`test/mobile-component-parity.test.ts`) her mobil olayın iki sözlükten
|
|
8
|
-
* birinde karşılanmasını zorunlu tutar.
|
|
9
|
-
*/
|
|
10
|
-
const NO_DATA = { payload: {} };
|
|
11
|
-
export const mobileComponentEventContracts = {
|
|
12
|
-
'choice-chips': {
|
|
13
|
-
change: {
|
|
14
|
-
payload: {
|
|
15
|
-
value: 'string | number | boolean | Array — seçenek ÖZGÜN tipinde (değeri `34` yazılmış seçenek sayı yayar). `multiple` açıkken seçili değerlerin DİZİSİ (`[34, "a"]`); tek kipte seçili çipe yeniden dokunmak boş metin (`""`) yayar. Devre dışı seçenek olay yaymaz.'
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
// Web ikizinin yükü metindir (`e.currentTarget.value`); mobil seçeneği ÖZGÜN tipinde yayar (f-06, `optionEmitValues`).
|
|
20
|
-
// İki platformda aynı koşul için karşılaştırmayı metne çevirin: `String(self.value) === '34'`.
|
|
21
|
-
radio: {
|
|
22
|
-
change: {
|
|
23
|
-
payload: {
|
|
24
|
-
value: 'string | number | boolean — seçilen seçeneğin ÖZGÜN değeri (değeri `34` yazılmış seçenek sayı yayar; web aynı seçimi `"34"` metni olarak yayar)'
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
checkboxgroup: {
|
|
29
|
-
change: {
|
|
30
|
-
payload: {
|
|
31
|
-
value: 'Array — seçili seçeneklerin ÖZGÜN değerleri (`["su", 9]`; web metin dizisi yayar). Seçeneklerde olmayan eski değer metin kalır'
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
tooltip: {
|
|
36
|
-
open: NO_DATA
|
|
37
|
-
},
|
|
38
|
-
calendar: {
|
|
39
|
-
mount: NO_DATA,
|
|
40
|
-
change: {
|
|
41
|
-
payload: {
|
|
42
|
-
value: "string 'yyyy-MM-ddT00:00:00' | null — seçilen gün (aralıkta başlangıç); web datepicker'ın biçimi: yerel duvar saati, gece yarısı, dilim eki yok",
|
|
43
|
-
endValue: "string 'yyyy-MM-ddT00:00:00' | null — YALNIZ mode: 'range'; ilk basışta null, ikinci basışta bitiş günü"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
stack: {
|
|
48
|
-
mount: NO_DATA
|
|
49
|
-
},
|
|
50
|
-
'list-item': {
|
|
51
|
-
click: NO_DATA
|
|
52
|
-
},
|
|
53
|
-
fab: {
|
|
54
|
-
click: NO_DATA
|
|
55
|
-
},
|
|
56
|
-
'photo-viewer': {
|
|
57
|
-
change: { payload: { index: 'number — gösterilen fotoğrafın sırası (0 tabanlı); makine index prop\'una yazar' } },
|
|
58
|
-
close: { payload: {}, reads: 'kapat düğmesi ya da geri; makine isOpen\'ı kapatır' },
|
|
59
|
-
share: { payload: { row: 'gösterilen satırın tamamı (images dizisindeki nesne)', index: 'number — satırın sırası' }, reads: 'Paylaş düğmesi yalnız bu olay bir akışa bağlıysa çizilir; paylaşmak akışın işidir' },
|
|
60
|
-
delete: { payload: { row: 'gösterilen satırın tamamı', index: 'number — satırın sırası' }, reads: 'Sil düğmesi yalnız bu olay bir akışa bağlıysa çizilir; satırı silmek ve listeyi yenilemek akışın işidir' }
|
|
61
|
-
},
|
|
62
|
-
timer: {
|
|
63
|
-
mount: NO_DATA,
|
|
64
|
-
tick: { payload: { value: 'number — gösterilen saniye (geri sayımda kalan, kronometrede geçen); makine value prop\'una yazar' } },
|
|
65
|
-
finish: { payload: { isRunning: 'false — geri sayım 0\'a indi; makine isRunning\'i kapatır' } }
|
|
66
|
-
},
|
|
67
|
-
audio: {
|
|
68
|
-
mount: NO_DATA,
|
|
69
|
-
play: { payload: { isPlaying: "true — çalma başladı (denetim ya da akış); makine isPlaying'i yazar" } },
|
|
70
|
-
pause: { payload: { isPlaying: "false — çalma durdu (denetim, akış, bitiş ya da tarayıcının otomatik oynatma reddi); makine isPlaying'i yazar" } },
|
|
71
|
-
ended: { payload: { isPlaying: "false — ses sona vardı (loop kapalıyken, pause'tan sonra); makine isPlaying'i kapatır" } }
|
|
72
|
-
},
|
|
73
|
-
lottie: {
|
|
74
|
-
mount: NO_DATA,
|
|
75
|
-
finish: { payload: { isPlaying: "false — döngüsüz animasyon bitti; makine isPlaying'i kapatır, yeniden true yazmak baştan oynatır" } }
|
|
76
|
-
},
|
|
77
|
-
webview: {
|
|
78
|
-
mount: NO_DATA,
|
|
79
|
-
load: { payload: {}, reads: "her tamamlanan yüklemede yayılır (izin verilen gezinmeden sonra da); cihazda yüklenemeyen sayfada yayılmaz (yerine error), web'de tarayıcı engellenen çerçevede de yayar" },
|
|
80
|
-
navigate: { payload: { url: "string — sayfanın gitmek istediği adres; makine url prop'una yazar (self.url). allowNavigation kapalıyken (varsayılan) gezinme engellenir; adres yalnız kullanıcının dokunduğu bağlantıda sistemde açılır" } },
|
|
81
|
-
message: {
|
|
82
|
-
payload: { data: "string — sayfanın window.ReactNativeWebView.postMessage(metin) ile yolladığı metin, olduğu gibi; makine data prop'una yazar (self.data)" },
|
|
83
|
-
reads: "iki yönlü köprü: sayfa window.ngApps.emit(name, data) çağırırsa yük olayın params'ında gelir — akış event.name ve event.data okur (self.data yazılmaz)"
|
|
84
|
-
},
|
|
85
|
-
error: { payload: {}, reads: "cihazda sayfa yüklenemeyince (ağ hatası) yayılır, görünüm yer tutucu çizer; web'de pratikte gelmez (iframe gibi)" }
|
|
86
|
-
},
|
|
87
|
-
html: {
|
|
88
|
-
mount: NO_DATA,
|
|
89
|
-
message: {
|
|
90
|
-
payload: {},
|
|
91
|
-
reads: "belgenin window.ngApps.emit(name, data) çağrısı; yük olayın params'ındadır — akış event.name (ileti adı) ve event.data (veri) okur. actions satırının akışı ise fireEvent(key, data) ile koşar: event.name = key, event.data = veri"
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
map: {
|
|
95
|
-
mount: NO_DATA,
|
|
96
|
-
markerClick: { payload: { markerId: "string — dokunulan işaretçinin `id`si (boşsa listedeki sırası); makine markerId prop'una yazar (self.markerId). Başlığı ya da açıklaması olan işaretçide balon da açılır" } },
|
|
97
|
-
regionChange: {
|
|
98
|
-
payload: {
|
|
99
|
-
latitude: 'number — kullanıcının bıraktığı merkezin enlemi (6 basamak)',
|
|
100
|
-
longitude: 'number — merkezin boylamı (6 basamak, −180…180)',
|
|
101
|
-
zoom: 'number — web harita ölçeği (2 basamak, 1–19)'
|
|
102
|
-
},
|
|
103
|
-
reads: "yalnız kullanıcının sürüklemesi ya da yakınlaştırması bitince yayılır; akışın yazdığı görünüm ve kutu boyu değişimi yaymaz. Makine üç prop'u da yazar (self.latitude, self.longitude, self.zoom)"
|
|
104
|
-
},
|
|
105
|
-
press: {
|
|
106
|
-
payload: {
|
|
107
|
-
latitude: 'number — yerin enlemi: tek işaretçi varsa o işaretçi, yoksa görünümün merkezi',
|
|
108
|
-
longitude: 'number — yerin boylamı',
|
|
109
|
-
mapsUrl: "string — yeri cihazın harita uygulamasında açan adres (iOS Apple Haritalar https://maps.apple.com/?ll=…&q=<ad>, Android geo:<lat>,<lng>?q=…(<ad>), web Google Haritalar araması)"
|
|
110
|
-
},
|
|
111
|
-
reads: "işaretçi dışına dokunuşta yayılır (interactive: false önizlemede bütün yüzey). Makine YALNIZ mapsUrl'i düğüme yazar (self.mapsUrl) — koordinat yazılsaydı harita kayardı; koordinat event.data'dadır. Tarif: redirect isRaw: true, path: '<harita>.mapsUrl'"
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
markdown: {
|
|
115
|
-
mount: NO_DATA,
|
|
116
|
-
linkClick: {
|
|
117
|
-
payload: {
|
|
118
|
-
href: "string — dokunulan bağlantının ham adresi; şema süzülmeden gelir (dışarıda yalnız http(s), mailto, tel açılır)"
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
'app-bar': {
|
|
123
|
-
clickBack: NO_DATA,
|
|
124
|
-
clickMenu: NO_DATA,
|
|
125
|
-
clickAction: { payload: { key: 'string (eylemin key alanı; yoksa dizideki sırası)' } }
|
|
126
|
-
},
|
|
127
|
-
'safe-area': {
|
|
128
|
-
mount: NO_DATA
|
|
129
|
-
},
|
|
130
|
-
// Web `container` yalnız `mount` yayar; `click` mobile-only (plans/mobil-plantcare-acigi f-04, K1).
|
|
131
|
-
container: {
|
|
132
|
-
click: NO_DATA
|
|
133
|
-
},
|
|
134
|
-
// Arama varyantının "Vazgeç"i (plans/mobil-plantcare-acigi f-05): değer temizlenir, klavye kapanır.
|
|
135
|
-
textinput: {
|
|
136
|
-
cancel: NO_DATA
|
|
137
|
-
},
|
|
138
|
-
'scroll-view': {
|
|
139
|
-
mount: NO_DATA,
|
|
140
|
-
scrollEnd: NO_DATA,
|
|
141
|
-
refresh: NO_DATA,
|
|
142
|
-
scroll: {
|
|
143
|
-
payload: {
|
|
144
|
-
y: 'number — dikey kaydırma konumu (yatay kaydırıcıda x)',
|
|
145
|
-
contentHeight: 'number — içeriğin boyu (yatayda contentWidth)',
|
|
146
|
-
viewportHeight: 'number — görünen alanın boyu (yatayda viewportWidth)'
|
|
147
|
-
},
|
|
148
|
-
reads: '100 ms seyreltmeli; yalnız bu olaya akış bağlıyken yayılır. Düğüme scrollY (scrollX) de yazılır'
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
'grouped-list': {
|
|
152
|
-
mount: NO_DATA,
|
|
153
|
-
change: {
|
|
154
|
-
payload: {
|
|
155
|
-
selectedIndex: 'number — dokunulan öğenin rows içindeki DÜZ indeksi (bölüm içi değil); aynı öğeye yeniden dokununca yayılmaz. Makine selectedIndex\'i yazar, akışta tıklanan satır <liste>.selectedItem'
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
itemPress: {
|
|
159
|
-
payload: {
|
|
160
|
-
index: 'number (öğenin rows içindeki düz indeksi, 0 tabanlı)',
|
|
161
|
-
row: 'object (öğenin satır verisi)'
|
|
162
|
-
},
|
|
163
|
-
reads: 'yalnız itemPressable açıkken; önce change { selectedIndex } yayılır. Öğe şablonu basılabilir bir bileşense (list-item, button) dokunuş onun click\'ine gider, itemPress yayılmaz'
|
|
164
|
-
},
|
|
165
|
-
swipe: {
|
|
166
|
-
payload: {
|
|
167
|
-
key: 'string (kaydırma eyleminin key alanı)',
|
|
168
|
-
index: 'number (öğenin rows içindeki düz indeksi, 0 tabanlı)',
|
|
169
|
-
row: 'object (öğenin satır verisi)'
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
sectionPress: {
|
|
173
|
-
payload: {
|
|
174
|
-
key: 'string — bölüm anahtarı (tarih değerinde yerel gün YYYY-AA-GG)',
|
|
175
|
-
title: 'string — bölüm başlığı (anahtar; boş alanlı satırların bölümünde otherSectionTitle)',
|
|
176
|
-
count: 'number — bölümdeki öğe sayısı',
|
|
177
|
-
items: 'object[] — bölümdeki satırların verisi'
|
|
178
|
-
},
|
|
179
|
-
reads: 'bölüm başlığına dokununca; yük başlık şablonunun Section ifadesiyle aynı nesnedir'
|
|
180
|
-
},
|
|
181
|
-
selectionChange: {
|
|
182
|
-
payload: {
|
|
183
|
-
selectedIndices: 'number[] — seçili satırların rows içindeki DÜZ indeksleri, sıralı',
|
|
184
|
-
count: 'number — seçili satır sayısı'
|
|
185
|
-
},
|
|
186
|
-
reads: 'yalnız selectionMode: multiple (ya da longPressSelects ile açılınca); akış event.data.selectedIndices / event.data.count okur, düğümün selectedIndices/selectedItems değeri de yazılır'
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
eventcalendar: {
|
|
190
|
-
mount: NO_DATA,
|
|
191
|
-
dateClick: {
|
|
192
|
-
payload: { date: "string 'yyyy-MM-dd'", rows: 'object[] — o güne düşen kaynak satırlar (mobil)' },
|
|
193
|
-
reads: "self'e yazılmaz — event.data ile oku; ay ve hafta görünümünde güne dokununca"
|
|
194
|
-
},
|
|
195
|
-
eventClick: {
|
|
196
|
-
payload: { id: 'string', title: 'string', row: 'kaynak satırın TAMAMI' },
|
|
197
|
-
reads: "self'e yazılmaz — event.data ile oku; gün çizelgesinde bloğa dokununca"
|
|
198
|
-
},
|
|
199
|
-
monthChange: {
|
|
200
|
-
payload: {
|
|
201
|
-
month: 'number (1-TABANLI)',
|
|
202
|
-
year: 'number',
|
|
203
|
-
view: "'month' | 'week' | 'day'",
|
|
204
|
-
start: "string 'yyyy-MM-dd' (görünen ilk gün)",
|
|
205
|
-
end: "string 'yyyy-MM-dd' (görünen son gün)"
|
|
206
|
-
},
|
|
207
|
-
reads: "self'e yazılmaz — event.data ile oku; oklar, yatay kaydırma ve Bugün ile her görünümde"
|
|
208
|
-
},
|
|
209
|
-
viewChange: {
|
|
210
|
-
payload: { view: "'month' | 'week' | 'day'", start: "string 'yyyy-MM-dd'", end: "string 'yyyy-MM-dd'" },
|
|
211
|
-
reads: "self'e yazılmaz — event.data ile oku; görünüm düğmesiyle"
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
'floating-container': {
|
|
215
|
-
mount: NO_DATA
|
|
216
|
-
},
|
|
217
|
-
repeater: {
|
|
218
|
-
swipe: {
|
|
219
|
-
payload: {
|
|
220
|
-
key: 'string (kaydırma eyleminin key alanı)',
|
|
221
|
-
index: 'number (satırın sırası, 0 tabanlı)',
|
|
222
|
-
row: 'object (satırın verisi)'
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
itemPress: {
|
|
226
|
-
payload: {
|
|
227
|
-
index: 'number (satırın sırası, 0 tabanlı)',
|
|
228
|
-
row: 'object (satırın verisi)'
|
|
229
|
-
}
|
|
230
|
-
},
|
|
231
|
-
selectionChange: {
|
|
232
|
-
payload: {
|
|
233
|
-
selectedIndices: 'number[] — seçili satırların rows içindeki DÜZ indeksleri, sıralı',
|
|
234
|
-
count: 'number — seçili satır sayısı'
|
|
235
|
-
},
|
|
236
|
-
reads: 'yalnız selectionMode: multiple (ya da longPressSelects ile açılınca); akış event.data.selectedIndices / event.data.count okur, düğümün selectedIndices/selectedItems değeri de yazılır'
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
};
|
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
import { IMAGE_SOURCE_PROPS, IMAGE_SOURCE_PROP_NAMES, MOBILE_RULES, REDIRECT_PRESENTATIONS, fileIdImageExpression, missingComponentAdvice, styleReplacement } from './mobileRules.js';
|
|
2
|
-
import { findingLine } from './profile.js';
|
|
3
|
-
import { SURFACE_KEYS } from '../styleResolveNative.js';
|
|
4
|
-
import { DOCUMENT_STYLE_TYPES } from '../styleResolve.js';
|
|
5
|
-
import { listThemeVarNames } from '../themeResolve.js';
|
|
6
|
-
import { closestArgument } from '../../platform/argumentAliases.js';
|
|
7
|
-
function asRecord(value) {
|
|
8
|
-
return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
|
|
9
|
-
}
|
|
10
|
-
function walk(value, visit) {
|
|
11
|
-
if (!Array.isArray(value)) {
|
|
12
|
-
const single = asRecord(value);
|
|
13
|
-
if (single)
|
|
14
|
-
walk([single], visit);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
for (const entry of value) {
|
|
18
|
-
const node = asRecord(entry);
|
|
19
|
-
if (!node)
|
|
20
|
-
continue;
|
|
21
|
-
visit(node);
|
|
22
|
-
walk(node.children, visit);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Koda ya da çeviriye bağlı prop: değeri çalışma anında `ref`'ten gelir, `data` yalnız tasarım yedeğidir.
|
|
27
|
-
* Belge CSS'i alan tipte (`DOCUMENT_STYLE_TYPES`) bağlı `style` metin sayılır — şema onu uzun metin ilan eder.
|
|
28
|
-
*/
|
|
29
|
-
function boundWrapper(value) {
|
|
30
|
-
const wrapped = asRecord(value);
|
|
31
|
-
return wrapped !== undefined && (wrapped.type === 'code' || wrapped.type === 'translation');
|
|
32
|
-
}
|
|
33
|
-
function propValue(value) {
|
|
34
|
-
const wrapped = asRecord(value);
|
|
35
|
-
return wrapped && 'data' in wrapped && typeof wrapped.type === 'string' ? wrapped.data : value;
|
|
36
|
-
}
|
|
37
|
-
/** Prop'un bağlı ifadesi: code sarmalının `ref`i (yoksa `data`sı) ya da çıplak şablon metni. */
|
|
38
|
-
function boundExpression(value) {
|
|
39
|
-
if (typeof value === 'string')
|
|
40
|
-
return value;
|
|
41
|
-
const wrapped = asRecord(value);
|
|
42
|
-
if (!wrapped || wrapped.type !== 'code')
|
|
43
|
-
return undefined;
|
|
44
|
-
const expression = wrapped.ref ?? wrapped.data;
|
|
45
|
-
return typeof expression === 'string' ? expression : undefined;
|
|
46
|
-
}
|
|
47
|
-
function label(node) {
|
|
48
|
-
return String(node.elementId ?? node.name ?? node.type ?? '?');
|
|
49
|
-
}
|
|
50
|
-
const GRID_LAYOUTS = new Set(['grid', 'cssgrid']);
|
|
51
|
-
const RELATIVE_UNIT = /\b\d*\.?\d+(em|rem)\b|calc\(/i;
|
|
52
|
-
/**
|
|
53
|
-
* THEME-012: mobil çizici `var(--ng-…)`'yi yalnız temanın yaydığı değişkenlerden çözer
|
|
54
|
-
* (`compose-native-style.ts` `resolveThemeToken`); web'deki bileşen yerel değişkenleri (`--ng-nav-bg` …)
|
|
55
|
-
* cihazda yoktur. Temada olmayan, yedeksiz bir ad çözülmez: zemin saydam kalır ve iOS gölgesi her çocuğa
|
|
56
|
-
* düşer (koşu 37 K37-c, `var(--ng-surface)`). Web profili bu kuralı koşmaz.
|
|
57
|
-
*/
|
|
58
|
-
const STYLE_GROUP_PROPS = new Set(['surfaceStyle', 'typographyStyle', 'headerStyle']);
|
|
59
|
-
const UNRESOLVED_TOKEN = /var\(\s*(--ng-[\w-]+)\s*\)/g;
|
|
60
|
-
let themeVarNames;
|
|
61
|
-
function nearestThemeVar(name) {
|
|
62
|
-
themeVarNames ??= listThemeVarNames();
|
|
63
|
-
const tail = `-${name.replace(/^--ng-/, '')}`;
|
|
64
|
-
const bySuffix = themeVarNames.filter(known => known.endsWith(tail)).sort((left, right) => left.length - right.length)[0];
|
|
65
|
-
return bySuffix ?? closestArgument(name, themeVarNames);
|
|
66
|
-
}
|
|
67
|
-
function unknownThemeTokens(value) {
|
|
68
|
-
themeVarNames ??= listThemeVarNames();
|
|
69
|
-
const found = [];
|
|
70
|
-
const visit = (entry) => {
|
|
71
|
-
const unwrapped = propValue(entry);
|
|
72
|
-
if (typeof unwrapped === 'string') {
|
|
73
|
-
for (const match of unwrapped.matchAll(UNRESOLVED_TOKEN)) {
|
|
74
|
-
const name = match[1] ?? '';
|
|
75
|
-
if (!themeVarNames.includes(name))
|
|
76
|
-
found.push(name);
|
|
77
|
-
}
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
for (const nested of Object.values(asRecord(unwrapped) ?? {}))
|
|
81
|
-
visit(nested);
|
|
82
|
-
};
|
|
83
|
-
visit(value);
|
|
84
|
-
return [...new Set(found)];
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Profilin taşınabilirlik bulguları. Web profilinde HER ZAMAN boş dizi döner — web davranışı
|
|
88
|
-
* değişmez (G1 kilidi); bulgular yalnız mobil profilde üretilir.
|
|
89
|
-
*/
|
|
90
|
-
export function profileFindings(profile, input) {
|
|
91
|
-
if (profile.platform === 'web')
|
|
92
|
-
return [];
|
|
93
|
-
const findings = [];
|
|
94
|
-
const nodes = [];
|
|
95
|
-
const blockNodes = [];
|
|
96
|
-
const gridNodes = [];
|
|
97
|
-
const styleHits = new Map();
|
|
98
|
-
const unknownTypes = new Map();
|
|
99
|
-
const shellNodes = new Map();
|
|
100
|
-
const legacyNodes = [];
|
|
101
|
-
const fileIdSources = [];
|
|
102
|
-
const nodeTypes = new Map();
|
|
103
|
-
const floorImages = [];
|
|
104
|
-
const namelessIconButtons = [];
|
|
105
|
-
const unknownTokens = [];
|
|
106
|
-
const hit = (map, key, target) => map.set(key, [...(map.get(key) ?? []), target]);
|
|
107
|
-
const inspectTokens = (target, value) => {
|
|
108
|
-
for (const name of unknownThemeTokens(value)) {
|
|
109
|
-
const nearest = nearestThemeVar(name);
|
|
110
|
-
unknownTokens.push(nearest ? `${target}: ${name} → ${nearest}` : `${target}: ${name}`);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
const inspectAppearance = (target, appearance) => {
|
|
114
|
-
if (!appearance)
|
|
115
|
-
return;
|
|
116
|
-
for (const key of profile.appearance.ignoredKeys) {
|
|
117
|
-
const value = appearance[key];
|
|
118
|
-
if (value !== undefined && value !== null && value !== '' && value !== 0)
|
|
119
|
-
hit(styleHits, key, target);
|
|
120
|
-
}
|
|
121
|
-
for (const key of ['widthString', 'heightString']) {
|
|
122
|
-
const value = appearance[key];
|
|
123
|
-
if (typeof value === 'string' && RELATIVE_UNIT.test(value))
|
|
124
|
-
hit(styleHits, `${key} (${value})`, target);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
// Mobil derleyici yüzey grubunun yalnız bilinen alanlarını okur; kalan alt anahtar cihazda düşer.
|
|
128
|
-
// `data`sız sarmal (`{ type: 'code', ref }`) bütün grubu bir ifadeye bağlar: denetlenecek alt anahtar yoktur.
|
|
129
|
-
const inspectSurface = (target, value) => {
|
|
130
|
-
const raw = asRecord(value);
|
|
131
|
-
if (raw && typeof raw.type === 'string' && !('data' in raw))
|
|
132
|
-
return;
|
|
133
|
-
for (const [key, wrapped] of Object.entries(asRecord(propValue(value)) ?? {})) {
|
|
134
|
-
const value = propValue(wrapped);
|
|
135
|
-
if (!SURFACE_KEYS.has(key) && value !== undefined && value !== null && value !== '')
|
|
136
|
-
hit(styleHits, `surfaceStyle.${key}`, target);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
const inspectNode = (node) => {
|
|
140
|
-
const target = label(node);
|
|
141
|
-
const type = String(node.type ?? '');
|
|
142
|
-
const props = asRecord(node.props) ?? {};
|
|
143
|
-
nodes.push(node);
|
|
144
|
-
nodeTypes.set(target, type);
|
|
145
|
-
for (const prop of IMAGE_SOURCE_PROPS[type] ?? []) {
|
|
146
|
-
const expression = fileIdImageExpression(boundExpression(props[prop]) ?? '');
|
|
147
|
-
if (expression)
|
|
148
|
-
fileIdSources.push({ target: `${target}.${prop}`, expression });
|
|
149
|
-
}
|
|
150
|
-
if (Array.isArray(node.blocks) && node.blocks.length > 0 && !profile.layout.blocksMeaningful)
|
|
151
|
-
blockNodes.push(target);
|
|
152
|
-
const layout = propValue(props.layout);
|
|
153
|
-
if (typeof layout === 'string' && GRID_LAYOUTS.has(layout))
|
|
154
|
-
gridNodes.push(`${target} (layout:${layout})`);
|
|
155
|
-
inspectAppearance(target, asRecord(node.appearance));
|
|
156
|
-
inspectSurface(target, props.surfaceStyle);
|
|
157
|
-
for (const group of STYLE_GROUP_PROPS)
|
|
158
|
-
inspectTokens(target, props[group]);
|
|
159
|
-
if (type === 'image' && !imageHasDefiniteHeight(asRecord(node.appearance)))
|
|
160
|
-
floorImages.push(target);
|
|
161
|
-
if (type === 'button' && propValue(props.size) === 'icon' && !String(propValue(props.ariaLabel) ?? '').trim() && !String(propValue(props.text) ?? '').trim()) {
|
|
162
|
-
namelessIconButtons.push(target);
|
|
163
|
-
}
|
|
164
|
-
if (!profile.style.freeStyle) {
|
|
165
|
-
const style = propValue(props.style);
|
|
166
|
-
const documentCss = DOCUMENT_STYLE_TYPES.has(type) && (typeof style === 'string' || boundWrapper(props.style));
|
|
167
|
-
if (!documentCss && ((asRecord(style) && Object.keys(style).length > 0) || (typeof style === 'string' && style.trim() !== '')))
|
|
168
|
-
hit(styleHits, 'style', target);
|
|
169
|
-
}
|
|
170
|
-
if (!profile.style.hoverStyle) {
|
|
171
|
-
const hover = propValue(props.hoverStyle);
|
|
172
|
-
if (asRecord(hover) && Object.keys(hover).length > 0)
|
|
173
|
-
hit(styleHits, 'hoverStyle', target);
|
|
174
|
-
}
|
|
175
|
-
if (type && input.catalog && input.catalog.size > 0 && !input.catalog.has(type) && !profile.shell.legacyShellNodes.has(type))
|
|
176
|
-
hit(unknownTypes, type, target);
|
|
177
|
-
if (type && profile.shell.suggestions[type])
|
|
178
|
-
hit(shellNodes, type, target);
|
|
179
|
-
if (type && profile.shell.legacyShellNodes.has(type))
|
|
180
|
-
legacyNodes.push(`${target} (${type})`);
|
|
181
|
-
};
|
|
182
|
-
walk(input.nodes, inspectNode);
|
|
183
|
-
const savedTypes = new Map();
|
|
184
|
-
walk(input.savedNodes, node => savedTypes.set(label(node), String(node.type ?? '')));
|
|
185
|
-
for (const op of input.ops ?? []) {
|
|
186
|
-
const target = typeof op.target === 'string' ? op.target : '?';
|
|
187
|
-
if (op.op === 'add_component')
|
|
188
|
-
walk(op.component, inspectNode);
|
|
189
|
-
if (op.op === 'set_block' && !profile.layout.blocksMeaningful)
|
|
190
|
-
blockNodes.push(`${target} (set_block)`);
|
|
191
|
-
if (op.op === 'set_appearance')
|
|
192
|
-
inspectAppearance(target, asRecord(op.appearance));
|
|
193
|
-
if (op.op === 'replace_prop' || op.op === 'set_binding') {
|
|
194
|
-
const prop = String(op.prop ?? '');
|
|
195
|
-
const value = propValue(op.value);
|
|
196
|
-
const targetType = nodeTypes.get(target) ?? savedTypes.get(target) ?? '';
|
|
197
|
-
const documentCss = DOCUMENT_STYLE_TYPES.has(targetType) && (typeof value === 'string' || op.op === 'set_binding' || boundWrapper(op.value));
|
|
198
|
-
if (prop === 'layout' && typeof value === 'string' && GRID_LAYOUTS.has(value))
|
|
199
|
-
gridNodes.push(`${target} (layout:${value})`);
|
|
200
|
-
if (prop === 'style' && !profile.style.freeStyle && !documentCss)
|
|
201
|
-
hit(styleHits, 'style', target);
|
|
202
|
-
if (prop === 'hoverStyle' && !profile.style.hoverStyle)
|
|
203
|
-
hit(styleHits, 'hoverStyle', target);
|
|
204
|
-
if (prop === 'surfaceStyle')
|
|
205
|
-
inspectSurface(target, op.value);
|
|
206
|
-
if (STYLE_GROUP_PROPS.has(prop))
|
|
207
|
-
inspectTokens(target, op.value);
|
|
208
|
-
// MOB-011: var olan düğümün tipi op'ta yok — tip biliniyorsa (aynı yazımda eklendi) ona, yoksa prop adına bakılır.
|
|
209
|
-
const knownType = nodeTypes.get(target);
|
|
210
|
-
const imageProp = knownType === undefined ? IMAGE_SOURCE_PROP_NAMES.has(prop) : (IMAGE_SOURCE_PROPS[knownType] ?? []).includes(prop);
|
|
211
|
-
const expression = imageProp ? fileIdImageExpression(boundExpression(typeof op.expression === 'string' ? op.expression : op.value) ?? '') : undefined;
|
|
212
|
-
if (expression)
|
|
213
|
-
fileIdSources.push({ target: `${target}.${prop}`, expression });
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
if (blockNodes.length > 0 || gridNodes.length > 0) {
|
|
217
|
-
findings.push({
|
|
218
|
-
code: MOBILE_RULES['MOB-001'].id,
|
|
219
|
-
severity: 'warn',
|
|
220
|
-
message: [
|
|
221
|
-
blockNodes.length > 0 ? `blok (12 sütun ızgara) mobil çizerde yok sayılır: ${[...new Set(blockNodes)].join(', ')}` : '',
|
|
222
|
-
gridNodes.length > 0 ? `grid/cssgrid yerleşimi yok, kap flex çizilir: ${gridNodes.join(', ')}` : ''
|
|
223
|
-
].filter(Boolean).join(' · ') + ". Sıra dizi indeksinden, yerleşim flex'ten gelir (direction/gap/horizontalAlign). Yazım platforma gitti.",
|
|
224
|
-
guide: "platform_guide('mobile')"
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
for (const [key, targets] of styleHits) {
|
|
228
|
-
findings.push({
|
|
229
|
-
code: MOBILE_RULES['MOB-002'].id,
|
|
230
|
-
severity: 'warn',
|
|
231
|
-
target: [...new Set(targets)].join(', '),
|
|
232
|
-
message: `'${key}' mobilde çizilmez — ${styleReplacement(key.split(' ')[0] ?? key)}. Yazım platforma gitti.`
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
if (unknownTokens.length > 0) {
|
|
236
|
-
findings.push({
|
|
237
|
-
code: 'THEME-012',
|
|
238
|
-
severity: 'warn',
|
|
239
|
-
target: [...new Set(unknownTokens.map(entry => entry.split(':')[0] ?? entry))].join(', '),
|
|
240
|
-
message: `temada tanımlı olmayan jeton cihazda çözülmez (zemin saydam kalır, iOS gölgesi içeriğe düşer): ${[...new Set(unknownTokens)].join(' · ')}. Geçerli adlar temanın yaydığı değişkenlerdir (theme_get); bilerek kullanıyorsanız yedek verin: var(--ad, #fff). Yazım platforma gitti.`,
|
|
241
|
-
guide: "platform_guide('theme')"
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
for (const [type, targets] of unknownTypes) {
|
|
245
|
-
findings.push({
|
|
246
|
-
code: MOBILE_RULES['MOB-003'].id,
|
|
247
|
-
severity: 'warn',
|
|
248
|
-
target: [...new Set(targets)].join(', '),
|
|
249
|
-
message: missingComponentAdvice(type)
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
for (const [type, targets] of shellNodes) {
|
|
253
|
-
findings.push({
|
|
254
|
-
code: MOBILE_RULES['MOB-004'].id,
|
|
255
|
-
severity: 'warn',
|
|
256
|
-
target: [...new Set(targets)].join(', '),
|
|
257
|
-
message: `'${type}' web kabuğudur, mobil uygulamada karşılığı: ${profile.shell.suggestions[type]}`,
|
|
258
|
-
guide: "examples/mobile-app-shell-{tab,stack,drawer}.json"
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
if (floorImages.length > 0) {
|
|
262
|
-
findings.push({
|
|
263
|
-
code: MOBILE_RULES['MOB-012'].id,
|
|
264
|
-
severity: 'info',
|
|
265
|
-
target: floorImages.join(', '),
|
|
266
|
-
message: "görselin boyu belirsiz, 96 dp taban boyla çizilir — boy verin (heightType: 'fixed' + heightString ya da 'fill': görsel kabuğu doldurur) ya da oran verin (appearance.aspectRatio + heightType: 'auto' + widthType 'fill'/'fixed')",
|
|
267
|
-
guide: "platform_guide('mobile')"
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
if (namelessIconButtons.length > 0) {
|
|
271
|
-
findings.push({
|
|
272
|
-
code: MOBILE_RULES['MOB-013'].id,
|
|
273
|
-
severity: 'info',
|
|
274
|
-
target: namelessIconButtons.join(', '),
|
|
275
|
-
message: "ikon boyundaki düğmenin adı yok — size: 'icon' metni çizmez ve ekran okuyucu ikonun ligatür adını (ör. 'notifications') okur; ariaLabel verin (ör. 'Bildirimler')",
|
|
276
|
-
guide: "platform_guide('mobile')"
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
if (legacyNodes.length > 0) {
|
|
280
|
-
findings.push({
|
|
281
|
-
code: MOBILE_RULES['MOB-007'].id,
|
|
282
|
-
severity: 'warn',
|
|
283
|
-
target: legacyNodes.join(', '),
|
|
284
|
-
message: "sekme çubuğu ve çekmece menüsü katalog bileşeni değildir, çizer bu düğümleri yok sayar — sekmeler Ayarlar › Sekmeler'den (application_update properties.mobile.tabs), çekmece 'drawer' widget'ı + app-bar.menuTarget"
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
if (fileIdSources.length > 0) {
|
|
288
|
-
const sample = fileIdSources[0]?.expression ?? '';
|
|
289
|
-
const object = sample.replace(/\??\.value(\s*\}\})$/, '$1');
|
|
290
|
-
findings.push({
|
|
291
|
-
code: MOBILE_RULES['MOB-011'].id,
|
|
292
|
-
severity: 'warn',
|
|
293
|
-
target: fileIdSources.map(source => source.target).join(', '),
|
|
294
|
-
message: `${[...new Set(fileIdSources.map(source => `'${source.expression}'`))].join(', ')} '.value' ile bitiyor — kayıttan okunan FILE alanı { type: 'ref', value: <dosya id>, absolute_path: <url> } döner ve '.value' dosya KİMLİĞİDİR (GUID), görsel çizilmez. Nesnenin kendisini verin ('${object}') ya da '.absolute_path' yazın. Gateway alan tipini sayfa şemasından bilemez: yol FILE alanı değilse (ör. URL taşıyan metin alanı) uyarıyı yok sayın. Yazım platforma gitti.`,
|
|
295
|
-
guide: "platform_guide('mobile') §Dosya ve fotoğraf"
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
const infoSteps = new Map();
|
|
299
|
-
const badPresentation = new Map();
|
|
300
|
-
walkSteps(input.steps, step => {
|
|
301
|
-
const type = String(step.type ?? '');
|
|
302
|
-
if (profile.steps.infoOnly.has(type))
|
|
303
|
-
hit(infoSteps, type, String(step.stepId ?? step.name ?? '?'));
|
|
304
|
-
// MOB-008: sunum biçimi yalnız `redirect`te anlamlı ve kümesi kapalı.
|
|
305
|
-
// Alan YOKSA bulgu yok — varsayılan `push` ve yazımların çoğu onu yazmaz.
|
|
306
|
-
if (type !== 'redirect')
|
|
307
|
-
return;
|
|
308
|
-
const args = asRecord(step.args);
|
|
309
|
-
const presentation = args?.presentation;
|
|
310
|
-
if (presentation === undefined || presentation === null || presentation === '')
|
|
311
|
-
return;
|
|
312
|
-
if (!REDIRECT_PRESENTATIONS.has(String(presentation))) {
|
|
313
|
-
hit(badPresentation, String(presentation), String(step.stepId ?? step.name ?? '?'));
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
for (const [value, stepIds] of badPresentation) {
|
|
317
|
-
findings.push({
|
|
318
|
-
code: MOBILE_RULES['MOB-008'].id,
|
|
319
|
-
severity: 'warn',
|
|
320
|
-
target: stepIds.join(', '),
|
|
321
|
-
message: `redirect.presentation '${value}' tanınmıyor — ${[...REDIRECT_PRESENTATIONS].join(' | ')} bekleniyor. Backend doğrulayıcısı 422 döner; geçse bile çizer 'push'a düşer.`,
|
|
322
|
-
guide: "platform_guide('mobile')"
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
for (const [type, stepIds] of infoSteps) {
|
|
326
|
-
findings.push({
|
|
327
|
-
code: MOBILE_RULES['MOB-005'].id,
|
|
328
|
-
severity: 'info',
|
|
329
|
-
target: stepIds.join(', '),
|
|
330
|
-
message: type === 'download'
|
|
331
|
-
? "mobil uygulamada 'download' tarayıcı indirmesi yapmaz: adres dönen yanıt Linking.openURL ile açılır, ikili gövde (JSON değil) önbelleğe yazılıp paylaşım sayfasında (expo-sharing) açılır"
|
|
332
|
-
: "mobil uygulamada 'setcookie' çerez yazmaz, cihaz deposuna (storage, expo-sqlite/kv-store) eşlenir — okuyan ifadeler aynı çalışır"
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
return findings;
|
|
336
|
-
}
|
|
337
|
-
function walkSteps(value, visit) {
|
|
338
|
-
if (!Array.isArray(value))
|
|
339
|
-
return;
|
|
340
|
-
for (const entry of value) {
|
|
341
|
-
const step = asRecord(entry);
|
|
342
|
-
if (!step)
|
|
343
|
-
continue;
|
|
344
|
-
visit(step);
|
|
345
|
-
walkSteps(step.steps, visit);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
/** Bulguları `layoutWarnings[]` satırlarına çevirir. */
|
|
349
|
-
export function findingLines(findings) {
|
|
350
|
-
return findings.map(findingLine);
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* MOB-014: yazılan değişkenlerden, profilin barındırıcısının depo vermediği saklama türünü taşıyanlar.
|
|
354
|
-
* Kararı platform adı değil profilin `state.storageKinds` ekseni verir; `profileFindings`'ten ayrı
|
|
355
|
-
* durur çünkü o yalnız mobil profilde bulgu üretir, bu kural kümenin boş olduğu profilde tetiklenir.
|
|
356
|
-
*/
|
|
357
|
-
export function stateStorageFindings(profile, entries) {
|
|
358
|
-
const ignored = entries.filter(entry => entry.storage !== undefined && !profile.state.storageKinds.has(entry.storage));
|
|
359
|
-
if (ignored.length === 0)
|
|
360
|
-
return [];
|
|
361
|
-
return [{
|
|
362
|
-
code: MOBILE_RULES['MOB-014'].id,
|
|
363
|
-
severity: MOBILE_RULES['MOB-014'].severity,
|
|
364
|
-
target: ignored.map(entry => `'${entry.key}'`).join(', '),
|
|
365
|
-
message: `saklama türü (${[...new Set(ignored.map(entry => entry.storage))].join(', ')}) ${profile.platform} uygulamasında uygulanmıyor: tür kayda yazıldı ama bu platformun çalışma zamanı depo vermez — state bellekte çalışır, sayfa yeniden açılınca varsayılana döner`,
|
|
366
|
-
guide: "platform_guide('mobile') §Kalıcı state"
|
|
367
|
-
}];
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Görselin boyu belli mi — mobil `imageFrameStyle` sırası: kabuktan (`fixed` + ölçülebilir `heightString`,
|
|
371
|
-
* ya da `fill`) ya da orandan (`aspectRatio` + `heightType: 'auto'` + genişlik `fill`/`fixed`+ölçü).
|
|
372
|
-
* Değilse görsel 96 dp taban boyla çizilir (MOB-012). Koşu bulgusu: `fixed`le kurulan görseller boşluk
|
|
373
|
-
* bıraktı, doğru kalıp yalnız bileşen açıklamasında yazıyordu (plans/mobil-plantcare-acigi g-10 adım 3).
|
|
374
|
-
*/
|
|
375
|
-
function imageHasDefiniteHeight(appearance) {
|
|
376
|
-
if (!appearance)
|
|
377
|
-
return false;
|
|
378
|
-
// Çizicinin `cssLength`'i: sayı, `Npx` ya da `N%` — birimsiz dize ölçülemez.
|
|
379
|
-
const measurable = (value) => typeof value === 'number' || (typeof value === 'string' && /^\d+(\.\d+)?(px|%)$/.test(value.trim()));
|
|
380
|
-
const heightType = appearance.heightType;
|
|
381
|
-
if (heightType === 'fill' || (heightType === 'fixed' && measurable(appearance.heightString)))
|
|
382
|
-
return true;
|
|
383
|
-
const definiteWidth = appearance.widthType === 'fill' || (appearance.widthType === 'fixed' && measurable(appearance.widthString));
|
|
384
|
-
return Number(appearance.aspectRatio) > 0 && heightType === 'auto' && definiteWidth;
|
|
385
|
-
}
|