@mcamdali/podexit 0.0.0-stage → 0.1.2

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.de.md +254 -0
  3. package/README.es.md +254 -0
  4. package/README.fr.md +254 -0
  5. package/README.ja.md +254 -0
  6. package/README.ko.md +254 -0
  7. package/README.md +297 -2
  8. package/README.pt-BR.md +254 -0
  9. package/README.ru.md +254 -0
  10. package/README.tr.md +254 -0
  11. package/README.zh-CN.md +254 -0
  12. package/data/publisher-policy.json +42 -0
  13. package/data/publisher-policy.schema.json +96 -0
  14. package/dist/analyze.d.ts +20 -0
  15. package/dist/analyze.js +195 -0
  16. package/dist/cli/discover.d.ts +15 -0
  17. package/dist/cli/discover.js +65 -0
  18. package/dist/cli/main.d.ts +2 -0
  19. package/dist/cli/main.js +11 -0
  20. package/dist/cli/run.d.ts +19 -0
  21. package/dist/cli/run.js +146 -0
  22. package/dist/core/classify.d.ts +39 -0
  23. package/dist/core/classify.js +71 -0
  24. package/dist/core/lockfile.d.ts +47 -0
  25. package/dist/core/lockfile.js +164 -0
  26. package/dist/core/policy.d.ts +45 -0
  27. package/dist/core/policy.js +40 -0
  28. package/dist/core/project.d.ts +13 -0
  29. package/dist/core/project.js +25 -0
  30. package/dist/core/timeline.d.ts +16 -0
  31. package/dist/core/timeline.js +14 -0
  32. package/dist/core/versions.d.ts +11 -0
  33. package/dist/core/versions.js +57 -0
  34. package/dist/data.d.ts +3 -0
  35. package/dist/data.js +9 -0
  36. package/dist/index.d.ts +27 -0
  37. package/dist/index.js +28 -0
  38. package/dist/net/cache.d.ts +28 -0
  39. package/dist/net/cache.js +89 -0
  40. package/dist/net/cocoapods.d.ts +34 -0
  41. package/dist/net/cocoapods.js +83 -0
  42. package/dist/net/fetcher.d.ts +33 -0
  43. package/dist/net/fetcher.js +35 -0
  44. package/dist/net/github.d.ts +14 -0
  45. package/dist/net/github.js +42 -0
  46. package/dist/report/escape.d.ts +17 -0
  47. package/dist/report/escape.js +54 -0
  48. package/dist/report/index.d.ts +11 -0
  49. package/dist/report/index.js +21 -0
  50. package/dist/report/labels.d.ts +22 -0
  51. package/dist/report/labels.js +82 -0
  52. package/dist/report/markdown.d.ts +6 -0
  53. package/dist/report/markdown.js +75 -0
  54. package/dist/report/tty.d.ts +12 -0
  55. package/dist/report/tty.js +103 -0
  56. package/dist/report-model.d.ts +75 -0
  57. package/dist/report-model.js +3 -0
  58. package/dist/version.d.ts +2 -0
  59. package/dist/version.js +7 -0
  60. package/package.json +72 -4
