@iwonz/ywtc 0.0.0-stage → 2.0.0

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 (94) hide show
  1. package/.env.example +4 -0
  2. package/CHANGELOG.md +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +259 -2
  5. package/dist/adapters/confluence.d.ts +46 -0
  6. package/dist/adapters/confluence.js +187 -0
  7. package/dist/adapters/confluence.js.map +1 -0
  8. package/dist/adapters/factory.d.ts +3 -0
  9. package/dist/adapters/factory.js +11 -0
  10. package/dist/adapters/factory.js.map +1 -0
  11. package/dist/adapters/yandex.d.ts +45 -0
  12. package/dist/adapters/yandex.js +233 -0
  13. package/dist/adapters/yandex.js.map +1 -0
  14. package/dist/cli-arguments.d.ts +41 -0
  15. package/dist/cli-arguments.js +149 -0
  16. package/dist/cli-arguments.js.map +1 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +180 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/clients/confluence-cloud.d.ts +45 -0
  21. package/dist/clients/confluence-cloud.js +261 -0
  22. package/dist/clients/confluence-cloud.js.map +1 -0
  23. package/dist/clients/confluence-factory.d.ts +3 -0
  24. package/dist/clients/confluence-factory.js +8 -0
  25. package/dist/clients/confluence-factory.js.map +1 -0
  26. package/dist/clients/confluence.d.ts +42 -0
  27. package/dist/clients/confluence.js +286 -0
  28. package/dist/clients/confluence.js.map +1 -0
  29. package/dist/clients/yandex-wiki.d.ts +35 -0
  30. package/dist/clients/yandex-wiki.js +255 -0
  31. package/dist/clients/yandex-wiki.js.map +1 -0
  32. package/dist/config.d.ts +52 -0
  33. package/dist/config.js +177 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/content-model.d.ts +12 -0
  36. package/dist/content-model.js +416 -0
  37. package/dist/content-model.js.map +1 -0
  38. package/dist/conversion.d.ts +43 -0
  39. package/dist/conversion.js +450 -0
  40. package/dist/conversion.js.map +1 -0
  41. package/dist/doctor.d.ts +24 -0
  42. package/dist/doctor.js +45 -0
  43. package/dist/doctor.js.map +1 -0
  44. package/dist/domain.d.ts +202 -0
  45. package/dist/domain.js +18 -0
  46. package/dist/domain.js.map +1 -0
  47. package/dist/filesystem-export.d.ts +53 -0
  48. package/dist/filesystem-export.js +243 -0
  49. package/dist/filesystem-export.js.map +1 -0
  50. package/dist/graph.d.ts +13 -0
  51. package/dist/graph.js +121 -0
  52. package/dist/graph.js.map +1 -0
  53. package/dist/http.d.ts +26 -0
  54. package/dist/http.js +100 -0
  55. package/dist/http.js.map +1 -0
  56. package/dist/index.d.ts +24 -0
  57. package/dist/index.js +25 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/input.d.ts +4 -0
  60. package/dist/input.js +56 -0
  61. package/dist/input.js.map +1 -0
  62. package/dist/locators.d.ts +24 -0
  63. package/dist/locators.js +84 -0
  64. package/dist/locators.js.map +1 -0
  65. package/dist/logger.d.ts +7 -0
  66. package/dist/logger.js +28 -0
  67. package/dist/logger.js.map +1 -0
  68. package/dist/migrator.d.ts +53 -0
  69. package/dist/migrator.js +669 -0
  70. package/dist/migrator.js.map +1 -0
  71. package/dist/rate-limiter.d.ts +12 -0
  72. package/dist/rate-limiter.js +31 -0
  73. package/dist/rate-limiter.js.map +1 -0
  74. package/dist/report.d.ts +101 -0
  75. package/dist/report.js +106 -0
  76. package/dist/report.js.map +1 -0
  77. package/dist/state.d.ts +119 -0
  78. package/dist/state.js +201 -0
  79. package/dist/state.js.map +1 -0
  80. package/dist/types.d.ts +197 -0
  81. package/dist/types.js +2 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/updater.d.ts +24 -0
  84. package/dist/updater.js +92 -0
  85. package/dist/updater.js.map +1 -0
  86. package/dist/version.d.ts +1 -0
  87. package/dist/version.js +8 -0
  88. package/dist/version.js.map +1 -0
  89. package/dist/workspace.d.ts +29 -0
  90. package/dist/workspace.js +157 -0
  91. package/dist/workspace.js.map +1 -0
  92. package/docs/assets/readme-header.png +0 -0
  93. package/package.json +110 -4
  94. package/ywtc.config.example.yaml +52 -0
