@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.
- package/LICENSE +21 -0
- package/README.de.md +254 -0
- package/README.es.md +254 -0
- package/README.fr.md +254 -0
- package/README.ja.md +254 -0
- package/README.ko.md +254 -0
- package/README.md +297 -2
- package/README.pt-BR.md +254 -0
- package/README.ru.md +254 -0
- package/README.tr.md +254 -0
- package/README.zh-CN.md +254 -0
- package/data/publisher-policy.json +42 -0
- package/data/publisher-policy.schema.json +96 -0
- package/dist/analyze.d.ts +20 -0
- package/dist/analyze.js +195 -0
- package/dist/cli/discover.d.ts +15 -0
- package/dist/cli/discover.js +65 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +11 -0
- package/dist/cli/run.d.ts +19 -0
- package/dist/cli/run.js +146 -0
- package/dist/core/classify.d.ts +39 -0
- package/dist/core/classify.js +71 -0
- package/dist/core/lockfile.d.ts +47 -0
- package/dist/core/lockfile.js +164 -0
- package/dist/core/policy.d.ts +45 -0
- package/dist/core/policy.js +40 -0
- package/dist/core/project.d.ts +13 -0
- package/dist/core/project.js +25 -0
- package/dist/core/timeline.d.ts +16 -0
- package/dist/core/timeline.js +14 -0
- package/dist/core/versions.d.ts +11 -0
- package/dist/core/versions.js +57 -0
- package/dist/data.d.ts +3 -0
- package/dist/data.js +9 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +28 -0
- package/dist/net/cache.d.ts +28 -0
- package/dist/net/cache.js +89 -0
- package/dist/net/cocoapods.d.ts +34 -0
- package/dist/net/cocoapods.js +83 -0
- package/dist/net/fetcher.d.ts +33 -0
- package/dist/net/fetcher.js +35 -0
- package/dist/net/github.d.ts +14 -0
- package/dist/net/github.js +42 -0
- package/dist/report/escape.d.ts +17 -0
- package/dist/report/escape.js +54 -0
- package/dist/report/index.d.ts +11 -0
- package/dist/report/index.js +21 -0
- package/dist/report/labels.d.ts +22 -0
- package/dist/report/labels.js +82 -0
- package/dist/report/markdown.d.ts +6 -0
- package/dist/report/markdown.js +75 -0
- package/dist/report/tty.d.ts +12 -0
- package/dist/report/tty.js +103 -0
- package/dist/report-model.d.ts +75 -0
- package/dist/report-model.js +3 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +7 -0
- package/package.json +72 -4
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { guideUrl, orderPods, PROJECT_LABELS, podsHeadline, requiredByLabel, summaryLines, swiftPackageLabel, updatesLabel, } from './labels.js';
|
|
2
|
+
const CODES = {
|
|
3
|
+
bold: [1, 22],
|
|
4
|
+
dim: [2, 22],
|
|
5
|
+
blue: [34, 39],
|
|
6
|
+
cyan: [36, 39],
|
|
7
|
+
yellow: [33, 39],
|
|
8
|
+
magenta: [35, 39],
|
|
9
|
+
green: [32, 39],
|
|
10
|
+
red: [31, 39],
|
|
11
|
+
};
|
|
12
|
+
function painter(color) {
|
|
13
|
+
if (!color)
|
|
14
|
+
return (_style, text) => text;
|
|
15
|
+
return (style, text) => {
|
|
16
|
+
const [open, close] = CODES[style];
|
|
17
|
+
return text ? `\u001b[${open}m${text}\u001b[${close}m` : text;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const UPDATE_STYLE = {
|
|
21
|
+
'frozen-on-trunk': 'yellow',
|
|
22
|
+
capped: 'magenta',
|
|
23
|
+
'not-affected': 'dim',
|
|
24
|
+
unknown: 'dim',
|
|
25
|
+
};
|
|
26
|
+
const PACKAGE_STYLE = {
|
|
27
|
+
'spm-available': 'green',
|
|
28
|
+
'no-spm': 'red',
|
|
29
|
+
unknown: 'dim',
|
|
30
|
+
'not-checked': 'dim',
|
|
31
|
+
};
|
|
32
|
+
const COLUMNS = [
|
|
33
|
+
{ title: 'POD', cell: (pod) => pod.name, style: (pod) => (pod.direct ? 'bold' : undefined) },
|
|
34
|
+
{ title: 'LOCKED', cell: (pod) => pod.version },
|
|
35
|
+
{ title: 'LATEST ON TRUNK', cell: (pod) => pod.updates.latestOnTrunk ?? '' },
|
|
36
|
+
{
|
|
37
|
+
title: 'UPDATES',
|
|
38
|
+
cell: updatesLabel,
|
|
39
|
+
style: (pod) => UPDATE_STYLE[pod.updates.status],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
title: 'SWIFT PACKAGE',
|
|
43
|
+
cell: swiftPackageLabel,
|
|
44
|
+
style: (pod) => PACKAGE_STYLE[pod.swiftPackage.status],
|
|
45
|
+
},
|
|
46
|
+
{ title: 'PULLED IN BY', cell: requiredByLabel, style: () => 'dim' },
|
|
47
|
+
];
|
|
48
|
+
function table(pods, paint) {
|
|
49
|
+
const rows = pods.map((pod) => COLUMNS.map((column) => column.cell(pod)));
|
|
50
|
+
const widths = COLUMNS.map((column, index) => Math.max(column.title.length, ...rows.map((row) => (row[index] ?? '').length)));
|
|
51
|
+
// The last column is not padded and lines are trimmed, so no line ends in spaces.
|
|
52
|
+
const line = (cells, styles) => ` ${cells
|
|
53
|
+
.map((cell, index) => {
|
|
54
|
+
// Padding stays outside the colour codes, so coloured and plain lines trim alike.
|
|
55
|
+
const width = index === cells.length - 1 ? 0 : (widths[index] ?? 0);
|
|
56
|
+
const style = styles[index];
|
|
57
|
+
return (style ? paint(style, cell) : cell) + ' '.repeat(Math.max(0, width - cell.length));
|
|
58
|
+
})
|
|
59
|
+
.join(' ')}`.trimEnd();
|
|
60
|
+
return [
|
|
61
|
+
line(COLUMNS.map((column) => column.title), COLUMNS.map(() => 'dim')),
|
|
62
|
+
...pods.map((pod, index) => line(rows[index] ?? [], COLUMNS.map((column) => column.style?.(pod)))),
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
function lockfileSection(lockfile, options, paint) {
|
|
66
|
+
const ordered = orderPods(lockfile.pods);
|
|
67
|
+
const shown = options.all
|
|
68
|
+
? ordered
|
|
69
|
+
: ordered.filter((pod) => pod.updates.status !== 'not-affected');
|
|
70
|
+
const hidden = ordered.length - shown.length;
|
|
71
|
+
const [updates, packages] = summaryLines(lockfile.summary);
|
|
72
|
+
const lines = [
|
|
73
|
+
`${paint('bold', paint('blue', lockfile.path))} ${paint('dim', `${PROJECT_LABELS[lockfile.project]} · ${podsHeadline(lockfile.summary)}`)}`,
|
|
74
|
+
'',
|
|
75
|
+
];
|
|
76
|
+
lines.push(...(shown.length > 0 ? table(shown, paint) : [' No pods from CocoaPods trunk.']));
|
|
77
|
+
lines.push('', ` ${updates}`, ` ${packages}`);
|
|
78
|
+
if (hidden > 0) {
|
|
79
|
+
lines.push(paint('dim', ` ${hidden} more from local paths, git or private specs (not affected); --all lists them.`));
|
|
80
|
+
}
|
|
81
|
+
lines.push(` Guide: ${paint('cyan', guideUrl(lockfile.guide.path))}`, '');
|
|
82
|
+
return lines;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Plain-text table for terminals. Colours are optional; the text is the same either way. Called
|
|
86
|
+
* through `render`, which has already replaced control characters in the report.
|
|
87
|
+
*/
|
|
88
|
+
export function renderTty(report, options) {
|
|
89
|
+
const paint = painter(options.color);
|
|
90
|
+
const { timeline } = report;
|
|
91
|
+
const lines = [
|
|
92
|
+
`${paint('bold', 'podexit')} ${report.tool.version} · CocoaPods trunk goes read-only on ${paint('bold', timeline.readOnly)} (trial run ${timeline.trialRun.from} to ${timeline.trialRun.to})`,
|
|
93
|
+
...report.notes.map((note) => paint('dim', note)),
|
|
94
|
+
'',
|
|
95
|
+
];
|
|
96
|
+
for (const lockfile of report.lockfiles)
|
|
97
|
+
lines.push(...lockfileSection(lockfile, options, paint));
|
|
98
|
+
if (report.offline) {
|
|
99
|
+
lines.push(paint('dim', 'Offline: answers come from the cache; missing ones show as unknown.'));
|
|
100
|
+
}
|
|
101
|
+
return `${lines.join('\n').trimEnd()}\n`;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=tty.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { SwiftPackageStatus, UpdateStatus } from './core/classify.js';
|
|
2
|
+
import type { PodSource } from './core/lockfile.js';
|
|
3
|
+
import type { Publisher } from './core/policy.js';
|
|
4
|
+
import type { ProjectKind } from './core/project.js';
|
|
5
|
+
import type { TIMELINE } from './core/timeline.js';
|
|
6
|
+
/** Version of the JSON report layout. It stays 0 until the layout is declared stable in 1.0. */
|
|
7
|
+
export declare const SCHEMA_VERSION = 0;
|
|
8
|
+
export interface UpdatesReport {
|
|
9
|
+
status: UpdateStatus;
|
|
10
|
+
summary: string;
|
|
11
|
+
/** Newest release on trunk; null when trunk was not asked or did not answer. */
|
|
12
|
+
latestOnTrunk: string | null;
|
|
13
|
+
latestReleasedAt: string | null;
|
|
14
|
+
lockedReleasedAt: string | null;
|
|
15
|
+
/** True when trunk has a newer release than the locked version. */
|
|
16
|
+
behindTrunk: boolean | null;
|
|
17
|
+
/** For a pod capped as a subdependency: the listed pod that pulls it in. */
|
|
18
|
+
via?: string;
|
|
19
|
+
publisher?: Pick<Publisher, 'id' | 'name' | 'lastMajorOnCocoaPods' | 'source'>;
|
|
20
|
+
}
|
|
21
|
+
export interface SwiftPackageReport {
|
|
22
|
+
status: SwiftPackageStatus;
|
|
23
|
+
summary: string;
|
|
24
|
+
/** Repository that holds (or lacks) the Package.swift. */
|
|
25
|
+
repository: string | null;
|
|
26
|
+
/** Whether Package.swift also exists at the locked version's tag; null when not checked. */
|
|
27
|
+
atLockedVersion: boolean | null;
|
|
28
|
+
/** Where the answer comes from. */
|
|
29
|
+
via: 'upstream' | 'publisher' | null;
|
|
30
|
+
}
|
|
31
|
+
export interface PodReport {
|
|
32
|
+
name: string;
|
|
33
|
+
version: string;
|
|
34
|
+
subspecs: string[];
|
|
35
|
+
direct: boolean;
|
|
36
|
+
requiredBy: string[];
|
|
37
|
+
source: PodSource;
|
|
38
|
+
updates: UpdatesReport;
|
|
39
|
+
swiftPackage: SwiftPackageReport;
|
|
40
|
+
}
|
|
41
|
+
export interface Summary {
|
|
42
|
+
pods: number;
|
|
43
|
+
direct: number;
|
|
44
|
+
frozenOnTrunk: number;
|
|
45
|
+
capped: number;
|
|
46
|
+
notAffected: number;
|
|
47
|
+
unknown: number;
|
|
48
|
+
spmAvailable: number;
|
|
49
|
+
noSpm: number;
|
|
50
|
+
spmUnknown: number;
|
|
51
|
+
}
|
|
52
|
+
export interface LockfileReport {
|
|
53
|
+
path: string;
|
|
54
|
+
project: ProjectKind;
|
|
55
|
+
guide: {
|
|
56
|
+
title: string;
|
|
57
|
+
path: string;
|
|
58
|
+
};
|
|
59
|
+
cocoapodsVersion: string | null;
|
|
60
|
+
summary: Summary;
|
|
61
|
+
pods: PodReport[];
|
|
62
|
+
}
|
|
63
|
+
export interface Report {
|
|
64
|
+
schemaVersion: typeof SCHEMA_VERSION;
|
|
65
|
+
tool: {
|
|
66
|
+
name: 'podexit';
|
|
67
|
+
version: string;
|
|
68
|
+
};
|
|
69
|
+
generatedAt: string;
|
|
70
|
+
offline: boolean;
|
|
71
|
+
timeline: typeof TIMELINE;
|
|
72
|
+
policyDataVersion: string;
|
|
73
|
+
notes: string[];
|
|
74
|
+
lockfiles: LockfileReport[];
|
|
75
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
// src/ and dist/ are both one level below the package root, so the same relative path works when
|
|
3
|
+
// running from source (tests) and from the published package.
|
|
4
|
+
const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
5
|
+
/** Version of the installed podexit package, read from its package.json. */
|
|
6
|
+
export const VERSION = manifest.version;
|
|
7
|
+
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcamdali/podexit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Shows which CocoaPods dependencies stop getting updates when CocoaPods trunk goes read-only on December 2, 2026, and which already ship a Swift package.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cocoapods",
|
|
7
|
+
"swift-package-manager",
|
|
8
|
+
"swiftpm",
|
|
9
|
+
"podfile-lock",
|
|
10
|
+
"flutter",
|
|
11
|
+
"react-native",
|
|
12
|
+
"expo",
|
|
13
|
+
"ios",
|
|
14
|
+
"migration",
|
|
15
|
+
"cli"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/muhittincamdali/podexit#readme",
|
|
18
|
+
"bugs": "https://github.com/muhittincamdali/podexit/issues",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/muhittincamdali/podexit.git"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "Muhittin Camdali",
|
|
28
|
+
"type": "module",
|
|
29
|
+
"bin": {
|
|
30
|
+
"podexit": "dist/cli/main.js"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"data/*.json",
|
|
42
|
+
"!dist/**/*.map"
|
|
43
|
+
],
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22.12"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"lint": "biome lint --error-on-warnings src test scripts examples && prettier --check .",
|
|
49
|
+
"format": "prettier --write .",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:coverage": "vitest run --coverage",
|
|
53
|
+
"build": "tsc -p tsconfig.build.json",
|
|
54
|
+
"prepack": "npm run build",
|
|
55
|
+
"fixtures:record": "node scripts/record-fixtures.mjs",
|
|
56
|
+
"demo": "npm run build && node scripts/demo.ts",
|
|
57
|
+
"docs": "npm --prefix docs/site run build",
|
|
58
|
+
"smoke": "node scripts/smoke-pack.ts",
|
|
59
|
+
"data:check": "node scripts/check-data.ts"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"commander": "15.0.0",
|
|
63
|
+
"yaml": "2.9.1",
|
|
64
|
+
"zod": "4.6.7"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@biomejs/biome": "2.5.15",
|
|
68
|
+
"@types/node": "24.19.2",
|
|
69
|
+
"@vitest/coverage-v8": "5.0.4",
|
|
70
|
+
"prettier": "3.9.10",
|
|
71
|
+
"typescript": "7.0.2",
|
|
72
|
+
"vitest": "5.0.4"
|
|
73
|
+
}
|
|
74
|
+
}
|