@mcamdali/sdkbump 0.0.0-stage → 0.1.3

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 (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.de.md +251 -0
  3. package/README.es.md +252 -0
  4. package/README.fr.md +252 -0
  5. package/README.ja.md +250 -0
  6. package/README.ko.md +250 -0
  7. package/README.md +322 -2
  8. package/README.pt-BR.md +252 -0
  9. package/README.ru.md +252 -0
  10. package/README.tr.md +338 -0
  11. package/README.zh-CN.md +250 -0
  12. package/dist/cli/main.d.ts +2 -0
  13. package/dist/cli/main.js +11 -0
  14. package/dist/cli/run.d.ts +29 -0
  15. package/dist/cli/run.js +111 -0
  16. package/dist/collect/app.d.ts +48 -0
  17. package/dist/collect/app.js +117 -0
  18. package/dist/collect/blank.d.ts +6 -0
  19. package/dist/collect/blank.js +75 -0
  20. package/dist/collect/pbxproj.d.ts +45 -0
  21. package/dist/collect/pbxproj.js +260 -0
  22. package/dist/collect/plist-binary.d.ts +2 -0
  23. package/dist/collect/plist-binary.js +123 -0
  24. package/dist/collect/plist-value.d.ts +15 -0
  25. package/dist/collect/plist-value.js +14 -0
  26. package/dist/collect/plist-xml.d.ts +2 -0
  27. package/dist/collect/plist-xml.js +195 -0
  28. package/dist/collect/plist.d.ts +6 -0
  29. package/dist/collect/plist.js +19 -0
  30. package/dist/collect/regions.d.ts +9 -0
  31. package/dist/collect/regions.js +108 -0
  32. package/dist/collect/sources.d.ts +45 -0
  33. package/dist/collect/sources.js +99 -0
  34. package/dist/core/files.d.ts +22 -0
  35. package/dist/core/files.js +47 -0
  36. package/dist/core/lines.d.ts +2 -0
  37. package/dist/core/lines.js +21 -0
  38. package/dist/core/versions.d.ts +18 -0
  39. package/dist/core/versions.js +63 -0
  40. package/dist/detect/project.d.ts +46 -0
  41. package/dist/detect/project.js +220 -0
  42. package/dist/index.d.ts +26 -0
  43. package/dist/index.js +27 -0
  44. package/dist/model.d.ts +93 -0
  45. package/dist/model.js +2 -0
  46. package/dist/report/index.d.ts +12 -0
  47. package/dist/report/index.js +22 -0
  48. package/dist/report/markdown.d.ts +2 -0
  49. package/dist/report/markdown.js +113 -0
  50. package/dist/report/text.d.ts +27 -0
  51. package/dist/report/text.js +63 -0
  52. package/dist/report/tty.d.ts +7 -0
  53. package/dist/report/tty.js +112 -0
  54. package/dist/rules/check.d.ts +11 -0
  55. package/dist/rules/check.js +253 -0
  56. package/dist/rules/data.d.ts +217 -0
  57. package/dist/rules/data.js +141 -0
  58. package/dist/rules/fixes.d.ts +28 -0
  59. package/dist/rules/fixes.js +161 -0
  60. package/dist/rules/patterns.d.ts +29 -0
  61. package/dist/rules/patterns.js +109 -0
  62. package/dist/rules/query.d.ts +16 -0
  63. package/dist/rules/query.js +50 -0
  64. package/dist/scan.d.ts +10 -0
  65. package/dist/scan.js +115 -0
  66. package/dist/version.d.ts +2 -0
  67. package/dist/version.js +7 -0
  68. package/package.json +69 -4
  69. package/rules/ios27.json +613 -0
  70. package/rules/schema.json +449 -0
@@ -0,0 +1,252 @@
1
+ <!-- i18n-source: README.md@49073c524eb2b7aad433b6794961ec40869c1170 status=reviewed -->
2
+ <!-- brand:start -->
3
+
4
+ <p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg" alt="sdkbump: Checks native iOS, Flutter and React Native apps for the iOS 27 SDK changes and names the fix for each."></picture></p>
5
+
6
+ <!-- lang-selector:start -->
7
+ <p align="center"><a href="README.md">English</a> · <a href="README.tr.md">Türkçe</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a> · <a href="README.es.md">Español</a> · <a href="README.de.md">Deutsch</a> · <a href="README.fr.md">Français</a> · <a href="README.pt-BR.md">Português (Brasil)</a> · <a href="README.ru.md">Русский</a></p>
8
+ <!-- lang-selector:end -->
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml/badge.svg" alt="Status da CI"></a>
12
+ <a href="https://github.com/muhittincamdali/sdkbump/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg" alt="Versão mais recente: v0.1.2"></picture></a>
13
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg" alt="Versão da linguagem: Node.js 22.12+"></picture></a>
14
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg" alt="Licença: MIT"></picture></a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="#início-rápido"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-pt-BR-light.svg" alt="Começar"></picture></a>
19
+ <a href="https://muhittincamdali.github.io/sdkbump/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-pt-BR-light.svg" alt="Documentação"></picture></a>
20
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-pt-BR-light.svg" alt="Guias"></picture></a>
21
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-pt-BR-light.svg" alt="Exemplos"></picture></a>
22
+ </p>
23
+
24
+ > Esta é uma tradução do README em inglês. Se houver diferença, vale a versão em inglês.
25
+
26
+ <!-- brand:end -->
27
+
28
+ Antes de publicar uma versão feita com o Xcode 27: o sdkbump verifica um projeto iOS nativo, Flutter ou React Native/Expo em busca do que o SDK do iOS 27 muda, começando pelo ciclo de vida do UIScene, e diz qual correção se aplica a cada achado. Ele lê os arquivos do seu projeto; não compila, não executa e não altera nada.
29
+
30
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-rn-087-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-rn-087-light.svg"><img src="docs/media/demo-rn-087-light.svg" alt="sdkbump executado em um app React Native 0.87: não abre quando compilado com o SDK do iOS 27; SCN001 sem configuração de cena e SCN002 janela criada no app delegate, com três formas de corrigir"></picture>
31
+
32
+ <sub>Gravado com a CLI real no <a href="fixtures/rn-087">fixture rn-087</a>, um app React Native
33
+ 0.87.1 criado com <code>@react-native-community/cli init</code> (<code>npm run demo</code>).</sub>
34
+
35
+ ## Destaques
36
+
37
+ - **Responde "vai abrir?"** Um app que não declara nenhuma cena compila com o Xcode 27 e depois para na abertura. O sdkbump avisa antes que você descubra isso em um dispositivo de teste e indica os arquivos a alterar.
38
+ - **Nativo, Flutter, React Native e Expo** em um único relatório, com os mesmos IDs de regra, em texto, Markdown ou JSON, e com um código de saída para CI.
39
+ - **A correção que se aplica ao seu projeto**: React Native 0.88 ou um scene delegate escrito à mão, a adesão opcional do Expo SDK 57 ou o SDK 58, a migração automática do Flutter ou os passos manuais (o sdkbump verifica as mesmas condições que o migrador do Flutter), ou a API do SwiftUI para um app SwiftUI.
40
+ - **Também as quebras silenciosas**: métodos do app delegate e opções de inicialização que o UIKit deixa de usar quando o app tem uma cena (links, Handoff, ações rápidas, transições para primeiro e segundo plano) e buscas de janela que deixam de encontrar a janela certa.
41
+ - **Cada afirmação tem uma fonte.** As regras são dados ([rules/ios27.json](rules/ios27.json)) e cada uma cita as próprias páginas da Apple, do Flutter, do React Native ou do Expo; os testes falham se alguma não citar.
42
+ - **Verificado no simulador do iOS 27**: a falha de abertura e a tela preta por trás de SCN001 e SCN002 foram reproduzidas com o Xcode 27.0, e as gravações estão no repositório.
43
+
44
+ ## Início rápido
45
+
46
+ Você precisa do [Node.js](https://nodejs.org/) 22.12 ou posterior (`node --version` mostra a versão; em um Mac, `brew install node` instala). Nada além disso.
47
+
48
+ **1. Abra um terminal na pasta do seu app**, a que tem o `.xcodeproj`, o `pubspec.yaml` ou o `package.json`:
49
+
50
+ ```sh
51
+ cd path/to/YourApp
52
+ ```
53
+
54
+ **2. Execute o sdkbump:**
55
+
56
+ ```sh
57
+ npx @mcamdali/sdkbump
58
+ ```
59
+
60
+ O pacote do npm é `@mcamdali/sdkbump`; o comando que ele instala é `sdkbump`. Um `npx sdkbump` sem escopo não o executa.
61
+
62
+ **3. Leia a primeira linha abaixo do nome do seu projeto.** "Fails to launch when built with the iOS 27 SDK" (não abre quando compilado com o SDK do iOS 27) significa que o app para na abertura até você corrigir os achados **ERROR**; cada um diz qual correção da lista "How to fix" se aplica. Os achados **WARNING** não impedem a abertura, mas deixam de funcionar quando o app tem uma cena. "Launch not determined" (abertura não determinada) significa que o sdkbump não conseguiu ler um Info.plist; as notas no fim do relatório dizem qual e por quê (veja Limites mais abaixo).
63
+
64
+ ## O que muda quando você compila com o SDK do iOS 27
65
+
66
+ Da página da Apple
67
+ [Transitioning to the UIKit scene-based life cycle](https://developer.apple.com/documentation/uikit/transitioning-to-the-uikit-scene-based-life-cycle) (tradução):
68
+
69
+ > A partir do iOS 27, iPadOS 27, Mac Catalyst 27, tvOS 27 e visionOS 27, os apps compilados com o SDK mais recente precisam adotar o ciclo de vida baseado em cenas, ou não abrem.
70
+
71
+ 1. **O app para na abertura se não declarar nenhuma cena.** Sem um `UIApplicationSceneManifest` com uma configuração no Info.plist e sem `application(_:configurationForConnecting:options:)`, o UIKit encerra o processo com a mensagem "UIScene life cycle is required for apps built with this SDK". O compilador não avisa, porque a verificação acontece quando o app inicia. React Native 0.87 e anteriores, Expo SDK 57 sem a adesão opcional e Expo SDK 56 e anteriores criam apps assim; o mesmo vale para apps Flutter que a ferramenta do Flutter não consegue migrar.
72
+ 2. **Com uma cena, o app delegate deixa de receber eventos de interface.** Links, user activities, ações rápidas e as transições ativo/segundo plano vão para o scene delegate, e uma janela criada pelo app delegate nunca é exibida.
73
+
74
+ [Por que compila e mesmo assim trava](docs/guides/why-it-crashes.md) mostra a [matriz de abertura](examples/launch-matrix/README.md) que executamos no simulador do iOS 27.0.
75
+
76
+ ## O que o sdkbump verifica
77
+
78
+ | Regra | Gravidade | Achado | Visto no simulador do iOS 27.0 |
79
+ | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
80
+ | SCN001 | error | Sem configuração de cena: nenhum `UIApplicationSceneManifest` configurado, nenhum `configurationForConnecting`, e não é um `App` do SwiftUI; no Expo sem `ios/`, a versão do SDK e `enableSceneSupport` | para na abertura |
81
+ | SCN002 | error | O app delegate cria a janela com `UIWindow(frame:)` | tela preta quando o app tem uma cena |
82
+ | SCN003 | warning | Métodos do app delegate e chaves de opções de inicialização que o UIKit deixa de usar com cenas (13 no total), a menos que o scene delegate já os trate | `applicationDidEnterBackground(_:)` não é chamado em um app SwiftUI |
83
+ | SCN004 | warning | Buscas de janela por `UIApplication.shared.keyWindow`, `.windows` ou pelo `window` do app delegate | apenas avisos de descontinuação do compilador |
84
+
85
+ Dados das regras `ios27@2026.10.15`, verificados com o Xcode 27.0 (27A266a). Quando o React Native ou o Expo tem `react-native-uiscene-bridge` ou `react-native-xcode27` instalado, os achados que ele trata em tempo de execução aparecem como tratados, com os limites descritos no README dele, e não fazem a execução falhar.
86
+
87
+ ## Instalação
88
+
89
+ Instale o comando `sdkbump` pelo npm (pacote `@mcamdali/sdkbump`):
90
+
91
+ ```sh
92
+ npm i -g @mcamdali/sdkbump
93
+ sdkbump
94
+ ```
95
+
96
+ Em um projeto, `npm install --save-dev @mcamdali/sdkbump` fixa uma versão, e então `npx sdkbump` executa essa cópia. Cada [versão no GitHub](https://github.com/muhittincamdali/sdkbump/releases) também traz o mesmo pacote como `sdkbump-<versão>.tgz`, com um arquivo `SHA256SUMS`; o `npx` o executa pela URL, sem o npm. Uma fórmula do Homebrew para `muhittincamdali/tap` é preparada pelo workflow de publicação (planejada junto com a primeira versão do tap).
97
+
98
+ ## Uso
99
+
100
+ ```text
101
+ sdkbump [path] [options]
102
+ ```
103
+
104
+ | Opção | O que faz |
105
+ | ----------------------- | ------------------------------------------------------------------------------- |
106
+ | `path` | Pasta do projeto ou `.xcodeproj`; o padrão é a pasta atual |
107
+ | `-f, --format <format>` | `tty` (padrão), `markdown` ou `json` |
108
+ | `-o, --output <file>` | Grava o relatório em um arquivo em vez de no terminal |
109
+ | `--fail-on <severity>` | `error` (padrão), `warning`, `info` ou `none`: quando o código de saída é 1 |
110
+ | `--no-color` | Texto simples mesmo em um terminal (`NO_COLOR` e `FORCE_COLOR` são respeitados) |
111
+
112
+ Códigos de saída: `0` nenhum achado não tratado no nível de `--fail-on` ou acima, `1` achados nesse nível ou acima, `2` argumentos inválidos, nenhum projeto iOS encontrado ou um erro inesperado.
113
+
114
+ O sdkbump encontra o app iOS sozinho: um `.xcodeproj` na raiz ou uma pasta abaixo para apps nativos, `ios/` para apps Flutter, React Native e Expo (`example/ios/` para um plugin do Flutter). Ele lê todos os targets de app iOS do arquivo de projeto, o Info.plist que cada um indica (XML ou binário) e os arquivos Swift e Objective-C do app, ignorando Pods, `node_modules`, a saída de compilação e os testes. Apps Expo sem `ios/` são verificados a partir do package.json e do app.json.
115
+
116
+ ### Guardar um relatório em Markdown junto com o código
117
+
118
+ ```sh
119
+ npx @mcamdali/sdkbump --format markdown --output sdkbump.md
120
+ ```
121
+
122
+ ### Usar o relatório JSON em scripts
123
+
124
+ ```sh
125
+ npx @mcamdali/sdkbump --format json > sdkbump.json
126
+ ```
127
+
128
+ Cada achado tem `rule`, `severity`, `file`, `line`, `message`, o `fix` com seus passos e seu guia, `alternatives`, `mitigation` (definido quando um pacote de contorno trata o achado) e `sources`. O formato é `schemaVersion` 0 e pode mudar antes da 1.0. [examples/shell/launch-blockers.sh](examples/shell/launch-blockers.sh) o filtra com `jq`.
129
+
130
+ ### Executar no CI
131
+
132
+ [examples/github-actions/sdkbump.yml](examples/github-actions/sdkbump.yml) adiciona o relatório ao resumo do job de cada pull request que mexe no app iOS e faz o job falhar quando há erros.
133
+
134
+ ### A partir do JavaScript
135
+
136
+ ```js
137
+ import { render, scan } from 'sdkbump';
138
+
139
+ const report = await scan('path/to/app');
140
+ console.log(report.verdict.text);
141
+ console.log(render(report, 'markdown'));
142
+ ```
143
+
144
+ Uma versão executável está em [examples/api/verdicts.mjs](examples/api/verdicts.mjs).
145
+
146
+ ## Demonstração
147
+
148
+ As gravações de terminal vêm da CLI executada nos [fixtures](fixtures/README.md), projetos reais criados com cada toolchain:
149
+
150
+ | Projeto | Gravação |
151
+ | ----------------------------------------------------------- | --------------------------------------------------------------------------------------- |
152
+ | App React Native 0.87.1 | no topo desta página |
153
+ | App Flutter com um AppDelegate personalizado (Flutter 3.24) | [claro](docs/media/demo-flutter-light.svg) · [escuro](docs/media/demo-flutter-dark.svg) |
154
+ | App SwiftUI com um app delegate por adaptador | [claro](docs/media/demo-swiftui-light.svg) · [escuro](docs/media/demo-swiftui-dark.svg) |
155
+
156
+ No simulador do iOS 27.0 (iPhone 17, compilado com o Xcode 27.0), o fixture nativo de UIKit para na abertura, e o mesmo app migrado para um scene delegate abre:
157
+
158
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-simulator-native-uikit-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-simulator-native-uikit-light.svg"><img src="docs/media/demo-simulator-native-uikit-light.svg" alt="scripts/simulator-check.sh native-uikit no simulador do iOS 27.0: não está em execução 4 segundos após a abertura, com a linha do UIKit: Application failed to launch: UIScene life cycle is required for apps built with this SDK"></picture>
159
+
160
+ <p align="center"><img src="docs/media/simulator/launched.png" width="480" alt="Os fixtures native-uikit-scenes e native-swiftui em execução em um simulador de iPhone 17 com iOS 27.0, compilados com o Xcode 27.0"></p>
161
+
162
+ Medido em 15 de outubro de 2026 em um Mac (Apple silicon, M5 Max) com Node.js 26.11 enquanto outros trabalhos rodavam nele: três séries de 100 execuções de `node dist/cli/main.js` nos dez fixtures, incluindo a inicialização do Node.js. As medianas das três séries foram 0,11, 0,12 e 0,19 segundo; a execução mais lenta levou 0,33 segundo. Com a máquina mais carregada, os tempos aumentam.
163
+
164
+ ## Status
165
+
166
+ | Recurso | Status |
167
+ | ------------------------------------------------------------------------------------------------------------------------ | --------------- |
168
+ | Detecção de projetos nativos, Flutter (app e exemplo de plugin), React Native e Expo | funciona |
169
+ | SCN001 a SCN004 no Info.plist e nos fontes Swift/Objective-C do próprio app | funciona |
170
+ | Escolha da correção por ecossistema e versão; verificação da migração automática do Flutter; pacotes de contorno | funciona |
171
+ | Relatórios em terminal, Markdown e JSON; códigos de saída de `--fail-on` | funciona |
172
+ | Dependências: Pods, `node_modules` e fontes de plugins do Flutter, com o nome do pacote | planejado (0.2) |
173
+ | Aviso de contorno SCN005 como regra própria; DPT001 para deployment targets abaixo de 15.0 | planejado (0.2) |
174
+ | `--verify`: compilar e abrir no simulador do iOS 27 a partir da CLI | planejado (0.3) |
175
+ | Árvores de sintaxe de Swift/Objective-C em vez de padrões; verificações de `.app` compilados; descontinuações do SiriKit | planejado (0.5) |
176
+ | `fix --dry-run` para apps nativos, saída SARIF, GitHub Action | planejado (0.8) |
177
+ | Esquema de regras e formato JSON estáveis | planejado (1.0) |
178
+
179
+ ## Limites
180
+
181
+ - **Padrões, não um compilador.** As regras são expressões regulares sobre texto Swift e Objective-C com comentários e strings apagados. Código gerado, escondido atrás de macros ou escrito de um jeito incomum pode passar despercebido ou ser detectado por engano. Árvores de sintaxe estão planejadas (0.5).
182
+ - **Só o código-fonte do próprio app.** Pods, `node_modules`, plugins do Flutter e outras dependências não são lidos, então um plugin que depende de métodos do app delegate que o UIKit não chama mais não é relatado. A verificação de dependências está planejada (0.2).
183
+ - **Configurações de build só do project.pbxproj.** O sdkbump lê `INFOPLIST_FILE` e `GENERATE_INFOPLIST_FILE` do arquivo do projeto e expande `$(SRCROOT)`, `$(PROJECT_DIR)`, `$(TARGET_NAME)` e `$(PRODUCT_NAME)`. Ele não lê arquivos `.xcconfig`, não expande outras configurações de build e não lê um Info.plist fora da pasta do projeto. Quando não consegue ler o Info.plist de um target, o SCN001 é um achado do tipo info e o veredito é "Launch not determined", em vez de um palpite.
184
+ - **Sem arquivo de supressão.** Um achado não pode ser marcado como revisado; `--fail-on` decide quais severidades fazem a execução falhar.
185
+ - **Só arquivos.** O sdkbump não compila nem abre o app; `--verify` está planejado (0.3).
186
+
187
+ ## Documentação
188
+
189
+ Referência da API e guias: [muhittincamdali.github.io/sdkbump](https://muhittincamdali.github.io/sdkbump/).
190
+
191
+ ## Guias
192
+
193
+ - [Por que compila e mesmo assim trava](docs/guides/why-it-crashes.md)
194
+ - [Apps nativos com UIKit e SwiftUI](docs/guides/native-ios.md)
195
+ - [Flutter: um AppDelegate personalizado e plugins](docs/guides/flutter.md)
196
+ - [React Native anterior à 0.88 e Expo anterior ao SDK 58](docs/guides/react-native-expo.md)
197
+ - [Autores de módulos nativos: links e notificações na inicialização a frio](docs/guides/native-module-authors.md)
198
+
199
+ ## Ferramentas relacionadas
200
+
201
+ Outros projetos trabalham na mesma mudança; qual serve depende do que você precisa:
202
+
203
+ - [react-native-uiscene-bridge](https://github.com/Atomics-hub/react-native-uiscene-bridge) e [react-native-xcode27](https://github.com/Atomics-hub/react-native-xcode27) fazem um app React Native ou Expo abrir sem alterações de código, em tempo de execução. Servem quando você ainda não pode atualizar; o sdkbump os reconhece.
204
+ - [auditor-uiscene](https://github.com/Anzell/auditor-uiscene) audita apps Flutter e seus plugins com um script de shell.
205
+ - O migrador do próprio Flutter (`flutter build ios` a partir da 3.41) migra um app Flutter sem modificações.
206
+ - [flutter_spm_doctor](https://pub.dev/packages/flutter_spm_doctor) verifica plugins do Flutter.
207
+
208
+ ## Requisitos
209
+
210
+ | Toolchain | Versão mínima |
211
+ | --------- | ------------- |
212
+ | Node.js | 22.12 |
213
+
214
+ O sdkbump não precisa do Xcode: ele lê arquivos, então também roda no Linux. O CI executa os testes no Node.js 22 e 24 (Linux); localmente, os 280 passam no Node.js 22.23, 24.22 e 26.11 em um Mac (Apple silicon). As gravações do simulador exigem um Mac com Xcode 27 e não fazem parte do CI.
215
+
216
+ ## Arquitetura
217
+
218
+ ```text
219
+ path ─► detectProject native | flutter | react-native | expo; iOS folder; versions
220
+ ─► collectApp iOS app targets from project.pbxproj, their Info.plist (XML or binary),
221
+ Swift and Objective-C sources with comments and strings blanked
222
+ ─► checkApp SCN001…SCN004, fix per ecosystem and version, workaround packages
223
+ rules/ios27.json what each rule says, fixes, sources (validated with zod)
224
+ ─► render tty | markdown | json
225
+ ```
226
+
227
+ - Os padrões de detecção são expressões regulares sobre o texto-fonte com comentários e strings em branco e, onde isso importa, só contam dentro de um app delegate ou de um scene delegate.
228
+ - Os dados das regras ficam separados do código e têm versão (`ios27@2026.10.15`); um teste falha quando uma regra, uma correção ou um contorno não tem fonte.
229
+ - A CLI (`src/cli/`) apenas interpreta os argumentos, escolhe cores e larguras e define o código de saída.
230
+
231
+ ## Roteiro
232
+
233
+ Veja a tabela de [Status](#status): a 0.2 adiciona dependências e deployment targets, a 0.3 a abertura no simulador a partir da CLI, a 0.5 árvores de sintaxe e verificações do app compilado, a 0.8 correções e SARIF, a 1.0 um esquema estável. O [CHANGELOG.md](CHANGELOG.md) lista o que cada versão mudou.
234
+
235
+ ## Perguntas frequentes
236
+
237
+ **Meu app funciona hoje no iOS 27. Ele é afetado?** Se foi compilado com o Xcode 26 ou anterior, a verificação não se aplica a essa compilação: no nosso teste, o mesmo código ligado ao SDK do iOS 26 abriu no simulador do iOS 27. Ela se aplica à sua próxima compilação com o Xcode 27.
238
+
239
+ **O sdkbump substitui o teste em um dispositivo?** Não. Ele lê arquivos. As gravações do simulador neste repositório são do simulador do iOS 27.0; nada aqui foi executado em um dispositivo.
240
+
241
+ **Por que um achado aparece como "tratado"?** Um pacote de contorno no package.json (react-native-uiscene-bridge ou react-native-xcode27) declara uma cena em tempo de execução. O app abre, mas continua sem suporte próprio a cenas; o relatório lista os limites do pacote e a correção de verdade.
242
+
243
+ **O sdkbump altera o meu projeto?** Não. Ele o lê e grava apenas o relatório que você pedir.
244
+
245
+
246
+ ## Como contribuir
247
+
248
+ Contribuições são bem-vindas. Leia o [guia de contribuição](CONTRIBUTING.md) e o [código de conduta](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md) antes de abrir um pull request. Relate problemas de segurança de forma privada, como descrito na [política de segurança](SECURITY.md).
249
+
250
+ ## Licença
251
+
252
+ Publicado sob a licença MIT. Veja [LICENSE](LICENSE).
package/README.ru.md ADDED
@@ -0,0 +1,252 @@
1
+ <!-- i18n-source: README.md@49073c524eb2b7aad433b6794961ec40869c1170 status=reviewed -->
2
+ <!-- brand:start -->
3
+
4
+ <p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg" alt="sdkbump: Checks native iOS, Flutter and React Native apps for the iOS 27 SDK changes and names the fix for each."></picture></p>
5
+
6
+ <!-- lang-selector:start -->
7
+ <p align="center"><a href="README.md">English</a> · <a href="README.tr.md">Türkçe</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a> · <a href="README.es.md">Español</a> · <a href="README.de.md">Deutsch</a> · <a href="README.fr.md">Français</a> · <a href="README.pt-BR.md">Português (Brasil)</a> · <a href="README.ru.md">Русский</a></p>
8
+ <!-- lang-selector:end -->
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml/badge.svg" alt="Статус CI"></a>
12
+ <a href="https://github.com/muhittincamdali/sdkbump/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg" alt="Последняя версия: v0.1.2"></picture></a>
13
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg" alt="Версия языка: Node.js 22.12+"></picture></a>
14
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg" alt="Лицензия: MIT"></picture></a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="#быстрый-старт"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-ru-light.svg" alt="Начать"></picture></a>
19
+ <a href="https://muhittincamdali.github.io/sdkbump/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-ru-light.svg" alt="Документация"></picture></a>
20
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-ru-light.svg" alt="Руководства"></picture></a>
21
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-ru-light.svg" alt="Примеры"></picture></a>
22
+ </p>
23
+
24
+ > Это перевод README на английском языке. Если они расходятся, актуальна английская версия.
25
+
26
+ <!-- brand:end -->
27
+
28
+ Прежде чем выпускать сборку, сделанную в Xcode 27: sdkbump проверяет нативный iOS-проект, проект Flutter или React Native/Expo на всё, что меняет SDK iOS 27, начиная с жизненного цикла UIScene, и подсказывает, какое исправление подходит к каждой находке. Он читает файлы вашего проекта; ничего не собирает, не запускает и не изменяет.
29
+
30
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-rn-087-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-rn-087-light.svg"><img src="docs/media/demo-rn-087-light.svg" alt="sdkbump на приложении React Native 0.87: не запускается, если собрано с SDK iOS 27; SCN001 нет конфигурации сцены и SCN002 окно создаётся в app delegate, с тремя способами исправления"></picture>
31
+
32
+ <sub>Записано с настоящего CLI на <a href="fixtures/rn-087">фикстуре rn-087</a> — приложении React
33
+ Native 0.87.1, созданном командой <code>@react-native-community/cli init</code> (<code>npm run demo</code>).</sub>
34
+
35
+ ## Основные возможности
36
+
37
+ - **Отвечает на вопрос «запустится ли?»** Приложение, которое не объявляет ни одной сцены, собирается в Xcode 27, а затем останавливается при запуске. sdkbump сообщает об этом раньше, чем вы заметите проблему на тестовом устройстве, и называет файлы, которые нужно изменить.
38
+ - **Нативные проекты, Flutter, React Native и Expo** в одном отчёте с одинаковыми идентификаторами правил — в виде текста, Markdown или JSON, с кодом завершения для CI.
39
+ - **Исправление, которое подходит вашему проекту**: React Native 0.88 или написанный вручную scene delegate, добровольное включение в Expo SDK 57 или SDK 58, автоматическая миграция Flutter или ручные шаги (sdkbump проверяет те же условия, что и мигратор Flutter) либо API SwiftUI для приложения на SwiftUI.
40
+ - **И тихие поломки**: методы app delegate и параметры запуска, которые UIKit перестаёт использовать, когда у приложения появляется сцена (ссылки, Handoff, быстрые действия, переходы на передний план и в фон), а также поиск окна, который перестаёт находить нужное окно.
41
+ - **У каждого утверждения есть источник.** Правила — это данные ([rules/ios27.json](rules/ios27.json)), и каждое ссылается на собственные страницы Apple, Flutter, React Native или Expo; если ссылки нет, тесты падают.
42
+ - **Проверено в симуляторе iOS 27**: сбой при запуске и чёрный экран, стоящие за SCN001 и SCN002, воспроизведены в Xcode 27.0, а записи лежат в репозитории.
43
+
44
+ ## Быстрый старт
45
+
46
+ Нужен [Node.js](https://nodejs.org/) 22.12 или новее (версию показывает `node --version`; на Mac его устанавливает `brew install node`). Больше ничего не требуется.
47
+
48
+ **1. Откройте терминал в папке вашего приложения** — той, где лежит `.xcodeproj`, `pubspec.yaml` или `package.json`:
49
+
50
+ ```sh
51
+ cd path/to/YourApp
52
+ ```
53
+
54
+ **2. Запустите sdkbump:**
55
+
56
+ ```sh
57
+ npx @mcamdali/sdkbump
58
+ ```
59
+
60
+ Пакет в npm называется `@mcamdali/sdkbump`; команда, которую он устанавливает, — `sdkbump`. `npx sdkbump` без scope его не запускает.
61
+
62
+ **3. Прочитайте первую строку под названием вашего проекта.** «Fails to launch when built with the iOS 27 SDK» (не запускается, если собрано с SDK iOS 27) означает, что приложение будет останавливаться при запуске, пока вы не исправите находки уровня **ERROR**; в каждой сказано, какое исправление из списка «How to fix» подходит. Находки уровня **WARNING** не мешают запуску, но перестают работать, когда у приложения появляется сцена. «Launch not determined» (запуск не определён) означает, что sdkbump не смог прочитать Info.plist; в примечаниях в конце отчёта сказано, какой и почему (см. «Ограничения» ниже).
63
+
64
+ ## Что меняется при сборке с SDK iOS 27
65
+
66
+ Из документа Apple
67
+ [Transitioning to the UIKit scene-based life cycle](https://developer.apple.com/documentation/uikit/transitioning-to-the-uikit-scene-based-life-cycle) (перевод):
68
+
69
+ > Начиная с iOS 27, iPadOS 27, Mac Catalyst 27, tvOS 27 и visionOS 27 приложения, собранные с последним SDK, должны перейти на жизненный цикл на основе сцен, иначе они не запустятся.
70
+
71
+ 1. **Приложение останавливается при запуске, если не объявляет ни одной сцены.** В Info.plist нет `UIApplicationSceneManifest` с конфигурацией и нет `application(_:configurationForConnecting:options:)`: UIKit завершает процесс с сообщением «UIScene life cycle is required for apps built with this SDK». Компилятор не предупреждает, потому что проверка выполняется при запуске приложения. Так устроены приложения, созданные в React Native 0.87 и более ранних версиях, в Expo SDK 57 без добровольного включения и в Expo SDK 56 и более ранних; так же ведут себя приложения Flutter, которые инструмент Flutter не может мигрировать.
72
+ 2. **Когда есть сцена, app delegate перестаёт получать события интерфейса.** Ссылки, user activities, быстрые действия и переходы между активным состоянием и фоном уходят в scene delegate, а окно, созданное app delegate, никогда не показывается.
73
+
74
+ [Почему код компилируется и всё равно падает](docs/guides/why-it-crashes.md) показывает [матрицу запусков](examples/launch-matrix/README.md), которую мы прогнали в симуляторе iOS 27.0.
75
+
76
+ ## Что проверяет sdkbump
77
+
78
+ | Правило | Серьёзность | Находка | Что видно в симуляторе iOS 27.0 |
79
+ | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
80
+ | SCN001 | error | Нет конфигурации сцены: нет настроенного `UIApplicationSceneManifest`, нет `configurationForConnecting`, это не `App` из SwiftUI; для Expo без `ios/` — версия SDK и `enableSceneSupport` | останавливается при запуске |
81
+ | SCN002 | error | App delegate создаёт окно через `UIWindow(frame:)` | чёрный экран, когда у приложения появляется сцена |
82
+ | SCN003 | warning | Методы app delegate и ключи параметров запуска, которые UIKit не использует при наличии сцен (13 штук), если только scene delegate уже не обрабатывает их | `applicationDidEnterBackground(_:)` не вызывается в приложении SwiftUI |
83
+ | SCN004 | warning | Поиск окна через `UIApplication.shared.keyWindow`, `.windows` или `window` у app delegate | только предупреждения компилятора об устаревании |
84
+
85
+ Данные правил `ios27@2026.10.15`, проверены на Xcode 27.0 (27A266a). Если в React Native или Expo установлен `react-native-uiscene-bridge` или `react-native-xcode27`, находки, которые он обрабатывает во время выполнения, показываются как обработанные — с ограничениями из его README — и не приводят к сбою запуска.
86
+
87
+ ## Установка
88
+
89
+ Установите команду `sdkbump` из npm (пакет `@mcamdali/sdkbump`):
90
+
91
+ ```sh
92
+ npm i -g @mcamdali/sdkbump
93
+ sdkbump
94
+ ```
95
+
96
+ В проекте `npm install --save-dev @mcamdali/sdkbump` фиксирует версию, после чего `npx sdkbump` запускает эту копию. Каждый [релиз на GitHub](https://github.com/muhittincamdali/sdkbump/releases) также содержит тот же пакет в виде `sdkbump-<версия>.tgz` с файлом `SHA256SUMS`; `npx` запускает его по URL без npm. Формулу Homebrew для `muhittincamdali/tap` подготавливает workflow релиза (запланировано вместе с первым релизом tap).
97
+
98
+ ## Использование
99
+
100
+ ```text
101
+ sdkbump [path] [options]
102
+ ```
103
+
104
+ | Параметр | Что делает |
105
+ | ----------------------- | ---------------------------------------------------------------------------------- |
106
+ | `path` | Папка проекта или `.xcodeproj`; по умолчанию — текущая папка |
107
+ | `-f, --format <format>` | `tty` (по умолчанию), `markdown` или `json` |
108
+ | `-o, --output <file>` | Записывает отчёт в файл вместо терминала |
109
+ | `--fail-on <severity>` | `error` (по умолчанию), `warning`, `info` или `none`: когда код завершения равен 1 |
110
+ | `--no-color` | Обычный текст даже в терминале (`NO_COLOR` и `FORCE_COLOR` учитываются) |
111
+
112
+ Коды завершения: `0` — нет необработанных находок уровня `--fail-on` и выше, `1` — есть находки этого уровня или выше, `2` — неверные аргументы, iOS-проект не найден или произошла непредвиденная ошибка.
113
+
114
+ sdkbump сам находит iOS-приложение: `.xcodeproj` в корне или на одну папку глубже для нативных приложений, `ios/` для приложений Flutter, React Native и Expo (`example/ios/` для плагина Flutter). Он читает каждый iOS-таргет приложения в файле проекта, Info.plist, на который тот указывает (XML или бинарный), а также файлы Swift и Objective-C приложения, пропуская Pods, `node_modules`, результаты сборки и тесты. Приложения Expo без `ios/` проверяются по package.json и app.json.
115
+
116
+ ### Хранить отчёт в Markdown вместе с кодом
117
+
118
+ ```sh
119
+ npx @mcamdali/sdkbump --format markdown --output sdkbump.md
120
+ ```
121
+
122
+ ### Использовать отчёт JSON в скриптах
123
+
124
+ ```sh
125
+ npx @mcamdali/sdkbump --format json > sdkbump.json
126
+ ```
127
+
128
+ У каждой находки есть `rule`, `severity`, `file`, `line`, `message`, `fix` с шагами и руководством, `alternatives`, `mitigation` (заполняется, если находку обрабатывает пакет-обходной путь) и `sources`. Формат — `schemaVersion` 0, и до версии 1.0 он может измениться. [examples/shell/launch-blockers.sh](examples/shell/launch-blockers.sh) фильтрует его с помощью `jq`.
129
+
130
+ ### Запускать в CI
131
+
132
+ [examples/github-actions/sdkbump.yml](examples/github-actions/sdkbump.yml) добавляет отчёт в сводку задания для каждого pull request, затрагивающего iOS-приложение, и завершает задание с ошибкой, если есть находки уровня error.
133
+
134
+ ### Из JavaScript
135
+
136
+ ```js
137
+ import { render, scan } from 'sdkbump';
138
+
139
+ const report = await scan('path/to/app');
140
+ console.log(report.verdict.text);
141
+ console.log(render(report, 'markdown'));
142
+ ```
143
+
144
+ Запускаемая версия — [examples/api/verdicts.mjs](examples/api/verdicts.mjs).
145
+
146
+ ## Демо
147
+
148
+ Записи терминала сделаны с CLI на [фикстурах](fixtures/README.md) — настоящих проектах, созданных каждым из тулчейнов:
149
+
150
+ | Проект | Запись |
151
+ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
152
+ | Приложение React Native 0.87.1 | в начале этой страницы |
153
+ | Приложение Flutter с изменённым AppDelegate (Flutter 3.24) | [светлая](docs/media/demo-flutter-light.svg) · [тёмная](docs/media/demo-flutter-dark.svg) |
154
+ | Приложение SwiftUI с app delegate через адаптер | [светлая](docs/media/demo-swiftui-light.svg) · [тёмная](docs/media/demo-swiftui-dark.svg) |
155
+
156
+ В симуляторе iOS 27.0 (iPhone 17, сборка в Xcode 27.0) нативная фикстура UIKit останавливается при запуске, а то же приложение, переведённое на scene delegate, запускается:
157
+
158
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-simulator-native-uikit-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-simulator-native-uikit-light.svg"><img src="docs/media/demo-simulator-native-uikit-light.svg" alt="scripts/simulator-check.sh native-uikit в симуляторе iOS 27.0: через 4 секунды после запуска приложение не работает, строка UIKit: Application failed to launch: UIScene life cycle is required for apps built with this SDK"></picture>
159
+
160
+ <p align="center"><img src="docs/media/simulator/launched.png" width="480" alt="Фикстуры native-uikit-scenes и native-swiftui работают в симуляторе iPhone 17 с iOS 27.0, сборка в Xcode 27.0"></p>
161
+
162
+ Измерено 15 октября 2026 года на Mac (Apple silicon, M5 Max) с Node.js 26.11, когда на нём шли другие задачи: три серии по 100 запусков `node dist/cli/main.js` на десяти фикстурах, включая старт Node.js. Медианы трёх серий — 0,11, 0,12 и 0,19 секунды; самый медленный запуск занял 0,33 секунды. На более загруженной машине время больше.
163
+
164
+ ## Статус
165
+
166
+ | Возможность | Статус |
167
+ | ----------------------------------------------------------------------------------------------------------- | ----------------- |
168
+ | Определение нативных проектов, Flutter (приложение и пример плагина), React Native и Expo | работает |
169
+ | SCN001–SCN004 по собственному Info.plist приложения и исходникам Swift/Objective-C | работает |
170
+ | Выбор исправления по экосистеме и версии; проверка автоматической миграции Flutter; пакеты-обходные пути | работает |
171
+ | Отчёты в терминале, Markdown и JSON; коды завершения `--fail-on` | работает |
172
+ | Зависимости: Pods, `node_modules` и исходники плагинов Flutter, с названием пакета | планируется (0.2) |
173
+ | Уведомление об обходном пути SCN005 как отдельное правило; DPT001 для deployment targets ниже 15.0 | планируется (0.2) |
174
+ | `--verify`: сборка и запуск в симуляторе iOS 27 из CLI | планируется (0.3) |
175
+ | Синтаксические деревья Swift/Objective-C вместо шаблонов; проверки собранных `.app`; устаревшие API SiriKit | планируется (0.5) |
176
+ | `fix --dry-run` для нативных приложений, вывод SARIF, GitHub Action | планируется (0.8) |
177
+ | Стабильная схема правил и формат JSON | планируется (1.0) |
178
+
179
+ ## Ограничения
180
+
181
+ - **Шаблоны, а не компилятор.** Правила — это регулярные выражения по тексту Swift и Objective-C, в котором комментарии и строки заменены пробелами. Сгенерированный код, код внутри макросов или написанный необычным образом может быть пропущен или найден по ошибке. Синтаксические деревья планируются (0.5).
182
+ - **Только собственные исходники приложения.** Pods, `node_modules`, плагины Flutter и другие зависимости не читаются, поэтому плагин, который полагается на методы app delegate, больше не вызываемые UIKit, не попадает в отчёт. Проверка зависимостей планируется (0.2).
183
+ - **Настройки сборки только из project.pbxproj.** sdkbump читает `INFOPLIST_FILE` и `GENERATE_INFOPLIST_FILE` из файла проекта и подставляет `$(SRCROOT)`, `$(PROJECT_DIR)`, `$(TARGET_NAME)` и `$(PRODUCT_NAME)`. Он не читает файлы `.xcconfig`, не подставляет другие настройки сборки и не читает Info.plist за пределами папки проекта. Если Info.plist таргета прочитать не удалось, SCN001 становится находкой уровня info, а вердикт — «Launch not determined» вместо догадки.
184
+ - **Нет файла подавления.** Находку нельзя пометить как проверенную; `--fail-on` определяет, какие уровни важности делают запуск неуспешным.
185
+ - **Только файлы.** sdkbump не собирает и не запускает приложение; `--verify` планируется (0.3).
186
+
187
+ ## Документация
188
+
189
+ Справочник API и руководства: [muhittincamdali.github.io/sdkbump](https://muhittincamdali.github.io/sdkbump/).
190
+
191
+ ## Руководства
192
+
193
+ - [Почему код компилируется и всё равно падает](docs/guides/why-it-crashes.md)
194
+ - [Нативные приложения на UIKit и SwiftUI](docs/guides/native-ios.md)
195
+ - [Flutter: изменённый AppDelegate и плагины](docs/guides/flutter.md)
196
+ - [React Native до 0.88 и Expo до SDK 58](docs/guides/react-native-expo.md)
197
+ - [Авторам нативных модулей: ссылки и уведомления при холодном старте](docs/guides/native-module-authors.md)
198
+
199
+ ## Похожие инструменты
200
+
201
+ Над тем же изменением работают и другие проекты; что подойдёт, зависит от того, что вам нужно:
202
+
203
+ - [react-native-uiscene-bridge](https://github.com/Atomics-hub/react-native-uiscene-bridge) и [react-native-xcode27](https://github.com/Atomics-hub/react-native-xcode27) позволяют приложению React Native или Expo запускаться без изменений кода — во время выполнения. Они подходят, когда обновиться пока нельзя; sdkbump их распознаёт.
204
+ - [auditor-uiscene](https://github.com/Anzell/auditor-uiscene) проверяет приложения Flutter и их плагины с помощью shell-скрипта.
205
+ - Собственный мигратор Flutter (`flutter build ios`, начиная с 3.41) мигрирует неизменённое приложение Flutter.
206
+ - [flutter_spm_doctor](https://pub.dev/packages/flutter_spm_doctor) проверяет плагины Flutter.
207
+
208
+ ## Требования
209
+
210
+ | Тулчейн | Минимальная версия |
211
+ | ------- | ------------------ |
212
+ | Node.js | 22.12 |
213
+
214
+ sdkbump не требует Xcode: он читает файлы, поэтому работает и в Linux. CI запускает тесты на Node.js 22 и 24 (Linux); локально все 280 проходят на Node.js 22.23, 24.22 и 26.11 на Mac (Apple silicon). Для записей симулятора нужен Mac с Xcode 27, и они не входят в CI.
215
+
216
+ ## Архитектура
217
+
218
+ ```text
219
+ path ─► detectProject native | flutter | react-native | expo; iOS folder; versions
220
+ ─► collectApp iOS app targets from project.pbxproj, their Info.plist (XML or binary),
221
+ Swift and Objective-C sources with comments and strings blanked
222
+ ─► checkApp SCN001…SCN004, fix per ecosystem and version, workaround packages
223
+ rules/ios27.json what each rule says, fixes, sources (validated with zod)
224
+ ─► render tty | markdown | json
225
+ ```
226
+
227
+ - Шаблоны обнаружения — это регулярные выражения по исходному тексту, в котором комментарии и строки заменены пробелами, и там, где это важно, они учитываются только внутри app delegate или scene delegate.
228
+ - Данные правил отделены от кода и имеют версию (`ios27@2026.10.15`); тест падает, если у правила, исправления или обходного пути нет источника.
229
+ - CLI (`src/cli/`) только разбирает аргументы, выбирает цвета и ширину и задаёт код завершения.
230
+
231
+ ## План развития
232
+
233
+ См. таблицу [Статус](#статус): в 0.2 появятся зависимости и deployment targets, в 0.3 — запуск в симуляторе из CLI, в 0.5 — синтаксические деревья и проверки собранного приложения, в 0.8 — исправления и SARIF, в 1.0 — стабильная схема. [CHANGELOG.md](CHANGELOG.md) перечисляет, что изменилось в каждом релизе.
234
+
235
+ ## Частые вопросы
236
+
237
+ **Моё приложение сегодня работает на iOS 27. Затронет ли его это?** Если оно собрано в Xcode 26 или более ранней версии, проверка к этой сборке не относится: в нашем прогоне тот же код, скомпонованный с SDK iOS 26, запустился в симуляторе iOS 27. Она относится к вашей следующей сборке в Xcode 27.
238
+
239
+ **Заменяет ли sdkbump тестирование на устройстве?** Нет. Он читает файлы. Записи симулятора в этом репозитории сделаны в симуляторе iOS 27.0; ничего из представленного здесь не запускалось на устройстве.
240
+
241
+ **Почему находка помечена как «обработана»?** Пакет-обходной путь в package.json (react-native-uiscene-bridge или react-native-xcode27) объявляет сцену во время выполнения. Приложение запускается, но собственной поддержки сцен у него по-прежнему нет; отчёт перечисляет ограничения пакета и настоящее исправление.
242
+
243
+ **Изменяет ли sdkbump мой проект?** Нет. Он читает проект и записывает только тот отчёт, который вы попросили.
244
+
245
+
246
+ ## Участие в разработке
247
+
248
+ Мы рады вашему участию. Перед открытием pull request прочитайте [руководство для участников](CONTRIBUTING.md) и [кодекс поведения](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md). О проблемах безопасности сообщайте конфиденциально, как описано в [политике безопасности](SECURITY.md).
249
+
250
+ ## Лицензия
251
+
252
+ Распространяется по лицензии MIT. Подробнее — в файле [LICENSE](LICENSE).