@@ -0,0 +1,45 @@
1
+ import type { YandexConnectionProfile } from '../config.js';
2
+ import type { AdapterCapabilities, DestinationAdapter, DestinationContainer, DestinationPage, PageReference, SourceAdapter, SourcePage, SourceResource, UploadedResource } from '../domain.js';
3
+ import type { YandexWikiClient } from '../clients/yandex-wiki.js';
4
+ export declare class YandexAdapter implements SourceAdapter, DestinationAdapter {
5
+ readonly profile: YandexConnectionProfile;
6
+ private readonly client;
7
+ readonly kind: "yandex-wiki";
8
+ readonly capabilities: AdapterCapabilities;
9
+ constructor(profile: YandexConnectionProfile, client: YandexWikiClient);
10
+ preflight(): Promise<{
11
+ product: string;
12
+ warnings: string[];
13
+ }>;
14
+ resolvePage(locator: string): Promise<SourcePage>;
15
+ getPage(id: string): Promise<SourcePage>;
16
+ getDescendants(page: SourcePage): Promise<SourcePage[]>;
17
+ resolveReference(from: SourcePage, reference: PageReference): Promise<SourcePage | undefined>;
18
+ listResources(page: SourcePage): Promise<SourceResource[]>;
19
+ downloadResource(resource: SourceResource, destination: string): Promise<import("../types.js").DownloadedFile>;
20
+ resolveContainer(locator: string): Promise<DestinationContainer>;
21
+ private childSlug;
22
+ findChild(container: DestinationContainer | DestinationPage, title: string): Promise<DestinationPage | undefined>;
23
+ createPage(input: {
24
+ container: DestinationContainer | DestinationPage;
25
+ title: string;
26
+ body: string;
27
+ }): Promise<DestinationPage>;
28
+ updatePage(input: {
29
+ page: DestinationPage;
30
+ title: string;
31
+ body: string;
32
+ expectedFingerprint?: string;
33
+ }): Promise<DestinationPage>;
34
+ uploadResource(input: {
35
+ page: DestinationPage;
36
+ name: string;
37
+ filePath: string;
38
+ size?: number;
39
+ mimeType?: string;
40
+ }): Promise<UploadedResource>;
41
+ listUploadedResources(page: DestinationPage): Promise<UploadedResource[]>;
42
+ verifyPage(page: DestinationPage): Promise<DestinationPage>;
43
+ renderPageReference(page: DestinationPage, label: string, anchor?: string): string;
44
+ renderResourceReference(resource: UploadedResource, label: string, image: boolean): string;
45
+ }
@@ -0,0 +1,233 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { stat } from 'node:fs/promises';
3
+ import { extractPageReferences, resolveYandexReferenceSlug } from '../content-model.js';
4
+ import { HttpRequestError } from '../http.js';
5
+ import { normalizeWikiSlug, safeFilename } from '../input.js';
6
+ const capabilities = {
7
+ readPages: true,
8
+ readHierarchy: true,
9
+ readResources: true,
10
+ writePages: true,
11
+ writeResources: true,
12
+ verifyWrites: true,
13
+ };
14
+ function pageUrl(profile, slug) {
15
+ return new URL(`${normalizeWikiSlug(slug)}/`, `${profile.webUrl}/`).toString();
16
+ }
17
+ function parentId(page) {
18
+ return [...(page.breadcrumbs ?? [])].reverse().find((item) => item.id !== undefined && item.id !== page.id)?.id?.toString();
19
+ }
20
+ function canonical(profile, id) {
21
+ return `${profile.name}:yandex-wiki:${id}`;
22
+ }
23
+ function sourcePage(profile, page) {
24
+ const rawContent = page.content ?? '';
25
+ const parent = parentId(page);
26
+ return {
27
+ provider: 'yandex-wiki',
28
+ profile: profile.name,
29
+ id: String(page.id),
30
+ canonicalId: canonical(profile, page.id),
31
+ title: page.title || normalizeWikiSlug(page.slug).split('/').at(-1) || `Page ${page.id}`,
32
+ locator: normalizeWikiSlug(page.slug),
33
+ url: pageUrl(profile, page.slug),
34
+ ...(parent ? { parentId: parent } : {}),
35
+ rawContent,
36
+ rawFormat: 'yfm',
37
+ ...(page.attributes?.modified_at ? { modifiedAt: page.attributes.modified_at, version: page.attributes.modified_at } : {}),
38
+ references: extractPageReferences(rawContent, 'yfm'),
39
+ };
40
+ }
41
+ function destinationPage(profile, page) {
42
+ const fingerprint = createHash('sha256').update(`${page.title}\0${page.content ?? ''}\0${page.attributes?.modified_at ?? ''}`).digest('hex');
43
+ return {
44
+ provider: 'yandex-wiki',
45
+ profile: profile.name,
46
+ id: String(page.id),
47
+ canonicalId: canonical(profile, page.id),
48
+ title: page.title,
49
+ url: pageUrl(profile, page.slug),
50
+ locator: normalizeWikiSlug(page.slug),
51
+ ...(page.attributes?.modified_at ? { version: page.attributes.modified_at } : {}),
52
+ fingerprint,
53
+ contentLength: Buffer.byteLength(page.content ?? ''),
54
+ };
55
+ }
56
+ function destinationContainer(profile, page) {
57
+ return {
58
+ provider: 'yandex-wiki',
59
+ profile: profile.name,
60
+ id: String(page.id),
61
+ canonicalId: canonical(profile, page.id),
62
+ title: page.title,
63
+ url: pageUrl(profile, page.slug),
64
+ locator: normalizeWikiSlug(page.slug),
65
+ };
66
+ }
67
+ function slugSegment(value) {
68
+ const normalized = value.normalize('NFKD').toLocaleLowerCase()
69
+ .replace(/[^\p{L}\p{N}]+/gu, '-')
70
+ .replace(/^-+|-+$/g, '');
71
+ return normalized || 'page';
72
+ }
73
+ function attachmentSize(value) {
74
+ if (typeof value === 'number')
75
+ return Number.isFinite(value) ? Math.round(value) : undefined;
76
+ const match = value.trim().match(/^(\d+(?:[.,]\d+)?)\s*(B|KB|KIB|MB|MIB|GB|GIB)?$/i);
77
+ if (!match?.[1])
78
+ return undefined;
79
+ const number = Number(match[1].replace(',', '.'));
80
+ const unit = match[2]?.toLocaleUpperCase() ?? 'B';
81
+ const multiplier = unit === 'KB' ? 1_000
82
+ : unit === 'KIB' ? 1_024
83
+ : unit === 'MB' ? 1_000_000
84
+ : unit === 'MIB' ? 1_048_576
85
+ : unit === 'GB' ? 1_000_000_000
86
+ : unit === 'GIB' ? 1_073_741_824
87
+ : 1;
88
+ return Number.isFinite(number) ? Math.round(number * multiplier) : undefined;
89
+ }
90
+ function attachmentResource(profile, page, attachment) {
91
+ const numericSize = attachmentSize(attachment.size);
92
+ return {
93
+ provider: 'yandex-wiki',
94
+ id: String(attachment.id),
95
+ pageId: page.id,
96
+ name: attachment.name,
97
+ ...(numericSize !== undefined ? { size: numericSize } : {}),
98
+ ...(attachment.mimetype ? { mimeType: attachment.mimetype } : {}),
99
+ ...(attachment.download_url ? { downloadUrl: attachment.download_url } : {}),
100
+ kind: attachment.has_preview ? 'image' : 'attachment',
101
+ metadata: { profile: profile.name },
102
+ };
103
+ }
104
+ export class YandexAdapter {
105
+ profile;
106
+ client;
107
+ kind = 'yandex-wiki';
108
+ capabilities = capabilities;
109
+ constructor(profile, client) {
110
+ this.profile = profile;
111
+ this.client = client;
112
+ }
113
+ async preflight() {
114
+ return { product: 'Yandex Wiki Public API v1', warnings: [] };
115
+ }
116
+ async resolvePage(locator) {
117
+ const trimmed = locator.trim();
118
+ if (/^\d+$/.test(trimmed))
119
+ return sourcePage(this.profile, await this.client.getPageById(Number(trimmed)));
120
+ let slug = trimmed;
121
+ try {
122
+ const url = new URL(trimmed);
123
+ const base = new URL(this.profile.webUrl);
124
+ if (url.origin !== base.origin)
125
+ throw new Error(`Yandex Wiki source host must match ${base.origin}`);
126
+ slug = url.pathname.slice(base.pathname.replace(/\/+$/, '').length);
127
+ }
128
+ catch (error) {
129
+ if (/^[a-z][a-z\d+.-]*:\/\//i.test(trimmed))
130
+ throw error;
131
+ }
132
+ return sourcePage(this.profile, await this.client.getPageBySlug(normalizeWikiSlug(slug)));
133
+ }
134
+ async getPage(id) {
135
+ return sourcePage(this.profile, await this.client.getPageById(Number(id)));
136
+ }
137
+ async getDescendants(page) {
138
+ const identities = await this.client.getDescendants(Number(page.id));
139
+ return Promise.all(identities.map(async (identity) => sourcePage(this.profile, await this.client.getPageById(identity.id))));
140
+ }
141
+ async resolveReference(from, reference) {
142
+ if (reference.kind !== 'page' || !reference.href)
143
+ return undefined;
144
+ const slug = resolveYandexReferenceSlug(from, reference.href);
145
+ if (!slug)
146
+ return undefined;
147
+ return sourcePage(this.profile, await this.client.getPageBySlug(slug));
148
+ }
149
+ async listResources(page) {
150
+ const [attachments, grids] = await Promise.all([
151
+ this.client.getAttachments(Number(page.id)),
152
+ this.client.getPageGrids(Number(page.id)),
153
+ ]);
154
+ const attachmentItems = attachments.filter((attachment) => attachment.is_downloadable).map((attachment) => attachmentResource(this.profile, page, attachment));
155
+ const gridItems = await Promise.all(grids.map(async (summary) => ({
156
+ provider: 'yandex-wiki',
157
+ id: summary.id,
158
+ pageId: page.id,
159
+ name: `${safeFilename(summary.title)}.grid.json`,
160
+ kind: 'grid',
161
+ metadata: { grid: await this.client.getGrid(summary.id) },
162
+ })));
163
+ return [...attachmentItems, ...gridItems];
164
+ }
165
+ downloadResource(resource, destination) {
166
+ if (resource.kind === 'grid')
167
+ throw new Error(`Grid ${resource.name} is normalized as page content and is not downloadable`);
168
+ return this.client.download(Number(resource.pageId), Number(resource.id), destination);
169
+ }
170
+ async resolveContainer(locator) {
171
+ const page = await this.resolvePage(locator);
172
+ const details = await this.client.getPageById(Number(page.id));
173
+ if (details.attributes?.is_readonly) {
174
+ throw new Error(`Yandex Wiki destination page ${details.slug} is read-only for the current user`);
175
+ }
176
+ return destinationContainer(this.profile, details);
177
+ }
178
+ childSlug(container, title) {
179
+ if (!container.locator)
180
+ throw new Error(`Yandex Wiki destination ${container.id} is missing a slug`);
181
+ return `${normalizeWikiSlug(container.locator)}/${slugSegment(title)}`;
182
+ }
183
+ async findChild(container, title) {
184
+ try {
185
+ return destinationPage(this.profile, await this.client.getPageBySlug(this.childSlug(container, title)));
186
+ }
187
+ catch (error) {
188
+ if (error instanceof HttpRequestError && error.status === 404)
189
+ return undefined;
190
+ throw error;
191
+ }
192
+ }
193
+ async createPage(input) {
194
+ const created = await this.client.createPage({ slug: this.childSlug(input.container, input.title), title: input.title, content: input.body });
195
+ return destinationPage(this.profile, created);
196
+ }
197
+ async updatePage(input) {
198
+ if (input.expectedFingerprint) {
199
+ const current = destinationPage(this.profile, await this.client.getPageById(Number(input.page.id)));
200
+ if (current.fingerprint !== input.expectedFingerprint)
201
+ throw new Error(`Destination conflict for Yandex Wiki page ${input.page.id}: content changed since the last verified run`);
202
+ }
203
+ return destinationPage(this.profile, await this.client.updatePage({ id: Number(input.page.id), title: input.title, content: input.body }));
204
+ }
205
+ async uploadResource(input) {
206
+ const size = input.size ?? (await stat(input.filePath)).size;
207
+ const attachment = await this.client.uploadAttachment({ pageId: Number(input.page.id), filename: input.name, path: input.filePath, size });
208
+ return { id: String(attachment.id), name: attachment.name, size, ...(attachment.download_url ? { url: attachment.download_url } : {}) };
209
+ }
210
+ async listUploadedResources(page) {
211
+ const attachments = await this.client.getAttachments(Number(page.id));
212
+ return attachments.map((attachment) => {
213
+ const size = attachmentSize(attachment.size);
214
+ return {
215
+ id: String(attachment.id),
216
+ name: attachment.name,
217
+ ...(size !== undefined ? { size } : {}),
218
+ ...(attachment.download_url ? { url: attachment.download_url } : {}),
219
+ };
220
+ });
221
+ }
222
+ async verifyPage(page) {
223
+ return destinationPage(this.profile, await this.client.getPageById(Number(page.id)));
224
+ }
225
+ renderPageReference(page, label, anchor) {
226
+ return `[${label}](${page.url}${anchor ? `#${anchor}` : ''})`;
227
+ }
228
+ renderResourceReference(resource, label, image) {
229
+ const href = resource.url ?? resource.name;
230
+ return image ? `![${label}](${href})` : `[${label}](${href})`;
231
+ }
232
+ }
233
+ //# sourceMappingURL=yandex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yandex.js","sourceRoot":"","sources":["../../src/adapters/yandex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { Command } from '@commander-js/extra-typings';
2
+ import type { ExportFormat, TransferScope } from './domain.js';
3
+ export type CliCommand = {
4
+ command: 'help';
5
+ topic?: 'init' | 'doctor' | 'migrate' | 'update';
6
+ } | {
7
+ command: 'version';
8
+ } | {
9
+ command: 'init';
10
+ workdir?: string;
11
+ } | {
12
+ command: 'doctor';
13
+ workdir?: string;
14
+ source?: string;
15
+ destination?: string;
16
+ sourceProfile?: string;
17
+ destinationProfile?: string;
18
+ scope: TransferScope;
19
+ format?: ExportFormat;
20
+ } | {
21
+ command: 'migrate';
22
+ source: string;
23
+ destination: string;
24
+ sourceProfile?: string;
25
+ destinationProfile?: string;
26
+ scope: TransferScope;
27
+ format?: ExportFormat;
28
+ archive: boolean;
29
+ workdir?: string;
30
+ dryRun: boolean;
31
+ fresh: boolean;
32
+ concurrency?: number;
33
+ stateFilename?: string;
34
+ } | {
35
+ command: 'update';
36
+ install: boolean;
37
+ via?: 'npm' | 'brew';
38
+ };
39
+ export declare function createCliProgram(onCommand?: (command: CliCommand) => void): Command;
40
+ export declare function parseCliArguments(argv: string[]): CliCommand;
41
+ export declare function cliHelp(topic?: 'init' | 'doctor' | 'migrate' | 'update'): string;
@@ -0,0 +1,149 @@
1
+ import { Command, Option } from '@commander-js/extra-typings';
2
+ import { packageVersion } from './version.js';
3
+ function nonEmpty(value, option) {
4
+ if (value === undefined)
5
+ return undefined;
6
+ const trimmed = value.trim();
7
+ if (!trimmed)
8
+ throw new Error(`${option} must be non-empty.`);
9
+ return trimmed;
10
+ }
11
+ function concurrency(value) {
12
+ const parsed = Number(value);
13
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 64)
14
+ throw new Error('--concurrency must be an integer between 1 and 64.');
15
+ return parsed;
16
+ }
17
+ export function createCliProgram(onCommand = () => undefined) {
18
+ const program = new Command()
19
+ .name('ywtc')
20
+ .description('Loss-aware Yandex Wiki and Confluence transfer CLI')
21
+ .version(packageVersion(), '-v, --version')
22
+ .showHelpAfterError('(run ywtc --help for usage)')
23
+ .showSuggestionAfterError(true);
24
+ program.command('init')
25
+ .description('Create or repair a workspace without overwriting data')
26
+ .option('--workdir <path>', 'workspace to initialize')
27
+ .action((options) => {
28
+ const workdir = nonEmpty(options.workdir, '--workdir');
29
+ onCommand({ command: 'init', ...(workdir ? { workdir } : {}) });
30
+ });
31
+ program.command('doctor')
32
+ .description('Validate profiles and optionally perform read-only endpoint preflight')
33
+ .option('--workdir <path>', 'workspace to inspect')
34
+ .option('--source <locator>', 'source page URL, ID, or slug')
35
+ .option('--destination <locator>', 'destination page URL, ID, slug, or directory')
36
+ .option('--source-profile <name>', 'named source connection')
37
+ .option('--destination-profile <name>', 'named destination connection')
38
+ .addOption(new Option('--scope <scope>', 'selection scope').choices(['page', 'subtree', 'linked']).default('subtree'))
39
+ .addOption(new Option('--format <format>', 'filesystem format').choices(['markdown', 'html']))
40
+ .action((options) => {
41
+ const source = nonEmpty(options.source, '--source');
42
+ const destination = nonEmpty(options.destination, '--destination');
43
+ const workdir = nonEmpty(options.workdir, '--workdir');
44
+ const sourceProfile = nonEmpty(options.sourceProfile, '--source-profile');
45
+ const destinationProfile = nonEmpty(options.destinationProfile, '--destination-profile');
46
+ if (Boolean(source) !== Boolean(destination))
47
+ throw new Error('doctor requires both --source and --destination for API preflight, or neither for local checks.');
48
+ onCommand({
49
+ command: 'doctor',
50
+ scope: options.scope,
51
+ ...(workdir ? { workdir } : {}),
52
+ ...(source && destination ? { source, destination } : {}),
53
+ ...(sourceProfile ? { sourceProfile } : {}),
54
+ ...(destinationProfile ? { destinationProfile } : {}),
55
+ ...(options.format ? { format: options.format } : {}),
56
+ });
57
+ });
58
+ program.command('migrate')
59
+ .description('Transfer or export a page graph')
60
+ .requiredOption('--source <locator>', 'source page URL, ID, or slug')
61
+ .requiredOption('--destination <locator>', 'destination page URL, ID, slug, or directory')
62
+ .option('--source-profile <name>', 'named source connection')
63
+ .option('--destination-profile <name>', 'named destination connection')
64
+ .addOption(new Option('--scope <scope>', 'selection scope').choices(['page', 'subtree', 'linked']).default('subtree'))
65
+ .addOption(new Option('--format <format>', 'filesystem format').choices(['markdown', 'html']))
66
+ .option('--archive', 'also create a ZIP for filesystem output', false)
67
+ .option('--workdir <path>', 'workspace (marked CWD, then ~/.ywtc)')
68
+ .option('--dry-run', 'discover and render without destination writes', false)
69
+ .option('--fresh', 'ignore mappings and preserve existing live state as a backup', false)
70
+ .option('--concurrency <n>', 'orchestration concurrency from 1 to 64', concurrency)
71
+ .option('--state <path>', 'state path inside workdir')
72
+ .action((options) => {
73
+ const source = nonEmpty(options.source, '--source');
74
+ const destination = nonEmpty(options.destination, '--destination');
75
+ const sourceProfile = nonEmpty(options.sourceProfile, '--source-profile');
76
+ const destinationProfile = nonEmpty(options.destinationProfile, '--destination-profile');
77
+ const workdir = nonEmpty(options.workdir, '--workdir');
78
+ const stateFilename = nonEmpty(options.state, '--state');
79
+ if (options.archive && !options.format)
80
+ throw new Error('--archive requires --format markdown|html and a directory destination.');
81
+ if (options.format && /^https?:\/\//i.test(destination))
82
+ throw new Error('--format cannot be used with a remote HTTP(S) destination.');
83
+ onCommand({
84
+ command: 'migrate',
85
+ source,
86
+ destination,
87
+ scope: options.scope,
88
+ archive: options.archive,
89
+ dryRun: options.dryRun,
90
+ fresh: options.fresh,
91
+ ...(sourceProfile ? { sourceProfile } : {}),
92
+ ...(destinationProfile ? { destinationProfile } : {}),
93
+ ...(options.format ? { format: options.format } : {}),
94
+ ...(workdir ? { workdir } : {}),
95
+ ...(options.concurrency !== undefined ? { concurrency: options.concurrency } : {}),
96
+ ...(stateFilename ? { stateFilename } : {}),
97
+ });
98
+ });
99
+ program.command('update')
100
+ .description('Check for a newer release and optionally update a safe installation')
101
+ .option('--install', 'install after checking', false)
102
+ .addOption(new Option('--via <channel>', 'force a compatible installation channel').choices(['npm', 'brew']))
103
+ .action((options) => onCommand({
104
+ command: 'update',
105
+ install: options.install,
106
+ ...(options.via ? { via: options.via } : {}),
107
+ }));
108
+ return program;
109
+ }
110
+ export function parseCliArguments(argv) {
111
+ if (argv.includes('--target'))
112
+ throw new Error('--target was removed in ywtc 2.0. Use --destination.');
113
+ if (argv.includes('--single-page'))
114
+ throw new Error('--single-page was removed in ywtc 2.0. Use --scope page.');
115
+ if (argv.length === 0 || (argv.length === 1 && ['--help', '-h'].includes(argv[0])))
116
+ return { command: 'help' };
117
+ if (argv.length === 1 && ['--version', '-v'].includes(argv[0]))
118
+ return { command: 'version' };
119
+ const helpIndex = argv.findIndex((value) => ['--help', '-h'].includes(value));
120
+ if (helpIndex >= 0) {
121
+ const topic = argv[0];
122
+ return ['init', 'doctor', 'migrate', 'update'].includes(topic ?? '')
123
+ ? { command: 'help', topic: topic }
124
+ : { command: 'help' };
125
+ }
126
+ let parsed;
127
+ const output = [];
128
+ const program = createCliProgram((command) => { parsed = command; });
129
+ program.exitOverride();
130
+ program.configureOutput({ writeOut: (value) => output.push(value), writeErr: (value) => output.push(value) });
131
+ try {
132
+ program.parse(['node', 'ywtc', ...argv], { from: 'node' });
133
+ }
134
+ catch (error) {
135
+ const message = output.join('').trim();
136
+ throw new Error(message || (error instanceof Error ? error.message : String(error)));
137
+ }
138
+ if (!parsed)
139
+ throw new Error('No command was selected. Run "ywtc --help".');
140
+ return parsed;
141
+ }
142
+ export function cliHelp(topic) {
143
+ const program = createCliProgram();
144
+ if (!topic)
145
+ return program.helpInformation();
146
+ const command = program.commands.find((candidate) => candidate.name() === topic);
147
+ return command?.helpInformation() ?? program.helpInformation();
148
+ }
149
+ //# sourceMappingURL=cli-arguments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-arguments.js","sourceRoot":"","sources":["../src/cli-arguments.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(argv?: string[]): Promise<number>;