@meerrec/cli 0.0.0-stage → 2.0.1
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 +201 -0
- package/README.md +142 -2
- package/dist/args.d.ts +48 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +256 -0
- package/dist/args.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/convert.d.ts +27 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +69 -0
- package/dist/convert.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/expand.d.ts +25 -0
- package/dist/expand.d.ts.map +1 -0
- package/dist/expand.js +148 -0
- package/dist/expand.js.map +1 -0
- package/dist/formats.d.ts +26 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/formats.js +71 -0
- package/dist/formats.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/pool.d.ts +36 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +149 -0
- package/dist/pool.js.map +1 -0
- package/dist/progress.d.ts +30 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +67 -0
- package/dist/progress.js.map +1 -0
- package/dist/run.d.ts +10 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +138 -0
- package/dist/run.js.map +1 -0
- package/dist/runtime-deno.d.ts +17 -0
- package/dist/runtime-deno.d.ts.map +1 -0
- package/dist/runtime-deno.js +116 -0
- package/dist/runtime-deno.js.map +1 -0
- package/dist/runtime-node.d.ts +13 -0
- package/dist/runtime-node.d.ts.map +1 -0
- package/dist/runtime-node.js +30 -0
- package/dist/runtime-node.js.map +1 -0
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +41 -0
- package/dist/runtime.js.map +1 -0
- package/dist/wasm.d.ts +23 -0
- package/dist/wasm.d.ts.map +1 -0
- package/dist/wasm.js +50 -0
- package/dist/wasm.js.map +1 -0
- package/dist/worker-deno.d.ts +10 -0
- package/dist/worker-deno.d.ts.map +1 -0
- package/dist/worker-deno.js +28 -0
- package/dist/worker-deno.js.map +1 -0
- package/dist/worker-protocol.d.ts +20 -0
- package/dist/worker-protocol.d.ts.map +1 -0
- package/dist/worker-protocol.js +7 -0
- package/dist/worker-protocol.js.map +1 -0
- package/dist/worker.d.ts +10 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +28 -0
- package/dist/worker.js.map +1 -0
- package/package.json +51 -4
package/dist/pool.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Пул воркеров для `batch`.
|
|
3
|
+
*
|
|
4
|
+
* Каждая задача — конвертация одного файла. Воркеров ровно `size`, очередь
|
|
5
|
+
* общая: воркер, закончивший файл, берёт следующий, поэтому медленный файл
|
|
6
|
+
* не держит остальных. Упавший воркер не роняет прогон — его задача
|
|
7
|
+
* помечается неудачной, а место занимает новый воркер, пока есть работа.
|
|
8
|
+
*/
|
|
9
|
+
import { createRequire } from 'node:module';
|
|
10
|
+
import { CliError } from './errors.js';
|
|
11
|
+
export class WorkerPool {
|
|
12
|
+
size;
|
|
13
|
+
#factory;
|
|
14
|
+
#live = new Set();
|
|
15
|
+
#idle = [];
|
|
16
|
+
#busy = new Map();
|
|
17
|
+
#dead = new Set();
|
|
18
|
+
#queue = [];
|
|
19
|
+
#respawnBudget;
|
|
20
|
+
#nextId = 0;
|
|
21
|
+
#closed = false;
|
|
22
|
+
constructor(size, factory = nodeWorkerFactory) {
|
|
23
|
+
this.size = size;
|
|
24
|
+
if (size < 1)
|
|
25
|
+
throw new CliError('worker pool needs at least one worker');
|
|
26
|
+
// Запас на замену: воркер, падающий на старте, не должен крутить пул вечно.
|
|
27
|
+
this.#respawnBudget = size * 4 + 4;
|
|
28
|
+
this.#factory = factory;
|
|
29
|
+
for (let i = 0; i < size; i += 1)
|
|
30
|
+
this.#idle.push(this.#spawn());
|
|
31
|
+
}
|
|
32
|
+
/** Сколько воркеров живо: тесты и диагностика. */
|
|
33
|
+
get live() {
|
|
34
|
+
return this.#live.size;
|
|
35
|
+
}
|
|
36
|
+
/** Поставить задачу в очередь; ответ придёт по завершении файла. */
|
|
37
|
+
run(job) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
if (this.#closed) {
|
|
40
|
+
reject(new CliError('worker pool is closed', 1));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
this.#queue.push({ job, resolve, reject });
|
|
44
|
+
this.#dispatch();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Дождаться завершения всех задач и погасить воркеры. */
|
|
48
|
+
async close() {
|
|
49
|
+
this.#closed = true;
|
|
50
|
+
const error = new CliError('worker pool is closed', 1);
|
|
51
|
+
for (const task of this.#queue.splice(0))
|
|
52
|
+
task.reject(error);
|
|
53
|
+
const workers = [...this.#live];
|
|
54
|
+
await Promise.all(workers.map(async (worker) => this.#stop(worker)));
|
|
55
|
+
}
|
|
56
|
+
#spawn() {
|
|
57
|
+
const worker = this.#factory();
|
|
58
|
+
worker.on('message', (message) => this.#onMessage(worker, message));
|
|
59
|
+
worker.on('error', (error) => this.#retire(worker, `worker failed: ${error.message}`));
|
|
60
|
+
worker.on('exit', (code) => this.#retire(worker, `worker exited with code ${code}`));
|
|
61
|
+
this.#live.add(worker);
|
|
62
|
+
return worker;
|
|
63
|
+
}
|
|
64
|
+
#dispatch() {
|
|
65
|
+
this.#ensureWorkers();
|
|
66
|
+
while (this.#queue.length > 0 && this.#idle.length > 0) {
|
|
67
|
+
const worker = this.#idle.pop();
|
|
68
|
+
const task = this.#queue.shift();
|
|
69
|
+
this.#busy.set(worker, task);
|
|
70
|
+
this.#nextId += 1;
|
|
71
|
+
worker.postMessage({ id: this.#nextId, job: task.job });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Добрать воркеров до `size`, если есть работа: замена упавшим. */
|
|
75
|
+
#ensureWorkers() {
|
|
76
|
+
while (this.#live.size < this.size && (this.#queue.length > 0 || this.#busy.size > 0)) {
|
|
77
|
+
if (this.#respawnBudget === 0) {
|
|
78
|
+
const error = new CliError('no workers left: the pool could not restart them', 1);
|
|
79
|
+
for (const task of this.#queue.splice(0))
|
|
80
|
+
task.reject(error);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.#respawnBudget -= 1;
|
|
84
|
+
this.#idle.push(this.#spawn());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
#onMessage(worker, message) {
|
|
88
|
+
const task = this.#busy.get(worker);
|
|
89
|
+
if (task === undefined)
|
|
90
|
+
return;
|
|
91
|
+
this.#busy.delete(worker);
|
|
92
|
+
if (message.ok)
|
|
93
|
+
task.resolve(message.result);
|
|
94
|
+
else
|
|
95
|
+
task.reject(new CliError(message.error, 1));
|
|
96
|
+
if (!this.#dead.has(worker))
|
|
97
|
+
this.#idle.push(worker);
|
|
98
|
+
if (!this.#closed)
|
|
99
|
+
this.#dispatch();
|
|
100
|
+
}
|
|
101
|
+
/** Вывести воркер из строя: его задача — с ошибкой, место — под замену. */
|
|
102
|
+
#retire(worker, message) {
|
|
103
|
+
if (this.#dead.has(worker))
|
|
104
|
+
return;
|
|
105
|
+
this.#dead.add(worker);
|
|
106
|
+
this.#live.delete(worker);
|
|
107
|
+
const index = this.#idle.indexOf(worker);
|
|
108
|
+
if (index >= 0)
|
|
109
|
+
this.#idle.splice(index, 1);
|
|
110
|
+
const task = this.#busy.get(worker);
|
|
111
|
+
if (task !== undefined) {
|
|
112
|
+
this.#busy.delete(worker);
|
|
113
|
+
task.reject(new CliError(message, 1));
|
|
114
|
+
}
|
|
115
|
+
worker.terminate().catch(() => {
|
|
116
|
+
// Воркер уже мёртв — гасить нечего.
|
|
117
|
+
});
|
|
118
|
+
if (!this.#closed)
|
|
119
|
+
this.#dispatch();
|
|
120
|
+
}
|
|
121
|
+
async #stop(worker) {
|
|
122
|
+
this.#dead.add(worker);
|
|
123
|
+
this.#live.delete(worker);
|
|
124
|
+
const task = this.#busy.get(worker);
|
|
125
|
+
if (task !== undefined) {
|
|
126
|
+
this.#busy.delete(worker);
|
|
127
|
+
task.reject(new CliError('worker pool is closed', 1));
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
await worker.terminate();
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Воркер уже мёртв — гасить нечего.
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Умолчание для программного API: `new WorkerPool(size)` как раньше.
|
|
139
|
+
*
|
|
140
|
+
* `node:worker_threads` подгружается `require`-ом только при вызове: Deno
|
|
141
|
+
* всегда передаёт свою фабрику из `runtime-deno`, поэтому модуль воркеров
|
|
142
|
+
* Node в его граф не попадает. `node:module` есть во всех трёх рантаймах.
|
|
143
|
+
*/
|
|
144
|
+
function nodeWorkerFactory() {
|
|
145
|
+
const require = createRequire(import.meta.url);
|
|
146
|
+
const workerThreads = require('node:worker_threads');
|
|
147
|
+
return new workerThreads.Worker(new URL('./worker.js', import.meta.url));
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=pool.js.map
|
package/dist/pool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Прогресс `batch` в stderr.
|
|
3
|
+
*
|
|
4
|
+
* Свой минимальный индикатор вместо `cli-progress`/`ora`: stdout остаётся
|
|
5
|
+
* чистым для скриптов, а от прогресса нужны только счётчик, полоса и
|
|
6
|
+
* последняя неудача. В терминале строка перерисовывается через `\r`, в
|
|
7
|
+
* пайпе — построчный лог: там `\r` превратился бы в мусор.
|
|
8
|
+
*/
|
|
9
|
+
export interface ProgressEvent {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
/** Имя файла без каталогов. */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Что записать после имени: путь выхода и размер или текст ошибки. */
|
|
14
|
+
detail: string;
|
|
15
|
+
}
|
|
16
|
+
/** Размер в удобных единицах: `4.0 KiB`. */
|
|
17
|
+
export declare function formatBytes(bytes: number): string;
|
|
18
|
+
export declare class ProgressReporter {
|
|
19
|
+
#private;
|
|
20
|
+
constructor(total: number, options?: {
|
|
21
|
+
stream?: NodeJS.WriteStream;
|
|
22
|
+
quiet?: boolean;
|
|
23
|
+
});
|
|
24
|
+
/** Сколько файлов не удалось. */
|
|
25
|
+
get failed(): number;
|
|
26
|
+
report(event: ProgressEvent): void;
|
|
27
|
+
/** Закрыть строку прогресса; в терминале — перевести курсор. */
|
|
28
|
+
finish(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4CAA4C;AAC5C,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASjD;AAED,qBAAa,gBAAgB;;gBASf,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;IAOzF,iCAAiC;IACjC,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAalC,gEAAgE;IAChE,MAAM,IAAI,IAAI;CAaf"}
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Прогресс `batch` в stderr.
|
|
3
|
+
*
|
|
4
|
+
* Свой минимальный индикатор вместо `cli-progress`/`ora`: stdout остаётся
|
|
5
|
+
* чистым для скриптов, а от прогресса нужны только счётчик, полоса и
|
|
6
|
+
* последняя неудача. В терминале строка перерисовывается через `\r`, в
|
|
7
|
+
* пайпе — построчный лог: там `\r` превратился бы в мусор.
|
|
8
|
+
*/
|
|
9
|
+
/** Размер в удобных единицах: `4.0 KiB`. */
|
|
10
|
+
export function formatBytes(bytes) {
|
|
11
|
+
const units = ['B', 'KiB', 'MiB', 'GiB'];
|
|
12
|
+
let value = bytes;
|
|
13
|
+
let unit = 0;
|
|
14
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
15
|
+
value /= 1024;
|
|
16
|
+
unit += 1;
|
|
17
|
+
}
|
|
18
|
+
return `${unit === 0 ? value : value.toFixed(1)} ${units[unit]}`;
|
|
19
|
+
}
|
|
20
|
+
export class ProgressReporter {
|
|
21
|
+
#total;
|
|
22
|
+
#stream;
|
|
23
|
+
#quiet;
|
|
24
|
+
#tty;
|
|
25
|
+
#done = 0;
|
|
26
|
+
#failed = 0;
|
|
27
|
+
#wrote = false;
|
|
28
|
+
constructor(total, options = {}) {
|
|
29
|
+
this.#total = total;
|
|
30
|
+
this.#stream = options.stream ?? process.stderr;
|
|
31
|
+
this.#quiet = options.quiet ?? false;
|
|
32
|
+
this.#tty = this.#stream.isTTY === true;
|
|
33
|
+
}
|
|
34
|
+
/** Сколько файлов не удалось. */
|
|
35
|
+
get failed() {
|
|
36
|
+
return this.#failed;
|
|
37
|
+
}
|
|
38
|
+
report(event) {
|
|
39
|
+
this.#done += 1;
|
|
40
|
+
if (!event.ok)
|
|
41
|
+
this.#failed += 1;
|
|
42
|
+
if (this.#quiet)
|
|
43
|
+
return;
|
|
44
|
+
if (this.#tty) {
|
|
45
|
+
this.#stream.write(`\r${this.#bar()} ${event.name}${' '.repeat(20)}\r`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const mark = event.ok ? 'ok ' : 'FAIL';
|
|
49
|
+
this.#stream.write(`${mark} ${this.#done}/${this.#total} ${event.name}: ${event.detail}\n`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Закрыть строку прогресса; в терминале — перевести курсор. */
|
|
53
|
+
finish() {
|
|
54
|
+
if (this.#quiet || !this.#tty || !this.#wrote)
|
|
55
|
+
return;
|
|
56
|
+
this.#stream.write(`\r${this.#bar()}${' '.repeat(20)}\n`);
|
|
57
|
+
}
|
|
58
|
+
#bar() {
|
|
59
|
+
const width = 24;
|
|
60
|
+
const filled = this.#total === 0 ? width : Math.round((this.#done / this.#total) * width);
|
|
61
|
+
const percent = this.#total === 0 ? 100 : Math.round((this.#done / this.#total) * 100);
|
|
62
|
+
const failures = this.#failed === 0 ? '' : ` failed: ${this.#failed}`;
|
|
63
|
+
this.#wrote = true;
|
|
64
|
+
return `[${'#'.repeat(filled)}${'-'.repeat(width - filled)}] ${this.#done}/${this.#total} ${percent}%${failures}`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,4CAA4C;AAC5C,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,KAAK,IAAI,IAAI,CAAC;QACd,IAAI,IAAI,CAAC,CAAC;IACZ,CAAC;IACD,OAAO,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,OAAO,gBAAgB;IAClB,MAAM,CAAS;IACf,OAAO,CAAqB;IAC5B,MAAM,CAAU;IAChB,IAAI,CAAU;IACvB,KAAK,GAAG,CAAC,CAAC;IACV,OAAO,GAAG,CAAC,CAAC;IACZ,MAAM,GAAG,KAAK,CAAC;IAEf,YAAY,KAAa,EAAE,UAA4D,EAAE;QACvF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC;IAC1C,CAAC;IAED,iCAAiC;IACjC,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,MAAM,CAAC,KAAoB;QACzB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC,KAAK,CAAC,EAAE;YAAE,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAExB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3E,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,MAAM;QACJ,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QACtD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI;QACF,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;QAC1F,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;QACvF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE,CAAC;QACtE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;IACpH,CAAC;CACF"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Исполнение разобранной команды: `convert` — в текущем процессе,
|
|
3
|
+
* `batch` — в пуле воркеров.
|
|
4
|
+
*/
|
|
5
|
+
/** Код возврата: 0 — всё сошлось, 1 — файл(ы) не сконвертировались, 2 — ошибка вызова. */
|
|
6
|
+
export declare function run(argv: readonly string[], streams?: {
|
|
7
|
+
stdout: NodeJS.WriteStream;
|
|
8
|
+
stderr: NodeJS.WriteStream;
|
|
9
|
+
}): Promise<number>;
|
|
10
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,0FAA0F;AAC1F,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE;IAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAA;CAGnH,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBlB"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Исполнение разобранной команды: `convert` — в текущем процессе,
|
|
3
|
+
* `batch` — в пуле воркеров.
|
|
4
|
+
*/
|
|
5
|
+
import { mkdir, stat } from 'node:fs/promises';
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
7
|
+
import { basename, join } from 'node:path';
|
|
8
|
+
import { parseArgs, USAGE } from './args.js';
|
|
9
|
+
import { convertFile } from './convert.js';
|
|
10
|
+
import { CliError } from './errors.js';
|
|
11
|
+
import { expandInputs } from './expand.js';
|
|
12
|
+
import { assertSupported, formatFromPath, inputKind, withExtension } from './formats.js';
|
|
13
|
+
import { formatBytes, ProgressReporter } from './progress.js';
|
|
14
|
+
import { loadRuntime } from './runtime.js';
|
|
15
|
+
/** Код возврата: 0 — всё сошлось, 1 — файл(ы) не сконвертировались, 2 — ошибка вызова. */
|
|
16
|
+
export async function run(argv, streams = {
|
|
17
|
+
stdout: process.stdout,
|
|
18
|
+
stderr: process.stderr,
|
|
19
|
+
}) {
|
|
20
|
+
try {
|
|
21
|
+
const runtime = await loadRuntime();
|
|
22
|
+
const command = parseArgs(argv, runtime);
|
|
23
|
+
switch (command.kind) {
|
|
24
|
+
case 'help':
|
|
25
|
+
streams.stdout.write(USAGE);
|
|
26
|
+
return 0;
|
|
27
|
+
case 'version':
|
|
28
|
+
streams.stdout.write(`${version()}\n`);
|
|
29
|
+
return 0;
|
|
30
|
+
case 'convert':
|
|
31
|
+
return await runConvert(command, streams.stderr);
|
|
32
|
+
case 'batch':
|
|
33
|
+
return await runBatch(command, streams.stderr, runtime);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
streams.stderr.write(`error: ${message}\n`);
|
|
39
|
+
if (error instanceof CliError && error.exitCode === 2) {
|
|
40
|
+
streams.stderr.write("run 'doc-converter help' for usage\n");
|
|
41
|
+
}
|
|
42
|
+
return error instanceof CliError ? error.exitCode : 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function runConvert(command, stderr) {
|
|
46
|
+
const kind = inputKind(command.input);
|
|
47
|
+
if (kind === null) {
|
|
48
|
+
throw new CliError(`unsupported input '${command.input}': expected .docx or .xlsx`);
|
|
49
|
+
}
|
|
50
|
+
const outIsDirectory = (await isDirectory(command.out)) || command.out.endsWith('/');
|
|
51
|
+
const format = command.format ?? (outIsDirectory ? null : formatFromPath(command.out));
|
|
52
|
+
if (format === null) {
|
|
53
|
+
throw new CliError(`cannot tell the output format from '${command.out}': pass --format <${['pdf', 'md', 'html', 'txt'].join('|')}>`);
|
|
54
|
+
}
|
|
55
|
+
assertSupported(kind, format);
|
|
56
|
+
const output = outIsDirectory ? join(command.out, withExtension(basename(command.input), format)) : command.out;
|
|
57
|
+
await assertWritable(output, command.force);
|
|
58
|
+
const result = await convertFile({ input: command.input, output, format, pdf: command.pdf });
|
|
59
|
+
stderr.write(`ok ${result.output} (${formatBytes(result.bytes)}, ${result.ms} ms)\n`);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
async function runBatch(command, stderr, runtime) {
|
|
63
|
+
const inputs = await expandInputs(command.inputs);
|
|
64
|
+
const jobs = await planJobs(inputs, command);
|
|
65
|
+
await mkdir(command.outDir, { recursive: true });
|
|
66
|
+
const progress = new ProgressReporter(jobs.length, { stream: stderr, quiet: command.quiet });
|
|
67
|
+
const pool = runtime.createPool(new URL('./worker.js', import.meta.url).href, command.workers);
|
|
68
|
+
const started = Date.now();
|
|
69
|
+
try {
|
|
70
|
+
await Promise.all(jobs.map(async (job) => {
|
|
71
|
+
try {
|
|
72
|
+
const result = await pool.submit(job);
|
|
73
|
+
progress.report({ ok: true, name: basename(job.input), detail: `${formatBytes(result.bytes)}, ${result.ms} ms` });
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
77
|
+
progress.report({ ok: false, name: basename(job.input), detail: message });
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await pool.close();
|
|
83
|
+
}
|
|
84
|
+
progress.finish();
|
|
85
|
+
const seconds = ((Date.now() - started) / 1000).toFixed(2);
|
|
86
|
+
const ok = jobs.length - progress.failed;
|
|
87
|
+
stderr.write(`done: ${ok}/${jobs.length} ok, ${progress.failed} failed in ${seconds}s (${command.workers} workers)\n`);
|
|
88
|
+
return progress.failed === 0 ? 0 : 1;
|
|
89
|
+
}
|
|
90
|
+
/** Проверить весь список до запуска воркеров: пары форматов и коллизии имён. */
|
|
91
|
+
async function planJobs(inputs, command) {
|
|
92
|
+
const byOutput = new Map();
|
|
93
|
+
const jobs = [];
|
|
94
|
+
for (const input of inputs) {
|
|
95
|
+
const kind = inputKind(input);
|
|
96
|
+
if (kind === null)
|
|
97
|
+
throw new CliError(`unsupported input '${input}': expected .docx or .xlsx`);
|
|
98
|
+
assertSupported(kind, command.format);
|
|
99
|
+
const output = join(command.outDir, withExtension(basename(input), command.format));
|
|
100
|
+
const previous = byOutput.get(output);
|
|
101
|
+
if (previous !== undefined) {
|
|
102
|
+
throw new CliError(`two inputs map to the same output '${output}': '${previous}' and '${input}'`);
|
|
103
|
+
}
|
|
104
|
+
byOutput.set(output, input);
|
|
105
|
+
await assertWritable(output, command.force);
|
|
106
|
+
jobs.push({ input, output, format: command.format, pdf: command.pdf });
|
|
107
|
+
}
|
|
108
|
+
return jobs;
|
|
109
|
+
}
|
|
110
|
+
async function assertWritable(output, force) {
|
|
111
|
+
if (!force && (await exists(output))) {
|
|
112
|
+
throw new CliError(`output exists: ${output} (use --force to overwrite)`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function exists(path) {
|
|
116
|
+
try {
|
|
117
|
+
await stat(path);
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function isDirectory(path) {
|
|
125
|
+
try {
|
|
126
|
+
return (await stat(path)).isDirectory();
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Версия пакета: `package.json` лежит на уровень выше `dist/`. */
|
|
133
|
+
function version() {
|
|
134
|
+
const require = createRequire(import.meta.url);
|
|
135
|
+
const pkg = require('../package.json');
|
|
136
|
+
return pkg.version ?? '0.0.0';
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Рантайм CLI под Deno.
|
|
3
|
+
*
|
|
4
|
+
* Пул — на веб-воркерах (`worker-deno.js`): протокол `worker-protocol.ts` от
|
|
5
|
+
* транспорта не зависит. `workerUrl` обязателен только Node-ветке; здесь
|
|
6
|
+
* адрес воркера берётся от `import.meta.url` этого модуля и указывает на
|
|
7
|
+
* соседний `worker-deno.js`.
|
|
8
|
+
*
|
|
9
|
+
* wasm-байты ищутся через `import.meta.resolve` — в Deno нет `createRequire`
|
|
10
|
+
* как основного пути разрешения пакетов. Разрешённый URL может быть
|
|
11
|
+
* `file:` (локальная сборка, `node_modules`) или `npm:` (пакет из реестра);
|
|
12
|
+
* для обоих пробуем `Deno.readFile`, затем `fetch`. Если разрешение не
|
|
13
|
+
* удалось, последний шанс — `createRequire` из Node-совместимости.
|
|
14
|
+
*/
|
|
15
|
+
import type { CliRuntime } from './runtime.js';
|
|
16
|
+
export declare function createRuntime(): CliRuntime;
|
|
17
|
+
//# sourceMappingURL=runtime-deno.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-deno.d.ts","sourceRoot":"","sources":["../src/runtime-deno.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAkF/C,wBAAgB,aAAa,IAAI,UAAU,CAc1C"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Рантайм CLI под Deno.
|
|
3
|
+
*
|
|
4
|
+
* Пул — на веб-воркерах (`worker-deno.js`): протокол `worker-protocol.ts` от
|
|
5
|
+
* транспорта не зависит. `workerUrl` обязателен только Node-ветке; здесь
|
|
6
|
+
* адрес воркера берётся от `import.meta.url` этого модуля и указывает на
|
|
7
|
+
* соседний `worker-deno.js`.
|
|
8
|
+
*
|
|
9
|
+
* wasm-байты ищутся через `import.meta.resolve` — в Deno нет `createRequire`
|
|
10
|
+
* как основного пути разрешения пакетов. Разрешённый URL может быть
|
|
11
|
+
* `file:` (локальная сборка, `node_modules`) или `npm:` (пакет из реестра);
|
|
12
|
+
* для обоих пробуем `Deno.readFile`, затем `fetch`. Если разрешение не
|
|
13
|
+
* удалось, последний шанс — `createRequire` из Node-совместимости.
|
|
14
|
+
*/
|
|
15
|
+
import { createRequire } from 'node:module';
|
|
16
|
+
import { WorkerPool } from './pool.js';
|
|
17
|
+
const globals = globalThis;
|
|
18
|
+
/**
|
|
19
|
+
* Обёртка веб-воркера под `WorkerLike` пула.
|
|
20
|
+
*
|
|
21
|
+
* У веб-воркера нет события `exit`: `terminate()` синхронный, а падение
|
|
22
|
+
* приходит событием `error` (или молчанием — пул тогда ждёт ответа).
|
|
23
|
+
*/
|
|
24
|
+
class DenoWorker {
|
|
25
|
+
#worker;
|
|
26
|
+
constructor(url) {
|
|
27
|
+
const ctor = globals.Worker;
|
|
28
|
+
if (ctor === undefined)
|
|
29
|
+
throw new Error('the Deno runtime has no Web Worker global');
|
|
30
|
+
this.#worker = new ctor(url, { type: 'module' });
|
|
31
|
+
}
|
|
32
|
+
postMessage(message) {
|
|
33
|
+
this.#worker.postMessage(message);
|
|
34
|
+
}
|
|
35
|
+
on(event, listener) {
|
|
36
|
+
if (event === 'message') {
|
|
37
|
+
const receive = listener;
|
|
38
|
+
this.#worker.addEventListener('message', (message) => receive(message.data));
|
|
39
|
+
}
|
|
40
|
+
else if (event === 'error') {
|
|
41
|
+
const fail = listener;
|
|
42
|
+
this.#worker.addEventListener('error', (event_) => {
|
|
43
|
+
fail(event_.error instanceof Error ? event_.error : new Error(event_.message ?? 'worker failed'));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// 'exit' у веб-воркера не приходит: остановку инициирует только пул.
|
|
47
|
+
}
|
|
48
|
+
terminate() {
|
|
49
|
+
this.#worker.terminate();
|
|
50
|
+
return Promise.resolve(0);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function createRuntime() {
|
|
54
|
+
return {
|
|
55
|
+
createPool(_workerUrl, size) {
|
|
56
|
+
const pool = new WorkerPool(size, () => new DenoWorker(new URL('./worker-deno.js', import.meta.url)));
|
|
57
|
+
return { submit: (job) => pool.run(job), close: () => pool.close() };
|
|
58
|
+
},
|
|
59
|
+
loadWasmBytes: wasmBytes,
|
|
60
|
+
availableParallelism() {
|
|
61
|
+
const value = globals.navigator?.hardwareConcurrency;
|
|
62
|
+
return typeof value === 'number' && value > 0 ? value : 1;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Байты `.wasm` по спеке клея: `import.meta.resolve`, затем `createRequire`. */
|
|
67
|
+
async function wasmBytes(jsSpecifier) {
|
|
68
|
+
const errors = [];
|
|
69
|
+
for (const candidate of resolveCandidates(jsSpecifier)) {
|
|
70
|
+
try {
|
|
71
|
+
return await readBytes(candidate);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
errors.push(`${candidate}: ${error instanceof Error ? error.message : String(error)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`cannot read wasm bytes for '${jsSpecifier}' under Deno (${errors.join('; ')})`);
|
|
78
|
+
}
|
|
79
|
+
/** URL'ы `.wasm`, лежащего рядом с клеем: от `import.meta.resolve` и `createRequire`. */
|
|
80
|
+
function resolveCandidates(jsSpecifier) {
|
|
81
|
+
const jsUrls = [];
|
|
82
|
+
try {
|
|
83
|
+
jsUrls.push(import.meta.resolve(jsSpecifier));
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Разрешение отдадим `createRequire` ниже.
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
// Deno реализует `createRequire`; для npm-пакетов он отдаёт путь в кэше.
|
|
90
|
+
jsUrls.push(createRequire(import.meta.url).resolve(jsSpecifier));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Оба способа не сработали — об этом скажет итоговая ошибка.
|
|
94
|
+
}
|
|
95
|
+
// Спека указывает на клей: `.wasm` лежит рядом с тем же именем.
|
|
96
|
+
return [...new Set(jsUrls.map((url) => url.replace(/\.js$/, '_bg.wasm')))];
|
|
97
|
+
}
|
|
98
|
+
async function readBytes(url) {
|
|
99
|
+
const deno = globals.Deno;
|
|
100
|
+
if (deno === undefined)
|
|
101
|
+
throw new Error('the Deno runtime adapter is loaded outside Deno');
|
|
102
|
+
if (url.startsWith('file:'))
|
|
103
|
+
return deno.readFile(new URL(url));
|
|
104
|
+
// `npm:`/`http(s):`-URL пакетного кэша: `readFile` может его не понять,
|
|
105
|
+
// `fetch` отдаёт те же байты.
|
|
106
|
+
try {
|
|
107
|
+
return await deno.readFile(new URL(url));
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
const response = await fetch(url);
|
|
111
|
+
if (!response.ok)
|
|
112
|
+
throw new Error(`HTTP ${response.status}`);
|
|
113
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=runtime-deno.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-deno.js","sourceRoot":"","sources":["../src/runtime-deno.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Рантайм CLI под Node и Bun.
|
|
3
|
+
*
|
|
4
|
+
* Пул — на `node:worker_threads`, wasm-байты читаются рядом с клеем через
|
|
5
|
+
* `createRequire` (в pnpm-раскладке пакет лежит в сторе, и путь из
|
|
6
|
+
* `import.meta.url` туда не ведёт), число ядер — у `node:os`.
|
|
7
|
+
*
|
|
8
|
+
* Bun идёт этой же веткой: перечисленные модули он реализует; отдельный
|
|
9
|
+
* `runtime-bun.ts` появится только при фактической несовместимости.
|
|
10
|
+
*/
|
|
11
|
+
import type { CliRuntime } from './runtime.js';
|
|
12
|
+
export declare function createRuntime(): CliRuntime;
|
|
13
|
+
//# sourceMappingURL=runtime-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-node.d.ts","sourceRoot":"","sources":["../src/runtime-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,wBAAgB,aAAa,IAAI,UAAU,CAe1C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Рантайм CLI под Node и Bun.
|
|
3
|
+
*
|
|
4
|
+
* Пул — на `node:worker_threads`, wasm-байты читаются рядом с клеем через
|
|
5
|
+
* `createRequire` (в pnpm-раскладке пакет лежит в сторе, и путь из
|
|
6
|
+
* `import.meta.url` туда не ведёт), число ядер — у `node:os`.
|
|
7
|
+
*
|
|
8
|
+
* Bun идёт этой же веткой: перечисленные модули он реализует; отдельный
|
|
9
|
+
* `runtime-bun.ts` появится только при фактической несовместимости.
|
|
10
|
+
*/
|
|
11
|
+
import { readFile } from 'node:fs/promises';
|
|
12
|
+
import { createRequire } from 'node:module';
|
|
13
|
+
import { availableParallelism } from 'node:os';
|
|
14
|
+
import { Worker } from 'node:worker_threads';
|
|
15
|
+
import { WorkerPool } from './pool.js';
|
|
16
|
+
export function createRuntime() {
|
|
17
|
+
return {
|
|
18
|
+
createPool(workerUrl, size) {
|
|
19
|
+
const pool = new WorkerPool(size, () => new Worker(new URL(workerUrl)));
|
|
20
|
+
return { submit: (job) => pool.run(job), close: () => pool.close() };
|
|
21
|
+
},
|
|
22
|
+
async loadWasmBytes(jsSpecifier) {
|
|
23
|
+
const require = createRequire(import.meta.url);
|
|
24
|
+
const jsPath = require.resolve(jsSpecifier);
|
|
25
|
+
return readFile(jsPath.replace(/\.js$/, '_bg.wasm'));
|
|
26
|
+
},
|
|
27
|
+
availableParallelism: () => availableParallelism(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=runtime-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-node.js","sourceRoot":"","sources":["../src/runtime-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAmB,MAAM,WAAW,CAAC;AAGxD,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,UAAU,CAAC,SAAS,EAAE,IAAI;YACxB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAA0B,CAAC,CAAC;YACjG,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QACvE,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,WAAW;YAC7B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC5C,OAAO,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,oBAAoB,EAAE,GAAG,EAAE,CAAC,oBAAoB,EAAE;KACnD,CAAC;AACJ,CAAC"}
|