@deckflow/deckuse 1.0.2 → 1.1.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.
- package/LICENSE +662 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin.js +657 -227
- package/dist/bin.js.map +1 -1
- package/dist/edition.d.ts +11 -0
- package/dist/edition.d.ts.map +1 -0
- package/dist/edition.js +9 -0
- package/dist/edition.js.map +1 -0
- package/dist/help.d.ts +6 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +575 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/monitor.d.ts +24 -0
- package/dist/monitor.d.ts.map +1 -0
- package/dist/monitor.js +884 -0
- package/dist/monitor.js.map +1 -0
- package/dist/render.d.ts +24 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +114 -0
- package/dist/render.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +18 -8
package/dist/bin.js
CHANGED
|
@@ -1,122 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { extname, resolve } from 'node:path';
|
|
2
|
+
import { access, readFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, extname, join, resolve } from 'node:path';
|
|
4
|
+
import { PROTOCOL_VERSION, revisionAsNumber, } from '@deckflow/deckuse-core';
|
|
5
|
+
import { helpTopicFromArgs, resolveHelp } from './help.js';
|
|
4
6
|
import { runCommand } from './index.js';
|
|
7
|
+
import { startMonitor } from './monitor.js';
|
|
8
|
+
import { renderPage } from './render.js';
|
|
9
|
+
import { EDITION } from './edition.js';
|
|
5
10
|
import { version } from './version.js';
|
|
6
11
|
const args = process.argv.slice(2);
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Common commands:
|
|
15
|
-
init <input> <workspace> Create a workspace from an Office document
|
|
16
|
-
inspect <workspace> Inspect the document structure
|
|
17
|
-
query <workspace> [selector] Query document elements
|
|
18
|
-
apply <workspace> Apply JSON command objects
|
|
19
|
-
validate <workspace> Validate workspace changes
|
|
20
|
-
commit <workspace> Export the workspace to a document
|
|
21
|
-
|
|
22
|
-
Run 'deckuse <command> --help' for details about a command.
|
|
23
|
-
Run 'deckuse help <command>' for the same command reference.
|
|
24
|
-
|
|
25
|
-
Options:
|
|
26
|
-
-h, --help Show this help message
|
|
27
|
-
-v, -V, --version
|
|
28
|
-
Show the deckuse version
|
|
29
|
-
--json Format command results as compact JSON
|
|
30
|
-
`,
|
|
31
|
-
init: `usage: deckuse init <input> <workspace> [--json]
|
|
32
|
-
|
|
33
|
-
Create a deckuse workspace from an Office document.
|
|
34
|
-
|
|
35
|
-
Arguments:
|
|
36
|
-
<input> Source document (.pptx, .docx, .xlsx, .key, or .numbers)
|
|
37
|
-
<workspace> Directory in which to create the workspace
|
|
38
|
-
|
|
39
|
-
Example:
|
|
40
|
-
deckuse init presentation.pptx ./presentation
|
|
41
|
-
`,
|
|
42
|
-
inspect: `usage: deckuse inspect <workspace> [--depth <n>] [--json]
|
|
43
|
-
|
|
44
|
-
Inspect the indexed structure of a workspace.
|
|
45
|
-
|
|
46
|
-
Arguments:
|
|
47
|
-
<workspace> Existing deckuse workspace
|
|
48
|
-
|
|
49
|
-
Options:
|
|
50
|
-
--depth <n> Traversal depth (default: 2)
|
|
51
|
-
|
|
52
|
-
Example:
|
|
53
|
-
deckuse inspect ./presentation --depth 3
|
|
54
|
-
`,
|
|
55
|
-
query: `usage: deckuse query <workspace> [selector] [--limit <n>] [--json]
|
|
56
|
-
|
|
57
|
-
Query indexed elements in a workspace.
|
|
58
|
-
|
|
59
|
-
Arguments:
|
|
60
|
-
<workspace> Existing deckuse workspace
|
|
61
|
-
[selector] Element selector (default: *)
|
|
62
|
-
|
|
63
|
-
Options:
|
|
64
|
-
--limit <n> Maximum results to return (default: 100)
|
|
65
|
-
|
|
66
|
-
Example:
|
|
67
|
-
deckuse query ./presentation 'slide[*] text' --limit 20
|
|
68
|
-
`,
|
|
69
|
-
apply: `usage: deckuse apply <workspace> [--input <file|->] [--json]
|
|
70
|
-
|
|
71
|
-
Apply one or more JSON command objects to a workspace. Input may be a JSON
|
|
72
|
-
object, a JSON array, or newline-delimited JSON. Commands read from standard
|
|
73
|
-
input by default.
|
|
74
|
-
|
|
75
|
-
Arguments:
|
|
76
|
-
<workspace> Existing deckuse workspace
|
|
77
|
-
|
|
78
|
-
Options:
|
|
79
|
-
--input <file|-> Command input file, or - for standard input (default: -)
|
|
80
|
-
|
|
81
|
-
Examples:
|
|
82
|
-
deckuse apply ./presentation --input changes.json
|
|
83
|
-
printf '%s\n' '{"type":"add", ...}' | deckuse apply ./presentation
|
|
84
|
-
`,
|
|
85
|
-
validate: `usage: deckuse validate <workspace> [--level <level>] [--json]
|
|
86
|
-
|
|
87
|
-
Validate workspace changes before export.
|
|
88
|
-
|
|
89
|
-
Arguments:
|
|
90
|
-
<workspace> Existing deckuse workspace
|
|
91
|
-
|
|
92
|
-
Options:
|
|
93
|
-
--level <level> Validation level (default: full)
|
|
94
|
-
|
|
95
|
-
Example:
|
|
96
|
-
deckuse validate ./presentation --level full
|
|
97
|
-
`,
|
|
98
|
-
commit: `usage: deckuse commit <workspace> [-o <output>] [--force] [--json]
|
|
99
|
-
|
|
100
|
-
Export workspace changes to an Office document.
|
|
101
|
-
|
|
102
|
-
Arguments:
|
|
103
|
-
<workspace> Existing deckuse workspace
|
|
104
|
-
|
|
105
|
-
Options:
|
|
106
|
-
-o, --output <output>
|
|
107
|
-
Destination document path
|
|
108
|
-
-f, --force Overwrite an existing destination
|
|
109
|
-
|
|
110
|
-
Example:
|
|
111
|
-
deckuse commit ./presentation -o updated.pptx
|
|
112
|
-
`,
|
|
12
|
+
const takeFlag = (list, name) => {
|
|
13
|
+
const i = list.indexOf(name);
|
|
14
|
+
if (i < 0)
|
|
15
|
+
return false;
|
|
16
|
+
list.splice(i, 1);
|
|
17
|
+
return true;
|
|
113
18
|
};
|
|
114
|
-
const
|
|
115
|
-
|
|
19
|
+
const takeOption = (list, name) => {
|
|
20
|
+
const i = list.indexOf(name);
|
|
21
|
+
if (i < 0)
|
|
22
|
+
return undefined;
|
|
23
|
+
const value = list[i + 1];
|
|
24
|
+
list.splice(i, 2);
|
|
25
|
+
return value;
|
|
26
|
+
};
|
|
27
|
+
const json = takeFlag(args, '--json');
|
|
28
|
+
const quiet = takeFlag(args, '--quiet');
|
|
29
|
+
const dryRun = takeFlag(args, '--dry-run');
|
|
30
|
+
const workspaceOpt = takeOption(args, '--workspace');
|
|
31
|
+
const revisionOpt = takeOption(args, '--revision');
|
|
32
|
+
const expectRevisionOpt = takeOption(args, '--expect-revision');
|
|
33
|
+
const reasonOpt = takeOption(args, '--reason');
|
|
34
|
+
const clean = args;
|
|
35
|
+
const findWorkspace = async (start) => {
|
|
36
|
+
if (start)
|
|
37
|
+
return resolve(start);
|
|
38
|
+
let dir = resolve(process.cwd());
|
|
39
|
+
for (;;) {
|
|
40
|
+
try {
|
|
41
|
+
await access(join(dir, '.deckuse', 'manifest.json'));
|
|
42
|
+
return dir;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
const parent = dirname(dir);
|
|
46
|
+
if (parent === dir)
|
|
47
|
+
throw new Error('No deckuse workspace found; pass --workspace <path>');
|
|
48
|
+
dir = parent;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const revisionFor = async (workspace) => {
|
|
53
|
+
const manifest = JSON.parse(await readFile(resolve(workspace, '.deckuse', 'manifest.json'), 'utf8'));
|
|
54
|
+
return manifest.revision;
|
|
116
55
|
};
|
|
117
|
-
const isHelpFlag = (value) => value === '--help' || value === '-h';
|
|
118
|
-
const isVersionFlag = (value) => value === '--version' || value === '-v' || value === '-V';
|
|
119
|
-
const isHelpCommand = (value) => value in HELP && value !== 'main';
|
|
120
56
|
const readStdin = async () => {
|
|
121
57
|
let value = '';
|
|
122
58
|
process.stdin.setEncoding('utf8');
|
|
@@ -124,137 +60,631 @@ const readStdin = async () => {
|
|
|
124
60
|
value += String(chunk);
|
|
125
61
|
return value;
|
|
126
62
|
};
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
return
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return result.ok;
|
|
63
|
+
const mutationExtras = async (workspace) => {
|
|
64
|
+
const transactionId = expectRevisionOpt ?? (await revisionFor(workspace));
|
|
65
|
+
return {
|
|
66
|
+
version: PROTOCOL_VERSION,
|
|
67
|
+
workspaceId: workspace,
|
|
68
|
+
transactionId,
|
|
69
|
+
...(dryRun ? { dryRun: true } : {}),
|
|
70
|
+
...(expectRevisionOpt ? { expectRevision: expectRevisionOpt } : {}),
|
|
71
|
+
...(reasonOpt ? { reason: reasonOpt } : {}),
|
|
72
|
+
};
|
|
138
73
|
};
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
74
|
+
const toEnvelope = (commandLabel, result, extras = {}) => {
|
|
75
|
+
if (!result.ok) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
command: commandLabel,
|
|
79
|
+
warnings: result.diagnostics
|
|
80
|
+
.filter((d) => d.severity === 'warning')
|
|
81
|
+
.map((d) => d.message),
|
|
82
|
+
error: {
|
|
83
|
+
code: result.error.code,
|
|
84
|
+
message: result.error.message,
|
|
85
|
+
...(result.error.target ? { target: result.error.target } : {}),
|
|
86
|
+
...(result.error.hint ? { hint: result.error.hint } : {}),
|
|
87
|
+
},
|
|
88
|
+
...extras,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const value = result.value;
|
|
92
|
+
const revision = revisionAsNumber(value['revision']) ??
|
|
93
|
+
(typeof value['revision'] === 'number' ? value['revision'] : undefined);
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
command: commandLabel,
|
|
97
|
+
...(revision !== undefined ? { revision } : {}),
|
|
98
|
+
branch: typeof value['branch'] === 'string' ? value['branch'] : 'main',
|
|
99
|
+
...(Array.isArray(value['affectedSlides'])
|
|
100
|
+
? { affectedSlides: value['affectedSlides'] }
|
|
101
|
+
: {}),
|
|
102
|
+
...(Array.isArray(value['changedTargets'])
|
|
103
|
+
? { changedTargets: value['changedTargets'] }
|
|
104
|
+
: {}),
|
|
105
|
+
...(Array.isArray(value['changedParts'])
|
|
106
|
+
? { changedParts: value['changedParts'] }
|
|
107
|
+
: {}),
|
|
108
|
+
warnings: [
|
|
109
|
+
...result.diagnostics.filter((d) => d.severity === 'warning').map((d) => d.message),
|
|
110
|
+
...(Array.isArray(value['warnings']) ? value['warnings'] : []),
|
|
111
|
+
],
|
|
112
|
+
data: value,
|
|
113
|
+
...extras,
|
|
114
|
+
};
|
|
142
115
|
};
|
|
143
|
-
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!ok)
|
|
148
|
-
process.exitCode = 1;
|
|
116
|
+
const outputEnvelope = (envelope) => {
|
|
117
|
+
if (json) {
|
|
118
|
+
process.stdout.write(`${JSON.stringify(envelope)}\n`);
|
|
119
|
+
return;
|
|
149
120
|
}
|
|
150
|
-
|
|
151
|
-
|
|
121
|
+
if (quiet)
|
|
122
|
+
return;
|
|
123
|
+
if (!envelope.ok) {
|
|
124
|
+
process.stderr.write(`deckuse: ${envelope.error?.code ?? 'ERROR'}: ${envelope.error?.message ?? 'failed'}\n`);
|
|
125
|
+
if (envelope.error?.hint)
|
|
126
|
+
process.stderr.write(`hint: ${envelope.error.hint}\n`);
|
|
127
|
+
return;
|
|
152
128
|
}
|
|
153
|
-
|
|
154
|
-
|
|
129
|
+
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
130
|
+
};
|
|
131
|
+
const execute = async (commandLabel, command) => {
|
|
132
|
+
if (revisionOpt && command && typeof command === 'object' && command !== null) {
|
|
133
|
+
const type = command.type;
|
|
134
|
+
if (type &&
|
|
135
|
+
![
|
|
136
|
+
'status',
|
|
137
|
+
'list',
|
|
138
|
+
'get',
|
|
139
|
+
'inspect',
|
|
140
|
+
'search',
|
|
141
|
+
'query',
|
|
142
|
+
'getText',
|
|
143
|
+
'validate',
|
|
144
|
+
'history',
|
|
145
|
+
'export',
|
|
146
|
+
].includes(type)) {
|
|
147
|
+
outputEnvelope({
|
|
148
|
+
ok: false,
|
|
149
|
+
command: commandLabel,
|
|
150
|
+
error: {
|
|
151
|
+
code: 'INVALID_COMMAND',
|
|
152
|
+
message: 'Write commands reject --revision; omit it or use a read command',
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
155
157
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
const result = await runCommand(command);
|
|
159
|
+
outputEnvelope(toEnvelope(commandLabel, result));
|
|
160
|
+
return result.ok;
|
|
161
|
+
};
|
|
162
|
+
const parseProps = (list) => {
|
|
163
|
+
const props = {};
|
|
164
|
+
for (let i = 0; i < list.length;) {
|
|
165
|
+
const token = list[i];
|
|
166
|
+
if (!token.startsWith('--')) {
|
|
167
|
+
i += 1;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const key = token.slice(2);
|
|
171
|
+
const next = list[i + 1];
|
|
172
|
+
if (next === undefined || next.startsWith('--')) {
|
|
173
|
+
props[key] = true;
|
|
174
|
+
i += 1;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
let value = next;
|
|
178
|
+
if (next === 'true')
|
|
179
|
+
value = true;
|
|
180
|
+
else if (next === 'false')
|
|
181
|
+
value = false;
|
|
182
|
+
else if (/^-?\d+(\.\d+)?$/.test(next))
|
|
183
|
+
value = Number(next);
|
|
184
|
+
else if ((next.startsWith('{') && next.endsWith('}')) ||
|
|
185
|
+
(next.startsWith('[') && next.endsWith(']'))) {
|
|
186
|
+
try {
|
|
187
|
+
value = JSON.parse(next);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
value = next;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
props[key] = value;
|
|
194
|
+
i += 2;
|
|
164
195
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
196
|
+
return props;
|
|
197
|
+
};
|
|
198
|
+
const optionFrom = (list, name) => {
|
|
199
|
+
const i = list.indexOf(name);
|
|
200
|
+
return i >= 0 ? list[i + 1] : undefined;
|
|
201
|
+
};
|
|
202
|
+
const main = async () => {
|
|
203
|
+
try {
|
|
204
|
+
if (clean.length === 0) {
|
|
205
|
+
const payload = await readStdin();
|
|
206
|
+
const parsed = JSON.parse(payload);
|
|
207
|
+
const ok = await execute('stdin', parsed);
|
|
208
|
+
if (!ok)
|
|
209
|
+
process.exitCode = 1;
|
|
172
210
|
}
|
|
173
|
-
else if (
|
|
174
|
-
|
|
175
|
-
if (!source || !workspace)
|
|
176
|
-
throw new Error('Usage: deckuse init input.pptx workspace/');
|
|
177
|
-
ok = await execute({
|
|
178
|
-
version: '1.0',
|
|
179
|
-
type: 'init',
|
|
180
|
-
workspaceId: workspace,
|
|
181
|
-
format: extname(source).slice(1).toLowerCase(),
|
|
182
|
-
source,
|
|
183
|
-
});
|
|
211
|
+
else if (clean[0] === '--version' || clean[0] === '-v' || clean[0] === '-V') {
|
|
212
|
+
process.stdout.write(`deckuse ${version} (edition=${EDITION})\n`);
|
|
184
213
|
}
|
|
185
|
-
else
|
|
186
|
-
const
|
|
187
|
-
if (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
214
|
+
else {
|
|
215
|
+
const helpTopic = helpTopicFromArgs(clean);
|
|
216
|
+
if (helpTopic !== null) {
|
|
217
|
+
process.stdout.write(resolveHelp(helpTopic));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const action = clean[0];
|
|
221
|
+
let ok = true;
|
|
222
|
+
if (action === 'init') {
|
|
223
|
+
const source = clean[1];
|
|
224
|
+
const workspace = workspaceOpt ?? clean[2];
|
|
225
|
+
if (!source || !workspace)
|
|
226
|
+
throw new Error('Usage: deckuse init <input.pptx> <workspace/>');
|
|
227
|
+
ok = await execute('deckuse init', {
|
|
228
|
+
version: PROTOCOL_VERSION,
|
|
229
|
+
type: 'init',
|
|
230
|
+
workspaceId: resolve(workspace),
|
|
231
|
+
format: extname(source).slice(1).toLowerCase(),
|
|
232
|
+
source: resolve(source),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
else if (action === 'status') {
|
|
236
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
237
|
+
ok = await execute('deckuse status', {
|
|
238
|
+
version: PROTOCOL_VERSION,
|
|
239
|
+
type: 'status',
|
|
193
240
|
workspaceId: workspace,
|
|
194
|
-
|
|
195
|
-
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
else if (action === 'list') {
|
|
244
|
+
const resource = clean[1];
|
|
245
|
+
if (!resource)
|
|
246
|
+
throw new Error('Usage: deckuse list <slides|shapes|layouts|masters|theme>');
|
|
247
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
248
|
+
const slide = optionFrom(clean, '--slide');
|
|
249
|
+
ok = await execute(`deckuse list ${resource}`, {
|
|
250
|
+
version: PROTOCOL_VERSION,
|
|
251
|
+
type: 'list',
|
|
252
|
+
workspaceId: workspace,
|
|
253
|
+
resource,
|
|
254
|
+
...(slide ? { slide: Number(slide) } : {}),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
else if (action === 'get') {
|
|
258
|
+
const target = clean[1];
|
|
259
|
+
if (!target)
|
|
260
|
+
throw new Error('Usage: deckuse get <target> [--resolve both] [--json]');
|
|
261
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
262
|
+
const resolveMode = optionFrom(clean, '--resolve') ?? 'both';
|
|
263
|
+
const propsRaw = optionFrom(clean, '--props');
|
|
264
|
+
ok = await execute('deckuse get', {
|
|
265
|
+
version: PROTOCOL_VERSION,
|
|
266
|
+
type: 'get',
|
|
267
|
+
workspaceId: workspace,
|
|
268
|
+
target,
|
|
269
|
+
resolve: resolveMode,
|
|
270
|
+
provenance: !clean.includes('--no-provenance'),
|
|
271
|
+
...(propsRaw ? { props: propsRaw.split(',').map((p) => p.trim()) } : {}),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
else if (action === 'inspect') {
|
|
275
|
+
const target = clean[1];
|
|
276
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
277
|
+
ok = await execute('deckuse inspect', {
|
|
278
|
+
version: PROTOCOL_VERSION,
|
|
279
|
+
type: 'inspect',
|
|
280
|
+
workspaceId: workspace,
|
|
281
|
+
...(target && !target.startsWith('--') ? { target } : {}),
|
|
282
|
+
visualTree: clean.includes('--visual-tree'),
|
|
283
|
+
depth: Number(optionFrom(clean, '--depth') ?? 2),
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
else if (action === 'search') {
|
|
287
|
+
const kind = clean[1];
|
|
288
|
+
if (kind !== 'text' && kind !== 'shape')
|
|
289
|
+
throw new Error('Usage: deckuse search <text|shape> ...');
|
|
290
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
291
|
+
const query = kind === 'text' ? clean[2] : optionFrom(clean, '--query');
|
|
292
|
+
ok = await execute('deckuse search', {
|
|
293
|
+
version: PROTOCOL_VERSION,
|
|
294
|
+
type: 'search',
|
|
295
|
+
workspaceId: workspace,
|
|
296
|
+
kind,
|
|
297
|
+
...(query ? { query } : {}),
|
|
298
|
+
...(optionFrom(clean, '--name') ? { name: optionFrom(clean, '--name') } : {}),
|
|
299
|
+
limit: Number(optionFrom(clean, '--limit') ?? 100),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
else if (action === 'add') {
|
|
303
|
+
const what = clean[1];
|
|
304
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
305
|
+
const base = await mutationExtras(workspace);
|
|
306
|
+
if (what === 'slide') {
|
|
307
|
+
ok = await execute('deckuse add slide', {
|
|
308
|
+
...base,
|
|
309
|
+
type: 'addSlide',
|
|
310
|
+
...(optionFrom(clean, '--after') ? { after: Number(optionFrom(clean, '--after')) } : {}),
|
|
311
|
+
...(optionFrom(clean, '--layout') ? { layout: optionFrom(clean, '--layout') } : {}),
|
|
312
|
+
...(optionFrom(clean, '--name') ? { name: optionFrom(clean, '--name') } : {}),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
else if (what === 'shape') {
|
|
316
|
+
const slide = optionFrom(clean, '--slide');
|
|
317
|
+
const shapeType = optionFrom(clean, '--type');
|
|
318
|
+
if (!slide || !shapeType)
|
|
319
|
+
throw new Error('Usage: deckuse add shape --slide <n> --type <text|rect|rounded-rect|ellipse|line|image|group|table|chart|video|audio>');
|
|
320
|
+
const rowsRaw = optionFrom(clean, '--rows');
|
|
321
|
+
let rows;
|
|
322
|
+
if (rowsRaw !== undefined) {
|
|
323
|
+
try {
|
|
324
|
+
const parsed = JSON.parse(rowsRaw);
|
|
325
|
+
if (!Array.isArray(parsed) ||
|
|
326
|
+
!parsed.every((row) => Array.isArray(row) && row.every((cell) => typeof cell === 'string'))) {
|
|
327
|
+
throw new Error('expected string[][]');
|
|
328
|
+
}
|
|
329
|
+
rows = parsed;
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
throw new Error(`--rows must be JSON string[][] (example: --rows '[["A","B"],["1","2"]]')`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const dataRaw = optionFrom(clean, '--data');
|
|
336
|
+
let data;
|
|
337
|
+
if (dataRaw !== undefined) {
|
|
338
|
+
try {
|
|
339
|
+
data = JSON.parse(dataRaw);
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
throw new Error(`--data must be JSON (example: --data '{"categories":["Q1"],"series":[{"name":"S1","values":[1]}]}')`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const chartType = optionFrom(clean, '--chart-type');
|
|
346
|
+
ok = await execute('deckuse add shape', {
|
|
347
|
+
...base,
|
|
348
|
+
type: 'addShape',
|
|
349
|
+
slide: Number(slide),
|
|
350
|
+
shapeType,
|
|
351
|
+
...(optionFrom(clean, '--name') ? { name: optionFrom(clean, '--name') } : {}),
|
|
352
|
+
...(optionFrom(clean, '--role') ? { role: optionFrom(clean, '--role') } : {}),
|
|
353
|
+
...(optionFrom(clean, '--x') ? { x: Number(optionFrom(clean, '--x')) } : {}),
|
|
354
|
+
...(optionFrom(clean, '--y') ? { y: Number(optionFrom(clean, '--y')) } : {}),
|
|
355
|
+
...(optionFrom(clean, '--width') ? { width: Number(optionFrom(clean, '--width')) } : {}),
|
|
356
|
+
...(optionFrom(clean, '--height')
|
|
357
|
+
? { height: Number(optionFrom(clean, '--height')) }
|
|
358
|
+
: {}),
|
|
359
|
+
...(optionFrom(clean, '--file') ? { file: optionFrom(clean, '--file') } : {}),
|
|
360
|
+
...(optionFrom(clean, '--text') !== undefined
|
|
361
|
+
? { text: optionFrom(clean, '--text') }
|
|
362
|
+
: {}),
|
|
363
|
+
...(rows !== undefined ? { rows } : {}),
|
|
364
|
+
...(chartType ? { chartType } : {}),
|
|
365
|
+
...(data !== undefined ? { data } : {}),
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
else
|
|
369
|
+
throw new Error('Usage: deckuse add <slide|shape> ...');
|
|
370
|
+
}
|
|
371
|
+
else if (action === 'remove') {
|
|
372
|
+
const target = clean[1];
|
|
373
|
+
if (!target)
|
|
374
|
+
throw new Error('Usage: deckuse remove <target>');
|
|
375
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
376
|
+
ok = await execute('deckuse remove', {
|
|
377
|
+
...(await mutationExtras(workspace)),
|
|
378
|
+
type: 'remove',
|
|
379
|
+
target,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
else if (action === 'set') {
|
|
383
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
384
|
+
const base = await mutationExtras(workspace);
|
|
385
|
+
if (clean[1] === 'text') {
|
|
386
|
+
const target = clean[2];
|
|
387
|
+
const value = optionFrom(clean, '--value');
|
|
388
|
+
if (!target || value === undefined)
|
|
389
|
+
throw new Error('Usage: deckuse set text <target> --value <text>');
|
|
390
|
+
ok = await execute('deckuse set text', {
|
|
391
|
+
...base,
|
|
392
|
+
type: 'setText',
|
|
393
|
+
target,
|
|
394
|
+
value,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
const target = clean[1];
|
|
399
|
+
if (!target)
|
|
400
|
+
throw new Error('Usage: deckuse set <target> --font.size 42 ...');
|
|
401
|
+
const props = parseProps(clean.slice(2));
|
|
402
|
+
delete props['scope'];
|
|
403
|
+
const scope = optionFrom(clean, '--scope') ?? 'local';
|
|
404
|
+
// remove flag keys that are not properties
|
|
405
|
+
for (const key of Object.keys(props)) {
|
|
406
|
+
if (['expect-revision', 'reason', 'dry-run', 'workspace', 'json', 'quiet'].includes(key))
|
|
407
|
+
delete props[key];
|
|
408
|
+
}
|
|
409
|
+
ok = await execute('deckuse set', {
|
|
410
|
+
...base,
|
|
411
|
+
type: 'set',
|
|
412
|
+
target,
|
|
413
|
+
properties: props,
|
|
414
|
+
scope,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
else if (action === 'replace-text') {
|
|
419
|
+
const source = optionFrom(clean, '--source');
|
|
420
|
+
const target = optionFrom(clean, '--target');
|
|
421
|
+
if (source === undefined || target === undefined)
|
|
422
|
+
throw new Error('Usage: deckuse replace-text --source <text> --target <text> [--regex] [--limit <n>] [--selector <sel>]');
|
|
423
|
+
if (!source)
|
|
424
|
+
throw new Error('replace-text --source must be a non-empty string');
|
|
425
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
426
|
+
ok = await execute('deckuse replace-text', {
|
|
427
|
+
...(await mutationExtras(workspace)),
|
|
428
|
+
type: 'replaceText',
|
|
429
|
+
find: source,
|
|
430
|
+
replace: target,
|
|
431
|
+
...(clean.includes('--regex') ? { regex: true } : {}),
|
|
432
|
+
...(optionFrom(clean, '--limit')
|
|
433
|
+
? { limit: Number(optionFrom(clean, '--limit')) }
|
|
434
|
+
: {}),
|
|
435
|
+
...(optionFrom(clean, '--selector')
|
|
436
|
+
? { selector: optionFrom(clean, '--selector') }
|
|
437
|
+
: {}),
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
else if (action === 'xfrm') {
|
|
441
|
+
if (clean[1] !== 'set')
|
|
442
|
+
throw new Error('Usage: deckuse xfrm set --slide <n> --shape <id> ...');
|
|
443
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
444
|
+
const slide = optionFrom(clean, '--slide');
|
|
445
|
+
const shape = optionFrom(clean, '--shape');
|
|
446
|
+
const target = optionFrom(clean, '--target') ??
|
|
447
|
+
(slide && shape ? `slide:${slide}/shape:${shape}` : undefined);
|
|
448
|
+
if (!target)
|
|
449
|
+
throw new Error('xfrm set requires --target or --slide and --shape');
|
|
450
|
+
ok = await execute('deckuse xfrm set', {
|
|
451
|
+
...(await mutationExtras(workspace)),
|
|
452
|
+
type: 'xfrmSet',
|
|
453
|
+
target,
|
|
454
|
+
...(optionFrom(clean, '--x') ? { x: Number(optionFrom(clean, '--x')) } : {}),
|
|
455
|
+
...(optionFrom(clean, '--y') ? { y: Number(optionFrom(clean, '--y')) } : {}),
|
|
456
|
+
...(optionFrom(clean, '--width') || optionFrom(clean, '--cx')
|
|
457
|
+
? { width: Number(optionFrom(clean, '--width') ?? optionFrom(clean, '--cx')) }
|
|
458
|
+
: {}),
|
|
459
|
+
...(optionFrom(clean, '--height') || optionFrom(clean, '--cy')
|
|
460
|
+
? { height: Number(optionFrom(clean, '--height') ?? optionFrom(clean, '--cy')) }
|
|
461
|
+
: {}),
|
|
462
|
+
...(optionFrom(clean, '--rotation')
|
|
463
|
+
? { rotation: Number(optionFrom(clean, '--rotation')) }
|
|
464
|
+
: {}),
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
else if (action === 'z') {
|
|
468
|
+
if (clean[1] !== 'move')
|
|
469
|
+
throw new Error('Usage: deckuse z move <target> --above <target>');
|
|
470
|
+
const target = clean[2];
|
|
471
|
+
if (!target)
|
|
472
|
+
throw new Error('Usage: deckuse z move <target> ...');
|
|
473
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
474
|
+
ok = await execute('deckuse z move', {
|
|
475
|
+
...(await mutationExtras(workspace)),
|
|
476
|
+
type: 'zMove',
|
|
477
|
+
target,
|
|
478
|
+
...(optionFrom(clean, '--above') ? { above: optionFrom(clean, '--above') } : {}),
|
|
479
|
+
...(optionFrom(clean, '--below') ? { below: optionFrom(clean, '--below') } : {}),
|
|
480
|
+
...(clean.includes('--to-front') ? { toFront: true } : {}),
|
|
481
|
+
...(clean.includes('--to-back') ? { toBack: true } : {}),
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
else if (action === 'apply') {
|
|
485
|
+
const input = optionFrom(clean, '--input') ?? '-';
|
|
486
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
487
|
+
const raw = input === '-' ? await readStdin() : await readFile(resolve(input), 'utf8');
|
|
488
|
+
let values;
|
|
489
|
+
let transactionOps;
|
|
490
|
+
try {
|
|
491
|
+
const parsed = JSON.parse(raw);
|
|
492
|
+
if (typeof parsed === 'object' &&
|
|
493
|
+
parsed !== null &&
|
|
494
|
+
Array.isArray(parsed.operations)) {
|
|
495
|
+
transactionOps = parsed.operations;
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
values = Array.isArray(parsed) ? parsed : [parsed];
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
values = raw
|
|
503
|
+
.split(/\r?\n/)
|
|
504
|
+
.filter(Boolean)
|
|
505
|
+
.map((line) => JSON.parse(line));
|
|
506
|
+
}
|
|
507
|
+
if (transactionOps) {
|
|
508
|
+
ok = await execute('deckuse apply', {
|
|
509
|
+
...(await mutationExtras(workspace)),
|
|
510
|
+
type: 'applyTransaction',
|
|
511
|
+
operations: transactionOps,
|
|
512
|
+
});
|
|
196
513
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
514
|
+
else {
|
|
515
|
+
const extras = await mutationExtras(workspace);
|
|
516
|
+
const WRITE = new Set([
|
|
517
|
+
'setText',
|
|
518
|
+
'replaceText',
|
|
519
|
+
'setTransform',
|
|
520
|
+
'setProperties',
|
|
521
|
+
'set',
|
|
522
|
+
'xfrmSet',
|
|
523
|
+
'zMove',
|
|
524
|
+
'add',
|
|
525
|
+
'addSlide',
|
|
526
|
+
'addShape',
|
|
527
|
+
'remove',
|
|
528
|
+
'replacePicture',
|
|
529
|
+
'duplicate',
|
|
530
|
+
'batch',
|
|
531
|
+
]);
|
|
532
|
+
const list = values ?? [];
|
|
533
|
+
if (list.length > 0 &&
|
|
534
|
+
list.every((value) => typeof value === 'object' &&
|
|
535
|
+
value !== null &&
|
|
536
|
+
'op' in value)) {
|
|
537
|
+
ok = await execute('deckuse apply', {
|
|
538
|
+
...extras,
|
|
539
|
+
type: 'applyTransaction',
|
|
540
|
+
operations: list,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
const commands = list.map((value) => {
|
|
545
|
+
if (typeof value !== 'object' || value === null)
|
|
546
|
+
throw new Error('apply input must contain command objects');
|
|
547
|
+
const record = value;
|
|
548
|
+
if (record['type'] === 'batch')
|
|
549
|
+
return record;
|
|
550
|
+
if (!WRITE.has(String(record['type'])))
|
|
551
|
+
throw new Error(`apply input contains non-write command: ${String(record['type'])}`);
|
|
552
|
+
return { ...extras, ...record };
|
|
553
|
+
});
|
|
554
|
+
const payload = commands.length === 1 && commands[0]?.['type'] !== 'batch'
|
|
555
|
+
? commands[0]
|
|
556
|
+
: {
|
|
557
|
+
...extras,
|
|
558
|
+
type: 'batch',
|
|
559
|
+
atomic: true,
|
|
560
|
+
commands: commands.flatMap((command) => command['type'] === 'batch'
|
|
561
|
+
? command.commands
|
|
562
|
+
: [command]),
|
|
563
|
+
};
|
|
564
|
+
ok = await execute('deckuse apply', payload);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
else if (action === 'validate') {
|
|
569
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
570
|
+
ok = await execute('deckuse validate', {
|
|
571
|
+
version: PROTOCOL_VERSION,
|
|
572
|
+
type: 'validate',
|
|
200
573
|
workspaceId: workspace,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
574
|
+
level: optionFrom(clean, '--level') ?? 'full',
|
|
575
|
+
package: clean.includes('--package'),
|
|
576
|
+
relationships: clean.includes('--relationships'),
|
|
577
|
+
...(optionFrom(clean, '--slide') ? { slide: Number(optionFrom(clean, '--slide')) } : {}),
|
|
204
578
|
});
|
|
205
|
-
}
|
|
206
|
-
else if (action === 'commit') {
|
|
207
|
-
const workspace = clean[1];
|
|
208
|
-
if (!workspace)
|
|
209
|
-
throw new Error('Usage: deckuse commit workspace/ -o output.pptx [--force]');
|
|
210
|
-
const force = clean.includes('--force') || clean.includes('-f');
|
|
211
|
-
ok = await execute({
|
|
212
|
-
version: '1.0',
|
|
213
|
-
type: 'commit',
|
|
214
|
-
workspaceId: workspace,
|
|
215
|
-
transactionId: await revisionFor(workspace),
|
|
216
|
-
...(option('-o') || option('--output')
|
|
217
|
-
? { destination: option('-o') ?? option('--output') }
|
|
218
|
-
: {}),
|
|
219
|
-
...(force ? { overwrite: true } : {}),
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
const workspace = clean[1], input = option('--input') ?? '-';
|
|
224
|
-
if (!workspace)
|
|
225
|
-
throw new Error('Usage: deckuse apply workspace/ --input file|-');
|
|
226
|
-
const raw = input === '-' ? await readStdin() : await readFile(resolve(input), 'utf8');
|
|
227
|
-
let values;
|
|
228
|
-
try {
|
|
229
|
-
const parsed = JSON.parse(raw);
|
|
230
|
-
values = Array.isArray(parsed) ? parsed : [parsed];
|
|
231
579
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
580
|
+
else if (action === 'history') {
|
|
581
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
582
|
+
ok = await execute('deckuse history', {
|
|
583
|
+
version: PROTOCOL_VERSION,
|
|
584
|
+
type: 'history',
|
|
585
|
+
workspaceId: workspace,
|
|
586
|
+
limit: Number(optionFrom(clean, '--limit') ?? 100),
|
|
587
|
+
offset: Number(optionFrom(clean, '--offset') ?? 0),
|
|
588
|
+
...(optionFrom(clean, '--slide') ? { slide: Number(optionFrom(clean, '--slide')) } : {}),
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
else if (action === 'undo') {
|
|
592
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
593
|
+
ok = await execute('deckuse undo', {
|
|
594
|
+
version: PROTOCOL_VERSION,
|
|
595
|
+
type: 'undo',
|
|
596
|
+
workspaceId: workspace,
|
|
597
|
+
steps: Number(optionFrom(clean, '--steps') ?? 1),
|
|
598
|
+
});
|
|
237
599
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
600
|
+
else if (action === 'export') {
|
|
601
|
+
const output = clean[1];
|
|
602
|
+
if (!output)
|
|
603
|
+
throw new Error('Usage: deckuse export <output.pptx>');
|
|
604
|
+
const workspace = await findWorkspace(workspaceOpt);
|
|
605
|
+
ok = await execute('deckuse export', {
|
|
606
|
+
version: PROTOCOL_VERSION,
|
|
607
|
+
type: 'export',
|
|
243
608
|
workspaceId: workspace,
|
|
244
|
-
|
|
245
|
-
...
|
|
609
|
+
output: resolve(output),
|
|
610
|
+
...(revisionOpt ? { revision: revisionOpt } : {}),
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
else if (action === 'monitor') {
|
|
614
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
615
|
+
const port = Number(optionFrom(clean, '--port') ?? 4173);
|
|
616
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535)
|
|
617
|
+
throw new Error('--port must be an integer between 0 and 65535');
|
|
618
|
+
const monitor = await startMonitor(workspace, {
|
|
619
|
+
host: optionFrom(clean, '--host') ?? '0.0.0.0',
|
|
620
|
+
port,
|
|
621
|
+
});
|
|
622
|
+
process.stdout.write(`Deckuse monitor: ${monitor.url}\n`);
|
|
623
|
+
const shutdown = async (signal) => {
|
|
624
|
+
process.stderr.write(`deckuse monitor: received ${signal}, shutting down\n`);
|
|
625
|
+
await monitor.close();
|
|
626
|
+
process.exit(0);
|
|
246
627
|
};
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
628
|
+
process.once('SIGINT', () => void shutdown('SIGINT'));
|
|
629
|
+
process.once('SIGTERM', () => void shutdown('SIGTERM'));
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
else if (action === 'render') {
|
|
633
|
+
const pageRaw = optionFrom(clean, '--page');
|
|
634
|
+
if (!pageRaw)
|
|
635
|
+
throw new Error('Usage: deckuse render --page <n> [--output <file.png>]');
|
|
636
|
+
if (/\s|,|-/.test(pageRaw))
|
|
637
|
+
throw new Error('--page accepts exactly one positive integer (not a range or list)');
|
|
638
|
+
const page = Number(pageRaw);
|
|
639
|
+
if (!Number.isInteger(page) || page < 1)
|
|
640
|
+
throw new Error('--page must be a positive integer');
|
|
641
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
642
|
+
const outputOpt = optionFrom(clean, '--output');
|
|
643
|
+
try {
|
|
644
|
+
const rendered = await renderPage(workspace, {
|
|
645
|
+
page,
|
|
646
|
+
...(outputOpt ? { output: resolve(outputOpt) } : {}),
|
|
647
|
+
});
|
|
648
|
+
outputEnvelope({
|
|
649
|
+
ok: true,
|
|
650
|
+
command: 'deckuse render',
|
|
651
|
+
data: { page: rendered.page, output: rendered.output },
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
catch (error) {
|
|
655
|
+
outputEnvelope({
|
|
656
|
+
ok: false,
|
|
657
|
+
command: 'deckuse render',
|
|
658
|
+
error: {
|
|
659
|
+
code: 'RENDER_FAILED',
|
|
660
|
+
message: error instanceof Error ? error.message : 'Render failed',
|
|
661
|
+
},
|
|
662
|
+
});
|
|
663
|
+
ok = false;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
else if (action === 'query') {
|
|
667
|
+
// Back-compat shim
|
|
668
|
+
const workspace = await findWorkspace(workspaceOpt ?? clean[1]);
|
|
669
|
+
ok = await execute('deckuse query', {
|
|
670
|
+
version: PROTOCOL_VERSION,
|
|
671
|
+
type: 'query',
|
|
672
|
+
workspaceId: workspace,
|
|
673
|
+
selector: clean[2] ?? '*',
|
|
674
|
+
limit: Number(optionFrom(clean, '--limit') ?? 100),
|
|
675
|
+
});
|
|
250
676
|
}
|
|
677
|
+
else {
|
|
678
|
+
throw new Error(`Unknown command: ${action}`);
|
|
679
|
+
}
|
|
680
|
+
if (!ok)
|
|
681
|
+
process.exitCode = 1;
|
|
251
682
|
}
|
|
252
|
-
if (!ok)
|
|
253
|
-
process.exitCode = 1;
|
|
254
683
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
684
|
+
catch (cause) {
|
|
685
|
+
process.stderr.write(`deckuse: ${cause instanceof Error ? cause.message : 'Invalid input'}\n`);
|
|
686
|
+
process.exitCode = 2;
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
void main();
|
|
260
690
|
//# sourceMappingURL=bin.js.map
|