@@ -0,0 +1,254 @@
1
+ <!-- i18n-source: README.md@1c83a153cf8713f20722fb4899b14a3a0509ab39 status=reviewed -->
2
+ <!-- brand:start -->
3
+
4
+ <p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg" alt="podexit: Which of your pods stop getting updates when CocoaPods trunk goes read-only, and which already ship a Swift package."></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/podexit/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/podexit/actions/workflows/ci.yml/badge.svg" alt="Status da CI"></a>
12
+ <a href="https://github.com/muhittincamdali/podexit/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg" alt="Versão mais recente: v0.1.1"></picture></a>
13
+ <a href="https://github.com/muhittincamdali/podexit/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/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/podexit/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/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/podexit/main/.github/brand/button-start-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-pt-BR-light.svg" alt="Começar"></picture></a>
19
+ <a href="https://muhittincamdali.github.io/podexit/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-pt-BR-light.svg" alt="Documentação"></picture></a>
20
+ <a href="https://github.com/muhittincamdali/podexit/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-pt-BR-light.svg" alt="Guias"></picture></a>
21
+ <a href="https://github.com/muhittincamdali/podexit/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-pt-BR-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-pt-BR-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/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
+ O CocoaPods trunk passará a ser somente leitura em 2 de dezembro de 2026. Seus builds continuam funcionando, mas os pods publicados lá nunca mais receberão atualizações. O podexit mostra quais das suas dependências ficam congeladas, quais já oferecem um pacote Swift e o caminho de migração para iOS nativo, Flutter e React Native/Expo. Ele lê o `Podfile.lock` que você já tem; nada é instalado no seu projeto.
29
+
30
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-native-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-native-light.svg"><img src="docs/media/demo-native-light.svg" alt="podexit executado em um app iOS nativo: pods do Firebase limitados a 12.x; Alamofire, Kingfisher, SnapKit e outros congelados após 2 de dezembro, cada um com um pacote Swift"></picture>
31
+
32
+ <sub>Gravado com a CLI real sobre o <a href="fixtures/native-app/Podfile">fixture native-app</a>, com as respostas do trunk e do GitHub salvas em 14 de outubro de 2026 (<code>npm run demo</code>).</sub>
33
+
34
+ ## Destaques
35
+
36
+ - **Duas respostas por pod**: se ele deixa de receber atualizações (congelado no trunk, limitado antes pelo publicador ou não afetado) e se o repositório de origem tem um `Package.swift`.
37
+ - **Atento às versões**: verifica também o `Package.swift` na tag que você travou e avisa quando o pacote Swift só existe em versões mais novas.
38
+ - **Limite do Firebase embutido**: os 20 pods do Firebase listados ficam limitados a 12.x, junto com suas subdependências, a partir de um arquivo de dados com fontes que cita a página do Firebase.
39
+ - **Nativo, Flutter, React Native e Expo**: encontra `Podfile.lock` na pasta ou em `ios/`, `macos/`, `example/ios/` ou `example/macos/`, reconhece o tipo de projeto e indica o guia correspondente.
40
+ - **Terminal, Markdown ou JSON**: uma tabela para você, Markdown para um pull request, JSON para scripts.
41
+ - **Funciona offline**: as respostas ficam em cache por 24 horas em `~/.cache/podexit`; `--offline` usa somente o cache.
42
+
43
+ ## Início rápido
44
+
45
+ Você precisa do [Node.js](https://nodejs.org/) 22.12 ou posterior (`node --version` mostra a versão; no Mac, `brew install node` instala). Mais nada.
46
+
47
+ **1. Abra um terminal na pasta do seu app**, a que tem o `Podfile`, a pasta `ios/` ou (em um plugin Flutter) a pasta `example/`:
48
+
49
+ ```sh
50
+ cd path/to/YourApp
51
+ ```
52
+
53
+ **2. Execute o podexit:**
54
+
55
+ ```sh
56
+ npx @mcamdali/podexit
57
+ ```
58
+
59
+ O pacote do npm se chama `@mcamdali/podexit` (o npm recusou o nome sem escopo); o comando que ele instala continua sendo `podexit`.
60
+
61
+ **3. Leia a tabela.** As linhas marcadas como **capped** são as primeiras a parar (o Firebase deixa de publicar no CocoaPods em outubro de 2026); as marcadas como **frozen after Dec 2** não recebem novas versões depois de 2 de dezembro. Onde a coluna Swift package mostra **yes**, o pod já pode ser migrado. A última linha aponta o guia do seu tipo de projeto.
62
+
63
+ ## O que muda em 2 de dezembro (e o que não muda)
64
+
65
+ Segundo o [anúncio do CocoaPods](https://blog.cocoapods.org/CocoaPods-Specs-Repo/) e a [página de migração do Firebase](https://firebase.google.com/docs/ios/cocoapods-deprecation):
66
+
67
+ 1. **Os builds continuam funcionando.** O repositório Specs e a CDN permanecem no ar; o `pod install` continua resolvendo todas as versões já publicadas. Um teste do modo somente leitura acontece de 1 a 7 de novembro de 2026.
68
+ 2. **Pods no trunk não recebem novas versões** depois de 2 de dezembro de 2026, nem mesmo correções de segurança, a menos que sejam distribuídos de outra forma (normalmente um pacote Swift).
69
+ 3. **O Firebase 12 é a última versão principal no CocoaPods**, e o Firebase deixa de publicar lá em outubro de 2026. As versões 12 e anteriores continuam instaláveis.
70
+
71
+ Saiba mais em [O que muda em 2 de dezembro](docs/guides/what-changes.md).
72
+
73
+ ## Instalação
74
+
75
+ Execute sem instalar, ou adicione a um projeto para fixar uma versão:
76
+
77
+ ```sh
78
+ npm install --save-dev @mcamdali/podexit
79
+ npx @mcamdali/podexit
80
+ ```
81
+
82
+ Para instalar o comando globalmente:
83
+
84
+ ```sh
85
+ npm i -g @mcamdali/podexit
86
+ podexit
87
+ ```
88
+
89
+ Com o Homebrew, `brew install muhittincamdali/tap/podexit` instala o tarball do release publicado no GitHub.
90
+
91
+ ## Uso
92
+
93
+ ```text
94
+ podexit [paths...] [options]
95
+ ```
96
+
97
+ | Opção | O que faz |
98
+ | ----------------------- | -------------------------------------------------------------------------------- |
99
+ | `paths` | Arquivos `Podfile.lock` ou pastas de projeto; o padrão é a pasta atual |
100
+ | `-f, --format <format>` | `tty` (padrão), `markdown` ou `json` |
101
+ | `-o, --output <file>` | Grava o relatório em um arquivo em vez de no terminal |
102
+ | `-a, --all` | Lista na tabela também os pods de caminhos locais, git e specs privados |
103
+ | `--offline` | Usa somente respostas em cache; nunca acessa a rede |
104
+ | `--refresh` | Ignora o cache e consulta a rede de novo |
105
+ | `--cache-dir <dir>` | Pasta de cache (padrão `$XDG_CACHE_HOME/podexit` ou `~/.cache/podexit`) |
106
+ | `--no-color` | Texto simples, mesmo em um terminal (`NO_COLOR` e `FORCE_COLOR` são respeitados) |
107
+ | `--concurrency <n>` | Consultas de pods em paralelo, de 1 a 64 (padrão 8) |
108
+
109
+ Códigos de saída: `0` relatório gravado, `2` argumentos inválidos, nenhum `Podfile.lock` encontrado ou um arquivo que não é um, `1` qualquer outro erro inesperado. O podexit relata; ele não faz um build falhar por causa do que encontra.
110
+
111
+ Sem caminhos, o podexit lê cada lockfile que encontrar em `Podfile.lock`, `ios/Podfile.lock`, `macos/Podfile.lock`, `example/ios/Podfile.lock` e `example/macos/Podfile.lock`; uma pasta passada como caminho é procurada da mesma forma.
112
+
113
+ | Variável de ambiente | O que faz |
114
+ | -------------------------- | --------------------------------------------------------------------------------- |
115
+ | `PODEXIT_CACHE_DIR` | Pasta de cache quando `--cache-dir` não é informado |
116
+ | `GITHUB_TOKEN`, `GH_TOKEN` | Enviado apenas a hosts do GitHub; necessário para repositórios de origem privados |
117
+ | `NO_COLOR`, `FORCE_COLOR` | Desativa ou ativa as cores do terminal |
118
+
119
+ ### Mantenha um relatório em Markdown junto com o código
120
+
121
+ ```sh
122
+ npx @mcamdali/podexit --format markdown --output podexit.md
123
+ ```
124
+
125
+ A versão em Markdown tem as mesmas tabelas, as datas de lançamento e os links para o repositório de cada pacote Swift; pods de caminhos locais e de git ficam agrupados em um bloco `<details>`.
126
+
127
+ ### Use o relatório JSON em scripts
128
+
129
+ ```sh
130
+ npx @mcamdali/podexit --format json > podexit.json
131
+ ```
132
+
133
+ Cada pod traz `updates.status`, `swiftPackage.status`, a versão mais recente no trunk com a data e uma frase que explica cada resposta. O formato é `schemaVersion` 0 e pode mudar antes da 1.0. [examples/shell/frozen-pods.sh](examples/shell/frozen-pods.sh) o filtra com `jq`.
134
+
135
+ ### Execute no CI
136
+
137
+ [examples/github-actions/podexit.yml](examples/github-actions/podexit.yml) adiciona o relatório ao resumo do job de todo pull request que altera um `Podfile.lock`.
138
+
139
+ ### Limites de requisições e repositórios privados
140
+
141
+ O podexit lê `Package.swift` por raw.githubusercontent.com, que não consome a cota da API do GitHub. Defina `GITHUB_TOKEN` (ou `GH_TOKEN`) para consultar repositórios de origem privados; o token é enviado apenas a hosts do GitHub.
142
+
143
+ ### A partir de JavaScript
144
+
145
+ ```js
146
+ import {
147
+ analyzeLockfile,
148
+ buildReport,
149
+ CachedFetcher,
150
+ HttpFetcher,
151
+ loadPublisherPolicy,
152
+ render,
153
+ } from '@mcamdali/podexit';
154
+
155
+ const policy = loadPublisherPolicy();
156
+ const fetcher = new CachedFetcher(new HttpFetcher({ userAgent: 'my-tool' }), {
157
+ directory: '.cache',
158
+ });
159
+ const lockfile = await analyzeLockfile(text, 'ios/Podfile.lock', { fetcher, policy });
160
+ console.log(render(buildReport([lockfile], { policy, offline: false }), 'markdown'));
161
+ ```
162
+
163
+ Uma versão executável está em [examples/api/summary.mjs](examples/api/summary.mjs).
164
+
165
+ ## Demonstração
166
+
167
+ As três gravações vêm dos [fixtures](fixtures/README.md): projetos reais criados com cada toolchain e resolvidos pelo CocoaPods 1.16.2, reproduzidos com as respostas salvas em 14 de outubro de 2026.
168
+
169
+ | Projeto | Gravação |
170
+ | ---------------------------------------------------- | --------------------------------------------------------------------------------------- |
171
+ | App iOS nativo (Firebase, Alamofire, Google Sign-In) | topo desta página |
172
+ | App Flutter (FlutterFire, google_sign_in, …) | [claro](docs/media/demo-flutter-light.svg) · [escuro](docs/media/demo-flutter-dark.svg) |
173
+ | App Expo SDK 57 (Sentry, RevenueCat, Lottie) | [claro](docs/media/demo-expo-light.svg) · [escuro](docs/media/demo-expo-dark.svg) |
174
+
175
+ Medido em um Mac (Apple silicon, M5 Max) com Node.js 25.9 em 14 de outubro de 2026: uma primeira execução no fixture nativo (28 pods) fez 112 requisições e levou de 6,6 a 7,1 segundos; uma segunda execução respondeu a partir do cache em 0,3 segundo. A velocidade da rede define a maior parte do primeiro número.
176
+
177
+ Para gravar de novo: `npm run demo`.
178
+
179
+ ## Status
180
+
181
+ | Funcionalidade | Status |
182
+ | ----------------------------------------------------------------------------- | --------------- |
183
+ | Ler `Podfile.lock`: pods, subspecs, grafo de dependências, origem de cada pod | funciona |
184
+ | Versão mais recente e datas de lançamento do CocoaPods trunk | funciona |
185
+ | `Package.swift` na branch padrão e na tag travada | funciona |
186
+ | Limites dos publicadores (Firebase 12.x) e suas subdependências | funciona |
187
+ | Detecção de nativo, app Flutter, plugin Flutter, React Native e Expo | funciona |
188
+ | Relatórios em terminal, Markdown e JSON; reprodução do cache com `--offline` | funciona |
189
+ | Indicar o pacote npm ou pub.dev que traz cada pod | planejado (0.3) |
190
+ | Nomes de produto e versões do pacote Swift por pod, `plan` → MIGRATION.md | planejado (0.5) |
191
+ | Saída SARIF, `--fail-on`, GitHub Action | planejado (0.5) |
192
+ | Modo autor: podspec → ponto de partida de `Package.swift` | planejado (0.8) |
193
+ | `--fix` do Flutter, página web estática, schema JSON estável | planejado (1.0) |
194
+
195
+ ## Documentação
196
+
197
+ Referência da API e guias: [muhittincamdali.github.io/podexit](https://muhittincamdali.github.io/podexit/).
198
+
199
+ ## Guias
200
+
201
+ - [O que muda em 2 de dezembro (e o que não muda)](docs/guides/what-changes.md)
202
+ - [iOS nativo: do CocoaPods ao Swift Package Manager](docs/guides/native-ios.md)
203
+ - [Apps e plugins Flutter](docs/guides/flutter.md)
204
+ - [React Native e Expo](docs/guides/react-native-expo.md)
205
+ - [Firebase depois da versão 12](docs/guides/firebase.md)
206
+ - [Autores de pods: como substituir o `pod trunk push`](docs/guides/pod-authors.md)
207
+
208
+ ## Requisitos
209
+
210
+ | Toolchain | Versão mínima |
211
+ | --------- | ------------- |
212
+ | Node.js | 22.12 |
213
+
214
+ O CI executa os testes no Node.js 22 e 24 (Linux). Localmente, eles passam no Node.js 22.23, 24.22 e 25.9 em um Mac (Apple silicon).
215
+
216
+ ## Arquitetura
217
+
218
+ ```text
219
+ Podfile.lock ─► parseLockfile pods, subspecs, dependency graph, source per pod
220
+ ─► classifyLockfile frozen-on-trunk | capped | not-affected | unknown
221
+ data/publisher-policy.json (sourced; Firebase 12.x)
222
+ ─► analyzeLockfile per trunk pod, through a Fetcher:
223
+ cdn.cocoapods.org versions and podspec (GitHub repository and tag)
224
+ trunk.cocoapods.org release dates
225
+ raw.githubusercontent.com Package.swift at HEAD and at the locked tag
226
+ ─► buildReport ─► render tty | markdown | json
227
+ ```
228
+
229
+ - `src/core/` é puro: parsing, comparação de versões, classificação. Sem E/S.
230
+ - Tudo o que vem da rede passa por um `Fetcher`. O `CachedFetcher` guarda um arquivo JSON por requisição; esses mesmos arquivos são as respostas gravadas que os testes e o `--offline` reproduzem.
231
+ - Uma resposta ausente é relatada como `unknown`, com o motivo, nunca como um erro.
232
+ - A CLI (`src/cli/`) apenas lê os argumentos, encontra os lockfiles e escreve a saída.
233
+
234
+ ## Roteiro
235
+
236
+ Veja a tabela de [Status](#status): a 0.3 acrescenta o pacote npm e pub.dev por trás de cada pod, a 0.5 o plano de migração, SARIF e uma GitHub Action, a 0.8 o modo autor e a 1.0 um schema JSON estável. O [CHANGELOG.md](CHANGELOG.md) lista o que cada release mudou.
237
+
238
+ ## FAQ
239
+
240
+ **Meu app vai parar de compilar em 2 de dezembro?** Não. Tanto o CocoaPods quanto o Firebase dizem que as versões existentes continuam instaláveis. O podexit trata das atualizações que você não vai receber, não de builds que deixam de funcionar.
241
+
242
+ **Por que um pod aparece como "unknown"?** O podspec dele aponta para um host que não é o GitHub (por exemplo, um binário em dl.google.com) ou a rede não estava disponível. Os relatórios JSON e Markdown dão o motivo de cada pod.
243
+
244
+ **Por que plugins Flutter e módulos React Native aparecem como "not affected"?** Eles são pods de caminho local vindos de `.symlinks/plugins` ou `node_modules`; são atualizados pelo pub ou pelo npm. Os SDKs de que dependem são listados à parte, e esses podem estar congelados.
245
+
246
+ **O podexit altera o meu projeto?** Não. Ele lê o `Podfile.lock` e grava apenas o próprio cache e o relatório que você pedir.
247
+
248
+ ## Como contribuir
249
+
250
+ Contribuições são bem-vindas. Leia o [CONTRIBUTING.md](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 como descrito no [SECURITY.md](SECURITY.md).
251
+
252
+ ## Licença
253
+
254
+ Publicado sob a licença MIT. Veja [LICENSE](LICENSE).
package/README.ru.md ADDED
@@ -0,0 +1,254 @@
1
+ <!-- i18n-source: README.md@1c83a153cf8713f20722fb4899b14a3a0509ab39 status=reviewed -->
2
+ <!-- brand:start -->
3
+
4
+ <p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/banner-light.svg" alt="podexit: Which of your pods stop getting updates when CocoaPods trunk goes read-only, and which already ship a Swift package."></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/podexit/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/podexit/actions/workflows/ci.yml/badge.svg" alt="Статус CI"></a>
12
+ <a href="https://github.com/muhittincamdali/podexit/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-version-light.svg" alt="Последняя версия: v0.1.1"></picture></a>
13
+ <a href="https://github.com/muhittincamdali/podexit/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-language-light.svg" alt="Версия языка: Node.js 22.12+"></picture></a>
14
+ <a href="https://github.com/muhittincamdali/podexit/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/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/podexit/main/.github/brand/button-start-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-start-ru-light.svg" alt="Начать"></picture></a>
19
+ <a href="https://muhittincamdali.github.io/podexit/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-docs-ru-light.svg" alt="Документация"></picture></a>
20
+ <a href="https://github.com/muhittincamdali/podexit/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-guides-ru-light.svg" alt="Руководства"></picture></a>
21
+ <a href="https://github.com/muhittincamdali/podexit/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-ru-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-ru-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/podexit/main/.github/brand/button-examples-ru-light.svg" alt="Примеры"></picture></a>
22
+ </p>
23
+
24
+ > Это перевод README на английском языке. Если они расходятся, актуальна английская версия.
25
+
26
+ <!-- brand:end -->
27
+
28
+ 2 декабря 2026 года CocoaPods trunk станет доступен только для чтения. Ваши сборки продолжат работать, но опубликованные там pod больше никогда не получат обновлений. podexit показывает, какие из ваших зависимостей заморожены, какие уже поставляются как Swift-пакет, и путь миграции для нативного iOS, Flutter и React Native/Expo. Он читает уже имеющийся у вас `Podfile.lock`; в ваш проект ничего не устанавливается.
29
+
30
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-native-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-native-light.svg"><img src="docs/media/demo-native-light.svg" alt="podexit на нативном iOS-приложении: pod Firebase ограничены версией 12.x; Alamofire, Kingfisher, SnapKit и другие заморожены после 2 декабря, у каждого есть Swift-пакет"></picture>
31
+
32
+ <sub>Записано настоящим CLI на <a href="fixtures/native-app/Podfile">фикстуре native-app</a>; ответы trunk и GitHub сохранены 14 октября 2026 года (<code>npm run demo</code>).</sub>
33
+
34
+ ## Основные возможности
35
+
36
+ - **Два ответа для каждого pod**: перестанет ли он получать обновления (заморожен на trunk, рано ограничен издателем или не затронут) и есть ли в его исходном репозитории `Package.swift`.
37
+ - **Учитывает версии**: проверяет `Package.swift` и на зафиксированном у вас теге и сообщает, если Swift-пакет есть только в более новых версиях.
38
+ - **Ограничение Firebase встроено**: 20 перечисленных Firebase pod и их подзависимости ограничены версией 12.x; данные берутся из файла с указанием источника, который ссылается на страницу Firebase.
39
+ - **Нативные проекты, Flutter, React Native и Expo**: находит `Podfile.lock` в самой папке или в `ios/`, `macos/`, `example/ios/` или `example/macos/`, определяет тип проекта и даёт ссылку на подходящее руководство.
40
+ - **Терминал, Markdown или JSON**: таблица для вас, Markdown для pull request, JSON для скриптов.
41
+ - **Работает офлайн**: ответы кэшируются на 24 часа в `~/.cache/podexit`; `--offline` использует только кэш.
42
+
43
+ ## Быстрый старт
44
+
45
+ Нужен [Node.js](https://nodejs.org/) версии 22.12 или новее (`node --version` покажет версию; на Mac его устанавливает `brew install node`). Больше ничего не требуется.
46
+
47
+ **1. Откройте терминал в папке вашего приложения** — той, где лежит `Podfile`, папка `ios/` или (для плагина Flutter) папка `example/`:
48
+
49
+ ```sh
50
+ cd path/to/YourApp
51
+ ```
52
+
53
+ **2. Запустите podexit:**
54
+
55
+ ```sh
56
+ npx @mcamdali/podexit
57
+ ```
58
+
59
+ Пакет в npm называется `@mcamdali/podexit` (npm отклонил имя без scope); команда, которую он устанавливает, по-прежнему `podexit`.
60
+
61
+ **3. Прочитайте таблицу.** Строки с пометкой **capped** останавливаются первыми (Firebase прекращает публикацию в CocoaPods в октябре 2026 года); строки с пометкой **frozen after Dec 2** не получат новых версий после 2 декабря. Если в столбце Swift package указано **yes**, pod можно переносить уже сейчас. Последняя строка содержит ссылку на руководство для вашего типа проекта.
62
+
63
+ ## Что изменится 2 декабря (а что нет)
64
+
65
+ По [объявлению CocoaPods](https://blog.cocoapods.org/CocoaPods-Specs-Repo/) и [странице миграции Firebase](https://firebase.google.com/docs/ios/cocoapods-deprecation):
66
+
67
+ 1. **Сборки продолжат работать.** Репозиторий Specs и CDN остаются в сети; `pod install` по-прежнему разрешает все уже опубликованные версии. Пробный запуск режима только для чтения пройдёт с 1 по 7 ноября 2026 года.
68
+ 2. **Pod на trunk не получат новых версий** после 2 декабря 2026 года, включая исправления безопасности, если только их не станут поставлять иным способом (чаще всего как Swift-пакет).
69
+ 3. **Firebase 12 — последняя основная версия в CocoaPods**, а Firebase прекращает публикацию там в октябре 2026 года. Версии 12 и более ранние остаются доступными для установки.
70
+
71
+ Подробнее — в руководстве [Что изменится 2 декабря](docs/guides/what-changes.md).
72
+
73
+ ## Установка
74
+
75
+ Запускайте без установки или добавьте в проект, чтобы зафиксировать версию:
76
+
77
+ ```sh
78
+ npm install --save-dev @mcamdali/podexit
79
+ npx @mcamdali/podexit
80
+ ```
81
+
82
+ Чтобы установить команду глобально:
83
+
84
+ ```sh
85
+ npm i -g @mcamdali/podexit
86
+ podexit
87
+ ```
88
+
89
+ С Homebrew достаточно `brew install muhittincamdali/tap/podexit`: он ставит архив релиза с GitHub.
90
+
91
+ ## Использование
92
+
93
+ ```text
94
+ podexit [paths...] [options]
95
+ ```
96
+
97
+ | Параметр | Что делает |
98
+ | ----------------------- | -------------------------------------------------------------------------- |
99
+ | `paths` | Файлы `Podfile.lock` или папки проектов; по умолчанию — текущая папка |
100
+ | `-f, --format <format>` | `tty` (по умолчанию), `markdown` или `json` |
101
+ | `-o, --output <file>` | Записать отчёт в файл вместо терминала |
102
+ | `-a, --all` | Также показывать в таблице pod из локальных путей, git и приватных specs |
103
+ | `--offline` | Использовать только кэшированные ответы; к сети не обращаться |
104
+ | `--refresh` | Игнорировать кэш и снова обратиться к сети |
105
+ | `--cache-dir <dir>` | Папка кэша (по умолчанию `$XDG_CACHE_HOME/podexit` или `~/.cache/podexit`) |
106
+ | `--no-color` | Обычный текст даже в терминале (`NO_COLOR` и `FORCE_COLOR` учитываются) |
107
+ | `--concurrency <n>` | Число параллельных запросов по pod, от 1 до 64 (по умолчанию 8) |
108
+
109
+ Коды завершения: `0` — отчёт записан, `2` — неверные аргументы, не найден ни один `Podfile.lock` или файл не является им, `1` — любая другая непредвиденная ошибка. podexit сообщает о находках, но не ломает сборку из-за них.
110
+
111
+ Без путей podexit читает каждый lock-файл, который находит в `Podfile.lock`, `ios/Podfile.lock`, `macos/Podfile.lock`, `example/ios/Podfile.lock` и `example/macos/Podfile.lock`; папка, переданная как путь, просматривается так же.
112
+
113
+ | Переменная окружения | Что делает |
114
+ | -------------------------- | ------------------------------------------------------------------------------ |
115
+ | `PODEXIT_CACHE_DIR` | Папка кэша, если `--cache-dir` не указан |
116
+ | `GITHUB_TOKEN`, `GH_TOKEN` | Отправляется только на хосты GitHub; нужна для приватных исходных репозиториев |
117
+ | `NO_COLOR`, `FORCE_COLOR` | Выключает или включает цвета в терминале |
118
+
119
+ ### Храните Markdown-отчёт вместе с кодом
120
+
121
+ ```sh
122
+ npx @mcamdali/podexit --format markdown --output podexit.md
123
+ ```
124
+
125
+ В Markdown-версии те же таблицы, даты выходов и ссылки на репозиторий каждого Swift-пакета; pod из локальных путей и git сворачиваются в блок `<details>`.
126
+
127
+ ### Используйте JSON-отчёт в скриптах
128
+
129
+ ```sh
130
+ npx @mcamdali/podexit --format json > podexit.json
131
+ ```
132
+
133
+ Для каждого pod указаны `updates.status`, `swiftPackage.status`, последняя версия на trunk с датой и предложение, объясняющее каждый ответ. Структура — `schemaVersion` 0, до версии 1.0 она может измениться. [examples/shell/frozen-pods.sh](examples/shell/frozen-pods.sh) фильтрует его с помощью `jq`.
134
+
135
+ ### Запускайте в CI
136
+
137
+ [examples/github-actions/podexit.yml](examples/github-actions/podexit.yml) добавляет отчёт в сводку задания каждого pull request, который меняет `Podfile.lock`.
138
+
139
+ ### Лимиты запросов и приватные репозитории
140
+
141
+ podexit читает `Package.swift` через raw.githubusercontent.com, который не расходует квоту GitHub API. Задайте `GITHUB_TOKEN` (или `GH_TOKEN`), чтобы заглядывать в приватные исходные репозитории; токен отправляется только на хосты GitHub.
142
+
143
+ ### Из JavaScript
144
+
145
+ ```js
146
+ import {
147
+ analyzeLockfile,
148
+ buildReport,
149
+ CachedFetcher,
150
+ HttpFetcher,
151
+ loadPublisherPolicy,
152
+ render,
153
+ } from '@mcamdali/podexit';
154
+
155
+ const policy = loadPublisherPolicy();
156
+ const fetcher = new CachedFetcher(new HttpFetcher({ userAgent: 'my-tool' }), {
157
+ directory: '.cache',
158
+ });
159
+ const lockfile = await analyzeLockfile(text, 'ios/Podfile.lock', { fetcher, policy });
160
+ console.log(render(buildReport([lockfile], { policy, offline: false }), 'markdown'));
161
+ ```
162
+
163
+ Готовый к запуску вариант — [examples/api/summary.mjs](examples/api/summary.mjs).
164
+
165
+ ## Демо
166
+
167
+ Три записи сделаны на [фикстурах](fixtures/README.md): это настоящие проекты, созданные штатными инструментами каждой платформы и разрешённые CocoaPods 1.16.2; воспроизводятся по ответам, сохранённым 14 октября 2026 года.
168
+
169
+ | Проект | Запись |
170
+ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
171
+ | Нативное iOS-приложение (Firebase, Alamofire, Google Sign-In) | вверху этой страницы |
172
+ | Приложение Flutter (FlutterFire, google_sign_in, …) | [светлая](docs/media/demo-flutter-light.svg) · [тёмная](docs/media/demo-flutter-dark.svg) |
173
+ | Приложение Expo SDK 57 (Sentry, RevenueCat, Lottie) | [светлая](docs/media/demo-expo-light.svg) · [тёмная](docs/media/demo-expo-dark.svg) |
174
+
175
+ Замер на Mac (Apple silicon, M5 Max) с Node.js 25.9 от 14 октября 2026 года: первый запуск на нативной фикстуре (28 pod) сделал 112 запросов и занял от 6,6 до 7,1 секунды; второй запуск ответил из кэша за 0,3 секунды. Первое значение в основном определяется скоростью сети.
176
+
177
+ Чтобы записать их заново: `npm run demo`.
178
+
179
+ ## Статус
180
+
181
+ | Возможность | Статус |
182
+ | --------------------------------------------------------------------------------------- | ------------------- |
183
+ | Чтение `Podfile.lock`: pod, subspec, граф зависимостей, источник каждого pod | работает |
184
+ | Последняя версия и даты выходов из CocoaPods trunk | работает |
185
+ | `Package.swift` в ветке по умолчанию и на зафиксированном теге | работает |
186
+ | Ограничения издателей (Firebase 12.x) и их подзависимости | работает |
187
+ | Определение нативного проекта, приложения Flutter, плагина Flutter, React Native и Expo | работает |
188
+ | Отчёты в терминале, Markdown и JSON; воспроизведение кэша через `--offline` | работает |
189
+ | Указание npm- или pub.dev-пакета, который приносит каждый pod | запланировано (0.3) |
190
+ | Названия продуктов и версии Swift-пакета для каждого pod, `plan` → MIGRATION.md | запланировано (0.5) |
191
+ | Вывод SARIF, `--fail-on`, GitHub Action | запланировано (0.5) |
192
+ | Режим автора: podspec → отправная точка для `Package.swift` | запланировано (0.8) |
193
+ | `--fix` для Flutter, статическая веб-страница, стабильная JSON-схема | запланировано (1.0) |
194
+
195
+ ## Документация
196
+
197
+ Справочник API и руководства: [muhittincamdali.github.io/podexit](https://muhittincamdali.github.io/podexit/).
198
+
199
+ ## Руководства
200
+
201
+ - [Что изменится 2 декабря (а что нет)](docs/guides/what-changes.md)
202
+ - [Нативный iOS: от CocoaPods к Swift Package Manager](docs/guides/native-ios.md)
203
+ - [Приложения и плагины Flutter](docs/guides/flutter.md)
204
+ - [React Native и Expo](docs/guides/react-native-expo.md)
205
+ - [Firebase после версии 12](docs/guides/firebase.md)
206
+ - [Авторам pod: чем заменить `pod trunk push`](docs/guides/pod-authors.md)
207
+
208
+ ## Требования
209
+
210
+ | Инструментарий | Минимальная версия |
211
+ | -------------- | ------------------ |
212
+ | Node.js | 22.12 |
213
+
214
+ CI запускает тесты на Node.js 22 и 24 (Linux). Локально они проходят на Node.js 22.23, 24.22 и 25.9 на Mac (Apple silicon).
215
+
216
+ ## Архитектура
217
+
218
+ ```text
219
+ Podfile.lock ─► parseLockfile pods, subspecs, dependency graph, source per pod
220
+ ─► classifyLockfile frozen-on-trunk | capped | not-affected | unknown
221
+ data/publisher-policy.json (sourced; Firebase 12.x)
222
+ ─► analyzeLockfile per trunk pod, through a Fetcher:
223
+ cdn.cocoapods.org versions and podspec (GitHub repository and tag)
224
+ trunk.cocoapods.org release dates
225
+ raw.githubusercontent.com Package.swift at HEAD and at the locked tag
226
+ ─► buildReport ─► render tty | markdown | json
227
+ ```
228
+
229
+ - `src/core/` — чистый слой: разбор, сравнение версий, классификация. Никакого ввода-вывода.
230
+ - Всё, что приходит из сети, проходит через `Fetcher`. `CachedFetcher` хранит по одному JSON-файлу на запрос; эти же файлы служат записанными ответами, которые воспроизводят тесты и `--offline`.
231
+ - Отсутствующий ответ помечается как `unknown` с указанием причины, а не как ошибка.
232
+ - CLI (`src/cli/`) только разбирает аргументы, находит lockfile и записывает вывод.
233
+
234
+ ## План развития
235
+
236
+ См. таблицу [Статус](#статус): в 0.3 появится npm- и pub.dev-пакет, стоящий за каждым pod, в 0.5 — план миграции, SARIF и GitHub Action, в 0.8 — режим автора, в 1.0 — стабильная JSON-схема. В [CHANGELOG.md](CHANGELOG.md) перечислено, что изменил каждый релиз.
237
+
238
+ ## FAQ
239
+
240
+ **Перестанет ли моё приложение собираться 2 декабря?** Нет. И CocoaPods, и Firebase заявляют, что существующие версии останутся доступными для установки. podexit говорит об обновлениях, которых вы не получите, а не о сборках, которые остановятся.
241
+
242
+ **Почему pod помечен как «unknown»?** Его podspec указывает на хост, отличный от GitHub (например, на бинарный файл на dl.google.com), либо сеть была недоступна. В JSON- и Markdown-отчётах причина указана для каждого pod.
243
+
244
+ **Почему плагины Flutter и модули React Native помечены как «not affected»?** Это pod с локальным путём из `.symlinks/plugins` или `node_modules`; они обновляются через pub или npm. SDK, от которых они зависят, перечислены отдельно, и вот они могут быть заморожены.
245
+
246
+ **Меняет ли podexit мой проект?** Нет. Он читает `Podfile.lock` и записывает только свой кэш и запрошенный вами отчёт.
247
+
248
+ ## Участие в разработке
249
+
250
+ Мы рады вашему участию. Перед открытием pull request прочитайте [CONTRIBUTING.md](CONTRIBUTING.md) и [кодекс поведения](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md). О проблемах безопасности сообщайте так, как описано в [SECURITY.md](SECURITY.md).
251
+
252
+ ## Лицензия
253
+
254
+ Распространяется по лицензии MIT. Подробнее — в файле [LICENSE](LICENSE).