izuemon commited on
Commit
be5a4b8
·
verified ·
1 Parent(s): 74e6b59

Update generate_html.cjs

Browse files
Files changed (1) hide show
  1. generate_html.cjs +406 -61
generate_html.cjs CHANGED
@@ -4,8 +4,11 @@ const fs = require("fs");
4
 
5
  // Scratch プロジェクトデータを取得
6
  async function fetchProjectData(projectId) {
7
- const metaRes = await fetch(`https://api.scratch.mit.edu/projects/${encodeURIComponent(projectId)}`);
 
 
8
  if (!metaRes.ok) throw new Error(`project metadata fetch failed: ${metaRes.status}`);
 
9
  const meta = await metaRes.json();
10
  const token = meta.project_token;
11
  if (!token) throw new Error("project_token が取得できませんでした");
@@ -14,9 +17,63 @@ async function fetchProjectData(projectId) {
14
  `https://projects.scratch.mit.edu/${encodeURIComponent(projectId)}?token=${encodeURIComponent(token)}`
15
  );
16
  if (!projectRes.ok) throw new Error(`project data fetch failed: ${projectRes.status}`);
 
17
  return Buffer.from(await projectRes.arrayBuffer());
18
  }
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  // URL から画像を Packager.Image に変換
21
  async function imageFromUrl(url) {
22
  if (!url) return undefined;
@@ -27,97 +84,385 @@ async function imageFromUrl(url) {
27
  return new Packager.Image(contentType, buffer);
28
  }
29
 
30
- // 真偽変換ユーティリティ
31
- function bool(v, fallback = false) {
32
- if (v === undefined || v === null || v === "") return fallback;
33
- if (typeof v === "boolean") return v;
34
- return String(v).toLowerCase() === "true" || v === "1" || String(v).toLowerCase() === "yes";
35
- }
36
 
37
- async function main() {
38
- const projectId = process.argv[2];
39
- const optionsJson = process.argv[3];
40
- if (!projectId) throw new Error("project id required");
41
 
42
- const options = optionsJson ? JSON.parse(fs.readFileSync(optionsJson, "utf8")) : {};
43
- const projectData = await fetchProjectData(projectId);
44
- const loadedProject = await Packager.loadProject(projectData);
45
 
46
- const packager = new Packager.Packager();
47
- packager.project = loadedProject;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  // 基本オプション
50
- if ("turbo" in options) packager.options.turbo = bool(options.turbo);
51
- if ("interpolation" in options) packager.options.interpolation = bool(options.interpolation);
52
- if ("highQualityPen" in options) packager.options.highQualityPen = bool(options.highQualityPen);
53
- if ("maxClones" in options) packager.options.maxClones = Number(options.maxClones);
54
- if ("stageWidth" in options) packager.options.stageWidth = Number(options.stageWidth);
55
- if ("stageHeight" in options) packager.options.stageHeight = Number(options.stageHeight);
56
- if ("resizeMode" in options) packager.options.resizeMode = options.resizeMode;
57
- if ("autoplay" in options) packager.options.autoplay = bool(options.autoplay);
58
- if ("username" in options) packager.options.username = options.username;
59
- if ("closeWhenStopped" in options) packager.options.closeWhenStopped = bool(options.closeWhenStopped);
60
-
61
- // カスタム CSS/JS
62
- if (options.custom?.js) packager.options.custom.js = options.custom.js;
63
- if (options.custom?.css) packager.options.custom.css = options.custom.css;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
  // appearance
66
- if (options.appearance) {
67
- packager.options.appearance.background = options.appearance.background || packager.options.appearance.background;
68
- packager.options.appearance.foreground = options.appearance.foreground || packager.options.appearance.foreground;
69
- if (options.appearance.accent) packager.options.appearance.accent = options.appearance.accent;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
  // loadingScreen
73
- if (options.loadingScreen) {
74
- packager.options.loadingScreen.progressBar = bool(options.loadingScreen.progressBar, true);
75
- if (typeof options.loadingScreen.text === "string") {
76
- packager.options.loadingScreen.text = options.loadingScreen.text;
 
 
77
  }
78
- if (typeof options.loadingScreen.imageMode === "string") {
79
- packager.options.loadingScreen.imageMode = options.loadingScreen.imageMode;
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  }
81
- const loadingImage = await imageFromUrl(options.loadingScreen.image);
82
- if (loadingImage) packager.options.loadingScreen.image = loadingImage;
83
  }
84
 
85
- // app
86
- if (options.app) {
87
- if (typeof options.app.windowTitle === "string" && options.app.windowTitle.trim() !== "") {
88
- packager.options.app.windowTitle = options.app.windowTitle;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
90
- const icon = await imageFromUrl(options.app.icon);
91
- if (icon) packager.options.app.icon = icon;
92
  }
93
 
94
  // compiler
95
- if (options.compiler) {
96
- packager.options.compiler.enabled = bool(options.compiler.enabled);
97
- packager.options.compiler.warpTimer = bool(options.compiler.warpTimer);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
 
100
  // chunks
101
- if (options.chunks) {
102
- packager.options.chunks.gamepad = bool(options.chunks.gamepad);
103
- packager.options.chunks.pointerlock = bool(options.chunks.pointerlock);
 
 
 
 
 
 
 
104
  }
105
 
106
  // cloudVariables
107
- if (options.cloudVariables) {
108
- packager.options.cloudVariables.mode = options.cloudVariables.mode || packager.options.cloudVariables.mode;
109
- packager.options.cloudVariables.cloudHost = options.cloudVariables.cloudHost || packager.options.cloudVariables.cloudHost;
110
- packager.options.cloudVariables.specialCloudBehaviors = bool(options.cloudVariables.specialCloudBehaviors);
111
- packager.options.cloudVariables.unsafeCloudBehaviors = bool(options.cloudVariables.unsafeCloudBehaviors);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  }
113
 
114
  // bakeExtensions
115
- if ("bakeExtensions" in options) packager.options.bakeExtensions = bool(options.bakeExtensions);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  // パッケージ作成
118
  const result = await packager.package();
119
 
120
- // バイナリデータとして出力
121
  process.stdout.write(Buffer.from(result.data));
122
  }
123
 
 
4
 
5
  // Scratch プロジェクトデータを取得
6
  async function fetchProjectData(projectId) {
7
+ const metaRes = await fetch(
8
+ `https://api.scratch.mit.edu/projects/${encodeURIComponent(projectId)}`
9
+ );
10
  if (!metaRes.ok) throw new Error(`project metadata fetch failed: ${metaRes.status}`);
11
+
12
  const meta = await metaRes.json();
13
  const token = meta.project_token;
14
  if (!token) throw new Error("project_token が取得できませんでした");
 
17
  `https://projects.scratch.mit.edu/${encodeURIComponent(projectId)}?token=${encodeURIComponent(token)}`
18
  );
19
  if (!projectRes.ok) throw new Error(`project data fetch failed: ${projectRes.status}`);
20
+
21
  return Buffer.from(await projectRes.arrayBuffer());
22
  }
23
 
24
+ // options 引数を「ファイルパス」または「JSON文字列」として読み込む
25
+ function readOptionsArg(arg) {
26
+ if (!arg) return {};
27
+ try {
28
+ if (fs.existsSync(arg) && fs.statSync(arg).isFile()) {
29
+ return JSON.parse(fs.readFileSync(arg, "utf8"));
30
+ }
31
+ } catch {
32
+ // ファイルとして読めなければ JSON 文字列として解釈する
33
+ }
34
+ return JSON.parse(arg);
35
+ }
36
+
37
+ function isPlainObject(v) {
38
+ return v !== null && typeof v === "object" && !Array.isArray(v);
39
+ }
40
+
41
+ function asBool(v, fallback = false) {
42
+ if (v === undefined || v === null || v === "") return fallback;
43
+ if (typeof v === "boolean") return v;
44
+ if (typeof v === "number") return v !== 0;
45
+ const s = String(v).toLowerCase();
46
+ return s === "true" || s === "1" || s === "yes" || s === "on";
47
+ }
48
+
49
+ function asNumber(v, fallback) {
50
+ if (v === undefined || v === null || v === "") return fallback;
51
+ const n = Number(v);
52
+ return Number.isFinite(n) ? n : fallback;
53
+ }
54
+
55
+ function asInt(v, fallback) {
56
+ const n = asNumber(v, NaN);
57
+ return Number.isFinite(n) ? Math.trunc(n) : fallback;
58
+ }
59
+
60
+ function asString(v, fallback) {
61
+ if (v === undefined || v === null) return fallback;
62
+ if (typeof v === "string") return v;
63
+ return String(v);
64
+ }
65
+
66
+ function asNonEmptyString(v, fallback) {
67
+ if (typeof v === "string" && v.trim() !== "") return v;
68
+ return fallback;
69
+ }
70
+
71
+ function asStringArray(v, fallback = []) {
72
+ if (Array.isArray(v)) return v.filter((x) => typeof x === "string");
73
+ if (typeof v === "string" && v.trim() !== "") return [v];
74
+ return fallback;
75
+ }
76
+
77
  // URL から画像を Packager.Image に変換
78
  async function imageFromUrl(url) {
79
  if (!url) return undefined;
 
84
  return new Packager.Image(contentType, buffer);
85
  }
86
 
87
+ // 画像として受け取るを正規化する
88
+ async function imageFromValue(value) {
89
+ if (value === undefined) return undefined;
90
+ if (value === null || value === "") return null;
 
 
91
 
92
+ // JSON 側では通常ここには来ないが、コード直書きの場合も吸収する
93
+ if (typeof value === "string") {
94
+ return await imageFromUrl(value);
95
+ }
96
 
97
+ if (typeof Packager.Image === "function" && value instanceof Packager.Image) {
98
+ return value;
99
+ }
100
 
101
+ // 互換用: { contentType, buffer } っぽい形を受けた場合
102
+ if (
103
+ isPlainObject(value) &&
104
+ typeof value.contentType === "string" &&
105
+ value.buffer !== undefined
106
+ ) {
107
+ const buf = Buffer.isBuffer(value.buffer) ? value.buffer : Buffer.from(value.buffer);
108
+ return new Packager.Image(value.contentType, buf);
109
+ }
110
+
111
+ throw new Error("画像は URL 文字列、null、または Packager.Image で指定してください");
112
+ }
113
+
114
+ async function applyOptions(packager, options, fallbackProjectId) {
115
+ if (!isPlainObject(options)) options = {};
116
+
117
+ // projectId は cloudVariables などでも使うので、CLI引数を既定値にする
118
+ packager.options.projectId = asNonEmptyString(options.projectId, fallbackProjectId);
119
 
120
  // 基本オプション
121
+ if ("turbo" in options) packager.options.turbo = asBool(options.turbo, packager.options.turbo);
122
+ if ("interpolation" in options) {
123
+ packager.options.interpolation = asBool(options.interpolation, packager.options.interpolation);
124
+ }
125
+ if ("framerate" in options) {
126
+ packager.options.framerate = asNumber(options.framerate, packager.options.framerate);
127
+ }
128
+ if ("highQualityPen" in options) {
129
+ packager.options.highQualityPen = asBool(options.highQualityPen, packager.options.highQualityPen);
130
+ }
131
+ if ("maxClones" in options) {
132
+ packager.options.maxClones = asInt(options.maxClones, packager.options.maxClones);
133
+ }
134
+ if ("fencing" in options) {
135
+ packager.options.fencing = asBool(options.fencing, packager.options.fencing);
136
+ }
137
+ if ("miscLimits" in options) {
138
+ packager.options.miscLimits = asBool(options.miscLimits, packager.options.miscLimits);
139
+ }
140
+ if ("stageWidth" in options) {
141
+ packager.options.stageWidth = asInt(options.stageWidth, packager.options.stageWidth);
142
+ }
143
+ if ("stageHeight" in options) {
144
+ packager.options.stageHeight = asInt(options.stageHeight, packager.options.stageHeight);
145
+ }
146
+ if ("resizeMode" in options) {
147
+ packager.options.resizeMode = asNonEmptyString(options.resizeMode, packager.options.resizeMode);
148
+ }
149
+ if ("autoplay" in options) {
150
+ packager.options.autoplay = asBool(options.autoplay, packager.options.autoplay);
151
+ }
152
+ if ("username" in options) {
153
+ packager.options.username = asNonEmptyString(options.username, packager.options.username);
154
+ }
155
+ if ("closeWhenStopped" in options) {
156
+ packager.options.closeWhenStopped = asBool(
157
+ options.closeWhenStopped,
158
+ packager.options.closeWhenStopped
159
+ );
160
+ }
161
+
162
+ if ("packagedRuntime" in options) {
163
+ packager.options.packagedRuntime = asBool(
164
+ options.packagedRuntime,
165
+ packager.options.packagedRuntime
166
+ );
167
+ }
168
+ if ("target" in options) {
169
+ packager.options.target = asNonEmptyString(options.target, packager.options.target);
170
+ }
171
+ if ("maxTextureDimension" in options) {
172
+ packager.options.maxTextureDimension = asInt(
173
+ options.maxTextureDimension,
174
+ packager.options.maxTextureDimension
175
+ );
176
+ }
177
+
178
+ // custom
179
+ if (isPlainObject(options.custom)) {
180
+ if ("css" in options.custom) {
181
+ packager.options.custom.css = asString(options.custom.css, packager.options.custom.css);
182
+ }
183
+ if ("js" in options.custom) {
184
+ packager.options.custom.js = asString(options.custom.js, packager.options.custom.js);
185
+ }
186
+ }
187
 
188
  // appearance
189
+ if (isPlainObject(options.appearance)) {
190
+ if ("background" in options.appearance) {
191
+ packager.options.appearance.background = asNonEmptyString(
192
+ options.appearance.background,
193
+ packager.options.appearance.background
194
+ );
195
+ }
196
+ if ("foreground" in options.appearance) {
197
+ packager.options.appearance.foreground = asNonEmptyString(
198
+ options.appearance.foreground,
199
+ packager.options.appearance.foreground
200
+ );
201
+ }
202
+ if ("accent" in options.appearance) {
203
+ packager.options.appearance.accent = asNonEmptyString(
204
+ options.appearance.accent,
205
+ packager.options.appearance.accent
206
+ );
207
+ }
208
  }
209
 
210
  // loadingScreen
211
+ if (isPlainObject(options.loadingScreen)) {
212
+ if ("progressBar" in options.loadingScreen) {
213
+ packager.options.loadingScreen.progressBar = asBool(
214
+ options.loadingScreen.progressBar,
215
+ packager.options.loadingScreen.progressBar
216
+ );
217
  }
218
+ if ("text" in options.loadingScreen) {
219
+ packager.options.loadingScreen.text = asString(
220
+ options.loadingScreen.text,
221
+ packager.options.loadingScreen.text
222
+ );
223
+ }
224
+ if ("imageMode" in options.loadingScreen) {
225
+ packager.options.loadingScreen.imageMode = asNonEmptyString(
226
+ options.loadingScreen.imageMode,
227
+ packager.options.loadingScreen.imageMode
228
+ );
229
+ }
230
+ if ("image" in options.loadingScreen) {
231
+ const loadingImage = await imageFromValue(options.loadingScreen.image);
232
+ packager.options.loadingScreen.image = loadingImage ?? null;
233
  }
 
 
234
  }
235
 
236
+ // controls
237
+ if (isPlainObject(options.controls)) {
238
+ if (isPlainObject(options.controls.greenFlag) && "enabled" in options.controls.greenFlag) {
239
+ packager.options.controls.greenFlag.enabled = asBool(
240
+ options.controls.greenFlag.enabled,
241
+ packager.options.controls.greenFlag.enabled
242
+ );
243
+ }
244
+ if (isPlainObject(options.controls.stopAll) && "enabled" in options.controls.stopAll) {
245
+ packager.options.controls.stopAll.enabled = asBool(
246
+ options.controls.stopAll.enabled,
247
+ packager.options.controls.stopAll.enabled
248
+ );
249
+ }
250
+ if (isPlainObject(options.controls.fullscreen) && "enabled" in options.controls.fullscreen) {
251
+ packager.options.controls.fullscreen.enabled = asBool(
252
+ options.controls.fullscreen.enabled,
253
+ packager.options.controls.fullscreen.enabled
254
+ );
255
+ }
256
+ if (isPlainObject(options.controls.pause) && "enabled" in options.controls.pause) {
257
+ packager.options.controls.pause.enabled = asBool(
258
+ options.controls.pause.enabled,
259
+ packager.options.controls.pause.enabled
260
+ );
261
+ }
262
+ }
263
+
264
+ // monitors
265
+ if (isPlainObject(options.monitors)) {
266
+ if ("editableLists" in options.monitors) {
267
+ packager.options.monitors.editableLists = asBool(
268
+ options.monitors.editableLists,
269
+ packager.options.monitors.editableLists
270
+ );
271
+ }
272
+ if ("variableColor" in options.monitors) {
273
+ packager.options.monitors.variableColor = asNonEmptyString(
274
+ options.monitors.variableColor,
275
+ packager.options.monitors.variableColor
276
+ );
277
+ }
278
+ if ("listColor" in options.monitors) {
279
+ packager.options.monitors.listColor = asNonEmptyString(
280
+ options.monitors.listColor,
281
+ packager.options.monitors.listColor
282
+ );
283
  }
 
 
284
  }
285
 
286
  // compiler
287
+ if (isPlainObject(options.compiler)) {
288
+ if ("enabled" in options.compiler) {
289
+ packager.options.compiler.enabled = asBool(
290
+ options.compiler.enabled,
291
+ packager.options.compiler.enabled
292
+ );
293
+ }
294
+ if ("warpTimer" in options.compiler) {
295
+ packager.options.compiler.warpTimer = asBool(
296
+ options.compiler.warpTimer,
297
+ packager.options.compiler.warpTimer
298
+ );
299
+ }
300
+ }
301
+
302
+ // app
303
+ if (isPlainObject(options.app)) {
304
+ if ("icon" in options.app) {
305
+ const icon = await imageFromValue(options.app.icon);
306
+ packager.options.app.icon = icon ?? null;
307
+ }
308
+ if ("packageName" in options.app) {
309
+ packager.options.app.packageName = asNonEmptyString(
310
+ options.app.packageName,
311
+ packager.options.app.packageName
312
+ );
313
+ }
314
+ if ("windowTitle" in options.app) {
315
+ packager.options.app.windowTitle = asNonEmptyString(
316
+ options.app.windowTitle,
317
+ packager.options.app.windowTitle
318
+ );
319
+ }
320
+ if ("windowMode" in options.app) {
321
+ packager.options.app.windowMode = asNonEmptyString(
322
+ options.app.windowMode,
323
+ packager.options.app.windowMode
324
+ );
325
+ }
326
+ if ("version" in options.app) {
327
+ packager.options.app.version = asNonEmptyString(options.app.version, packager.options.app.version);
328
+ }
329
+ if ("escapeBehavior" in options.app) {
330
+ packager.options.app.escapeBehavior = asNonEmptyString(
331
+ options.app.escapeBehavior,
332
+ packager.options.app.escapeBehavior
333
+ );
334
+ }
335
+ if ("windowControls" in options.app) {
336
+ packager.options.app.windowControls = asNonEmptyString(
337
+ options.app.windowControls,
338
+ packager.options.app.windowControls
339
+ );
340
+ }
341
+ if ("backgroundThrottling" in options.app) {
342
+ packager.options.app.backgroundThrottling = asBool(
343
+ options.app.backgroundThrottling,
344
+ packager.options.app.backgroundThrottling
345
+ );
346
+ }
347
  }
348
 
349
  // chunks
350
+ if (isPlainObject(options.chunks)) {
351
+ if ("gamepad" in options.chunks) {
352
+ packager.options.chunks.gamepad = asBool(options.chunks.gamepad, packager.options.chunks.gamepad);
353
+ }
354
+ if ("pointerlock" in options.chunks) {
355
+ packager.options.chunks.pointerlock = asBool(
356
+ options.chunks.pointerlock,
357
+ packager.options.chunks.pointerlock
358
+ );
359
+ }
360
  }
361
 
362
  // cloudVariables
363
+ if (isPlainObject(options.cloudVariables)) {
364
+ if ("mode" in options.cloudVariables) {
365
+ packager.options.cloudVariables.mode = asNonEmptyString(
366
+ options.cloudVariables.mode,
367
+ packager.options.cloudVariables.mode
368
+ );
369
+ }
370
+ if ("cloudHost" in options.cloudVariables) {
371
+ packager.options.cloudVariables.cloudHost = asNonEmptyString(
372
+ options.cloudVariables.cloudHost,
373
+ packager.options.cloudVariables.cloudHost
374
+ );
375
+ }
376
+ if ("custom" in options.cloudVariables && isPlainObject(options.cloudVariables.custom)) {
377
+ packager.options.cloudVariables.custom = { ...options.cloudVariables.custom };
378
+ }
379
+ if ("specialCloudBehaviors" in options.cloudVariables) {
380
+ packager.options.cloudVariables.specialCloudBehaviors = asBool(
381
+ options.cloudVariables.specialCloudBehaviors,
382
+ packager.options.cloudVariables.specialCloudBehaviors
383
+ );
384
+ }
385
+ if ("unsafeCloudBehaviors" in options.cloudVariables) {
386
+ packager.options.cloudVariables.unsafeCloudBehaviors = asBool(
387
+ options.cloudVariables.unsafeCloudBehaviors,
388
+ packager.options.cloudVariables.unsafeCloudBehaviors
389
+ );
390
+ }
391
+ }
392
+
393
+ // cursor
394
+ if (isPlainObject(options.cursor)) {
395
+ if ("type" in options.cursor) {
396
+ packager.options.cursor.type = asNonEmptyString(options.cursor.type, packager.options.cursor.type);
397
+ }
398
+ if ("custom" in options.cursor) {
399
+ const cursorImage = await imageFromValue(options.cursor.custom);
400
+ packager.options.cursor.custom = cursorImage ?? null;
401
+ }
402
+ if (isPlainObject(options.cursor.center)) {
403
+ if ("x" in options.cursor.center) {
404
+ packager.options.cursor.center.x = asNumber(
405
+ options.cursor.center.x,
406
+ packager.options.cursor.center.x
407
+ );
408
+ }
409
+ if ("y" in options.cursor.center) {
410
+ packager.options.cursor.center.y = asNumber(
411
+ options.cursor.center.y,
412
+ packager.options.cursor.center.y
413
+ );
414
+ }
415
+ }
416
+ }
417
+
418
+ // steamworks
419
+ if (isPlainObject(options.steamworks)) {
420
+ if ("appId" in options.steamworks) {
421
+ packager.options.steamworks.appId = asNonEmptyString(
422
+ options.steamworks.appId,
423
+ packager.options.steamworks.appId
424
+ );
425
+ }
426
+ if ("onError" in options.steamworks) {
427
+ packager.options.steamworks.onError = asNonEmptyString(
428
+ options.steamworks.onError,
429
+ packager.options.steamworks.onError
430
+ );
431
+ }
432
+ }
433
+
434
+ // extensions
435
+ if ("extensions" in options) {
436
+ packager.options.extensions = asStringArray(options.extensions, packager.options.extensions);
437
  }
438
 
439
  // bakeExtensions
440
+ if ("bakeExtensions" in options) {
441
+ packager.options.bakeExtensions = asBool(
442
+ options.bakeExtensions,
443
+ packager.options.bakeExtensions
444
+ );
445
+ }
446
+ }
447
+
448
+ async function main() {
449
+ const projectId = process.argv[2];
450
+ const optionsArg = process.argv[3];
451
+ if (!projectId) throw new Error("project id required");
452
+
453
+ const options = readOptionsArg(optionsArg);
454
+ const projectData = await fetchProjectData(projectId);
455
+ const loadedProject = await Packager.loadProject(projectData);
456
+
457
+ const packager = new Packager.Packager();
458
+ packager.project = loadedProject;
459
+
460
+ await applyOptions(packager, options, projectId);
461
 
462
  // パッケージ作成
463
  const result = await packager.package();
464
 
465
+ // 出力
466
  process.stdout.write(Buffer.from(result.data));
467
  }
468