@kubohiroya/turbowarp-asset-cache 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/dist/asset-cache.js +427 -85
- package/dist/composition.js +427 -85
- package/dist/types/extension.d.ts +3 -0
- package/dist/types/fixed-input-editors.d.ts +10 -0
- package/dist/types/fixed-input-schema.d.ts +46 -0
- package/docs/fixed-input-editors.ja.md +20 -0
- package/package.json +15 -6
- package/schemas/block-editor-fixed-inputs.schema.json +24 -0
package/README.md
CHANGED
|
@@ -4,6 +4,13 @@ A browser-local image, audio, and runtime-text asset cache for TurboWarp project
|
|
|
4
4
|
|
|
5
5
|
Asset Cache intentionally keeps the legacy `isLoaded` and cache lifecycle semantics. It is not a general server object store: every block is marked `server.supported: false` in the format 2 manifest. Use [`@kubohiroya/turbowarp-kvs`](https://github.com/kubohiroya/turbowarp-kvs) for portable namespace/key persistence and server lowering.
|
|
6
6
|
|
|
7
|
+
`@kubohiroya/turbowarp-asset-manager` is deprecated. Composition consumers can replace its import
|
|
8
|
+
path with `@kubohiroya/turbowarp-asset-cache/composition` for asset registration, rendering,
|
|
9
|
+
playback, DOM image resources, and verified remote-cache APIs. Import binary object, bundle, and
|
|
10
|
+
session-backing APIs directly from `@kubohiroya/turbowarp-kvs`. Standalone projects must also
|
|
11
|
+
replace the extension ID `kubohiroyaassetmanager` with `kubohiroyaassetcache`; published historical
|
|
12
|
+
SB3 artifacts should remain pinned to their original extension.
|
|
13
|
+
|
|
7
14
|
## User Guide
|
|
8
15
|
|
|
9
16
|
For setup, safety notes, recipes, and the illustrated block guide, see the [English user guide](https://kubohiroya.github.io/turbowarp-asset-cache/) or [Japanese user guide](https://kubohiroya.github.io/turbowarp-asset-cache/ja/).
|
|
@@ -41,13 +48,13 @@ The built JavaScript file is committed to this repository so users do not need t
|
|
|
41
48
|
The versioned npm package contains the same reviewed build:
|
|
42
49
|
|
|
43
50
|
```bash
|
|
44
|
-
pnpm add --save-exact @kubohiroya/turbowarp-asset-cache@0.2.
|
|
51
|
+
pnpm add --save-exact @kubohiroya/turbowarp-asset-cache@0.2.2
|
|
45
52
|
```
|
|
46
53
|
|
|
47
54
|
Load `node_modules/@kubohiroya/turbowarp-asset-cache/dist/asset-cache.js`, or use the version-pinned CDN URL:
|
|
48
55
|
|
|
49
56
|
```text
|
|
50
|
-
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-cache@0.2.
|
|
57
|
+
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-cache@0.2.2/dist/asset-cache.js
|
|
51
58
|
```
|
|
52
59
|
|
|
53
60
|
## Quick Start
|
package/dist/asset-cache.js
CHANGED
|
@@ -287,7 +287,404 @@
|
|
|
287
287
|
]
|
|
288
288
|
};
|
|
289
289
|
//#endregion
|
|
290
|
-
//#region node_modules/.pnpm/@kubohiroya+turbowarp-
|
|
290
|
+
//#region node_modules/.pnpm/@kubohiroya+turbowarp-extension-data-editor@0.2.1_react@18.3.1/node_modules/@kubohiroya/turbowarp-extension-data-editor/dist/fixed-input-schema.js
|
|
291
|
+
var numberToken = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
|
|
292
|
+
var invalidNumber = Object.freeze({
|
|
293
|
+
kind: "invalid",
|
|
294
|
+
code: "fixed-number-input-invalid"
|
|
295
|
+
});
|
|
296
|
+
/**
|
|
297
|
+
* Parse a NEW numeric draft according to NP-finite-new-input-v1.
|
|
298
|
+
* Never apply this to opening/no-op raw values or use it as an owner validator.
|
|
299
|
+
* Keep the validated token so negative zero, precision and exponent spelling survive.
|
|
300
|
+
*/
|
|
301
|
+
function parseFixedNumberInput(input) {
|
|
302
|
+
if (typeof input === "number") {
|
|
303
|
+
if (!Number.isFinite(input)) return invalidNumber;
|
|
304
|
+
return Object.freeze({
|
|
305
|
+
kind: "valid",
|
|
306
|
+
token: Object.is(input, -0) ? "-0" : String(input),
|
|
307
|
+
value: input
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (typeof input !== "string") return invalidNumber;
|
|
311
|
+
const token = input.trim();
|
|
312
|
+
if (!numberToken.test(token)) return invalidNumber;
|
|
313
|
+
const value = Number(token);
|
|
314
|
+
return Number.isFinite(value) ? Object.freeze({
|
|
315
|
+
kind: "valid",
|
|
316
|
+
token,
|
|
317
|
+
value
|
|
318
|
+
}) : invalidNumber;
|
|
319
|
+
}
|
|
320
|
+
var block_editor_fixed_inputs_schema_default = {
|
|
321
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
322
|
+
$id: "https://kubohiroya.github.io/turbowarp-asset-cache/schemas/block-editor-fixed-inputs.schema.json",
|
|
323
|
+
$defs: {
|
|
324
|
+
"setTextStyle": {
|
|
325
|
+
"type": "object",
|
|
326
|
+
"properties": {
|
|
327
|
+
"PROPERTY": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"enum": [
|
|
330
|
+
"animation",
|
|
331
|
+
"font",
|
|
332
|
+
"color",
|
|
333
|
+
"width",
|
|
334
|
+
"align"
|
|
335
|
+
]
|
|
336
|
+
},
|
|
337
|
+
"VALUE": { "type": "string" }
|
|
338
|
+
},
|
|
339
|
+
"additionalProperties": false
|
|
340
|
+
},
|
|
341
|
+
"animation": {
|
|
342
|
+
"type": "string",
|
|
343
|
+
"enum": [
|
|
344
|
+
"",
|
|
345
|
+
"none",
|
|
346
|
+
"type",
|
|
347
|
+
"rainbow",
|
|
348
|
+
"zoom",
|
|
349
|
+
"shake"
|
|
350
|
+
]
|
|
351
|
+
},
|
|
352
|
+
"font": { "type": "string" },
|
|
353
|
+
"color": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"pattern": "^(?:|#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})$"
|
|
356
|
+
},
|
|
357
|
+
"width": {
|
|
358
|
+
"type": "string",
|
|
359
|
+
"$comment": "Empty/trimmed empty resets; otherwise normalizeTextStyleValue requires Number(value) finite and positive. Preserve the existing STRING grammar, including hexadecimal and leading plus."
|
|
360
|
+
},
|
|
361
|
+
"align": {
|
|
362
|
+
"type": "string",
|
|
363
|
+
"enum": [
|
|
364
|
+
"",
|
|
365
|
+
"left",
|
|
366
|
+
"center",
|
|
367
|
+
"right"
|
|
368
|
+
]
|
|
369
|
+
},
|
|
370
|
+
"loadingCostumeAt": {
|
|
371
|
+
"type": "object",
|
|
372
|
+
"properties": { "INDEX": { "type": "number" } },
|
|
373
|
+
"additionalProperties": false
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/fixed-input-schema.ts
|
|
379
|
+
/** Canonical owner schema fragments; no network resources or runtime providers. */
|
|
380
|
+
function fixedInputBundle(fragment, schema) {
|
|
381
|
+
const source = {
|
|
382
|
+
repository: "turbowarp-asset-cache",
|
|
383
|
+
path: "schemas/block-editor-fixed-inputs.schema.json",
|
|
384
|
+
symbol: {
|
|
385
|
+
"setTextStyle-PROPERTY": "#/$defs/setTextStyle/properties/PROPERTY",
|
|
386
|
+
"setTextStyle-VALUE": "#/$defs/setTextStyle/properties/VALUE",
|
|
387
|
+
"loadingCostumeAt-INDEX": "#/$defs/loadingCostumeAt/properties/INDEX"
|
|
388
|
+
}[fragment] ?? `#/$defs/${fragment}`
|
|
389
|
+
};
|
|
390
|
+
return {
|
|
391
|
+
identity: {
|
|
392
|
+
ownerId: "turbowarp-asset-cache",
|
|
393
|
+
contractId: "fixed-inputs",
|
|
394
|
+
revision: "1",
|
|
395
|
+
variantId: fragment
|
|
396
|
+
},
|
|
397
|
+
dialect: "2020-12",
|
|
398
|
+
root: {
|
|
399
|
+
retrievalUri: block_editor_fixed_inputs_schema_default.$id,
|
|
400
|
+
document: schema,
|
|
401
|
+
artifact: {
|
|
402
|
+
role: "canonical-schema",
|
|
403
|
+
source
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
resources: [],
|
|
407
|
+
provenance: {
|
|
408
|
+
canonicalSources: [
|
|
409
|
+
source,
|
|
410
|
+
{
|
|
411
|
+
repository: "turbowarp-asset-cache",
|
|
412
|
+
path: "src/text-style.ts",
|
|
413
|
+
symbol: "normalizeTextStyleProperty / normalizeTextStyleValue"
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
repository: "turbowarp-asset-cache",
|
|
417
|
+
path: "src/extension.ts",
|
|
418
|
+
symbol: "getInfo / loadingCostumeAt"
|
|
419
|
+
}
|
|
420
|
+
],
|
|
421
|
+
generatedFiles: [],
|
|
422
|
+
referenceSchemas: [],
|
|
423
|
+
generationSources: []
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
var fixedSchemas = block_editor_fixed_inputs_schema_default.$defs;
|
|
428
|
+
//#endregion
|
|
429
|
+
//#region src/text-style.ts
|
|
430
|
+
var TEXT_RUNTIME_NAMESPACE = "text";
|
|
431
|
+
var TEXT_STYLE_RUNTIME_NAMESPACE = "textStyle";
|
|
432
|
+
var TEXT_STYLE_PROPERTIES = [
|
|
433
|
+
"animation",
|
|
434
|
+
"font",
|
|
435
|
+
"color",
|
|
436
|
+
"width",
|
|
437
|
+
"align"
|
|
438
|
+
];
|
|
439
|
+
var DEFAULT_STAGE_WIDTH = 480;
|
|
440
|
+
var DEFAULT_FONT = "Handwriting";
|
|
441
|
+
var DEFAULT_COLOR = "#ffffff";
|
|
442
|
+
var DEFAULT_ALIGNMENT = "center";
|
|
443
|
+
var DEFAULT_OUTLINE_COLOR = "#000000";
|
|
444
|
+
function textRuntimeVariableName(name) {
|
|
445
|
+
return `${TEXT_RUNTIME_NAMESPACE}:${name}`;
|
|
446
|
+
}
|
|
447
|
+
function textStyleRuntimeVariableName(name, property) {
|
|
448
|
+
return `${TEXT_STYLE_RUNTIME_NAMESPACE}:${name}:${property}`;
|
|
449
|
+
}
|
|
450
|
+
function normalizeTextStyleProperty(value) {
|
|
451
|
+
const property = String(value ?? "").trim().toLowerCase();
|
|
452
|
+
if (TEXT_STYLE_PROPERTIES.includes(property)) return property;
|
|
453
|
+
throw new Error(`Unknown text style property: ${property || "(empty)"}`);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Normalize a DSL-facing style value for runtime-variable storage.
|
|
457
|
+
* An empty value intentionally resets the property to its default.
|
|
458
|
+
*/
|
|
459
|
+
function normalizeTextStyleValue(property, value) {
|
|
460
|
+
const raw = String(value ?? "").trim();
|
|
461
|
+
if (!raw) return "";
|
|
462
|
+
switch (property) {
|
|
463
|
+
case "animation": {
|
|
464
|
+
const animation = raw.toLowerCase() === "typing" ? "type" : raw.toLowerCase();
|
|
465
|
+
if (animation === "none" || animation === "type" || animation === "rainbow" || animation === "zoom" || animation === "shake") return animation;
|
|
466
|
+
throw new Error(`Invalid text animation: ${raw}`);
|
|
467
|
+
}
|
|
468
|
+
case "font": return raw;
|
|
469
|
+
case "color": {
|
|
470
|
+
if (/^#[0-9a-f]{6}$/i.test(raw)) return raw.toLowerCase();
|
|
471
|
+
const shortColor = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(raw);
|
|
472
|
+
if (shortColor) return `#${shortColor[1]}${shortColor[1]}${shortColor[2]}${shortColor[2]}${shortColor[3]}${shortColor[3]}`.toLowerCase();
|
|
473
|
+
throw new Error(`Invalid text color: ${raw}`);
|
|
474
|
+
}
|
|
475
|
+
case "width": {
|
|
476
|
+
const width = Number(raw);
|
|
477
|
+
if (!Number.isFinite(width) || width <= 0) throw new Error(`Text width must be a positive number: ${raw}`);
|
|
478
|
+
return String(width);
|
|
479
|
+
}
|
|
480
|
+
case "align": {
|
|
481
|
+
const align = raw.toLowerCase();
|
|
482
|
+
if (align === "left" || align === "center" || align === "right") return align;
|
|
483
|
+
throw new Error(`Invalid text alignment: ${raw}`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function resolveTextStyle(name, stageWidth, getRuntimeVariable) {
|
|
488
|
+
const width = Number(stageWidth);
|
|
489
|
+
const defaults = {
|
|
490
|
+
animation: "none",
|
|
491
|
+
font: DEFAULT_FONT,
|
|
492
|
+
color: DEFAULT_COLOR,
|
|
493
|
+
width: Number.isFinite(width) && width > 0 ? width : DEFAULT_STAGE_WIDTH,
|
|
494
|
+
align: DEFAULT_ALIGNMENT
|
|
495
|
+
};
|
|
496
|
+
const read = (property) => normalizeTextStyleValue(property, getRuntimeVariable(textStyleRuntimeVariableName(name, property)));
|
|
497
|
+
const animation = read("animation");
|
|
498
|
+
const font = read("font");
|
|
499
|
+
const color = read("color");
|
|
500
|
+
const configuredWidth = read("width");
|
|
501
|
+
const align = read("align");
|
|
502
|
+
return {
|
|
503
|
+
animation: animation ? animation : defaults.animation,
|
|
504
|
+
font: font || defaults.font,
|
|
505
|
+
color: color || defaults.color,
|
|
506
|
+
width: configuredWidth ? Number(configuredWidth) : defaults.width,
|
|
507
|
+
align: align ? align : defaults.align
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/fixed-input-editors.ts
|
|
512
|
+
var extensionId = "kubohiroyaassetcache";
|
|
513
|
+
var choices = (values) => values.map((value) => ({ value }));
|
|
514
|
+
var context = () => ({
|
|
515
|
+
consumerId: "turbowarp-asset-cache",
|
|
516
|
+
nowMs: 0,
|
|
517
|
+
settings: null
|
|
518
|
+
});
|
|
519
|
+
var string = (value) => {
|
|
520
|
+
if (typeof value !== "string") throw new TypeError("Expected a string literal.");
|
|
521
|
+
return value;
|
|
522
|
+
};
|
|
523
|
+
var issue = () => [{ message: "Invalid asset style value." }];
|
|
524
|
+
/** New edits preserve the candidate token; existing aliases are display projections only. */
|
|
525
|
+
function styleBinding(property) {
|
|
526
|
+
const values = property === "animation" ? [
|
|
527
|
+
"",
|
|
528
|
+
"none",
|
|
529
|
+
"type",
|
|
530
|
+
"rainbow",
|
|
531
|
+
"zoom",
|
|
532
|
+
"shake"
|
|
533
|
+
] : property === "align" ? [
|
|
534
|
+
"",
|
|
535
|
+
"left",
|
|
536
|
+
"center",
|
|
537
|
+
"right"
|
|
538
|
+
] : void 0;
|
|
539
|
+
return {
|
|
540
|
+
argument: "VALUE",
|
|
541
|
+
schemaBundle: fixedInputBundle(property, fixedSchemas[property]),
|
|
542
|
+
control: {
|
|
543
|
+
kind: values ? "enum" : property === "color" ? "color" : property === "width" ? "number" : "text",
|
|
544
|
+
reset: "",
|
|
545
|
+
...values ? { choices: choices(values) } : {}
|
|
546
|
+
},
|
|
547
|
+
read(value) {
|
|
548
|
+
return normalizeTextStyleValue(property, string(value));
|
|
549
|
+
},
|
|
550
|
+
encode(value) {
|
|
551
|
+
const raw = string(value);
|
|
552
|
+
if (property !== "width" || raw === "") return raw;
|
|
553
|
+
normalizeTextStyleValue(property, raw);
|
|
554
|
+
return raw;
|
|
555
|
+
},
|
|
556
|
+
validateCandidate(value) {
|
|
557
|
+
try {
|
|
558
|
+
normalizeTextStyleValue(property, string(value));
|
|
559
|
+
return [];
|
|
560
|
+
} catch {
|
|
561
|
+
return issue();
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
var fixedInputEditors = [{
|
|
567
|
+
apiVersion: 1,
|
|
568
|
+
extensionId,
|
|
569
|
+
editorId: "text-style-fixed",
|
|
570
|
+
opcodes: [`${extensionId}_setTextStyle`],
|
|
571
|
+
contractId: "CP-asset-cache",
|
|
572
|
+
contractRevision: "1",
|
|
573
|
+
validationContext: context,
|
|
574
|
+
bindings: [{
|
|
575
|
+
argument: "PROPERTY",
|
|
576
|
+
schemaBundle: fixedInputBundle("setTextStyle-PROPERTY", fixedSchemas.setTextStyle.properties.PROPERTY),
|
|
577
|
+
control: {
|
|
578
|
+
kind: "enum",
|
|
579
|
+
choices: choices(TEXT_STYLE_PROPERTIES)
|
|
580
|
+
},
|
|
581
|
+
read(value) {
|
|
582
|
+
const raw = string(value);
|
|
583
|
+
try {
|
|
584
|
+
return normalizeTextStyleProperty(raw);
|
|
585
|
+
} catch {
|
|
586
|
+
return raw;
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
encode: (value) => string(value),
|
|
590
|
+
validateCandidate(value) {
|
|
591
|
+
try {
|
|
592
|
+
normalizeTextStyleProperty(value);
|
|
593
|
+
return [];
|
|
594
|
+
} catch {
|
|
595
|
+
return issue();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}, {
|
|
599
|
+
argument: "VALUE",
|
|
600
|
+
schemaBundle: fixedInputBundle("setTextStyle-VALUE", fixedSchemas.setTextStyle.properties.VALUE),
|
|
601
|
+
read: (value) => string(value),
|
|
602
|
+
encode: (value) => string(value),
|
|
603
|
+
validateCandidate: () => []
|
|
604
|
+
}],
|
|
605
|
+
dependencies: [{
|
|
606
|
+
selector: "PROPERTY",
|
|
607
|
+
dependents: ["VALUE"]
|
|
608
|
+
}],
|
|
609
|
+
branchPolicies: [{
|
|
610
|
+
selector: "PROPERTY",
|
|
611
|
+
normalize: {
|
|
612
|
+
trim: true,
|
|
613
|
+
lowercase: true
|
|
614
|
+
},
|
|
615
|
+
cases: TEXT_STYLE_PROPERTIES.map((property) => ({
|
|
616
|
+
values: [property],
|
|
617
|
+
activeDependents: ["VALUE"],
|
|
618
|
+
bindings: [styleBinding(property)]
|
|
619
|
+
}))
|
|
620
|
+
}]
|
|
621
|
+
}, {
|
|
622
|
+
apiVersion: 1,
|
|
623
|
+
extensionId,
|
|
624
|
+
editorId: "loading-costume-index-fixed",
|
|
625
|
+
opcodes: [`${extensionId}_loadingCostumeAt`],
|
|
626
|
+
contractId: "turbowarp-asset-cache/loadingCostumeAt.INDEX",
|
|
627
|
+
contractRevision: "1",
|
|
628
|
+
validationContext: context,
|
|
629
|
+
bindings: [{
|
|
630
|
+
argument: "INDEX",
|
|
631
|
+
schemaBundle: fixedInputBundle("loadingCostumeAt-INDEX", fixedSchemas.loadingCostumeAt.properties.INDEX),
|
|
632
|
+
control: { kind: "number" },
|
|
633
|
+
read(value) {
|
|
634
|
+
if (typeof value !== "number" && typeof value !== "string" || typeof value === "string" && value.trim() === "") throw new TypeError("Non-numeric index.");
|
|
635
|
+
const number = Number(value);
|
|
636
|
+
if (!Number.isFinite(number)) throw new TypeError("Nonfinite index.");
|
|
637
|
+
return number;
|
|
638
|
+
},
|
|
639
|
+
encode(value) {
|
|
640
|
+
const parsed = parseFixedNumberInput(value);
|
|
641
|
+
if (parsed.kind !== "valid") throw new TypeError("Invalid index.");
|
|
642
|
+
return parsed.token;
|
|
643
|
+
},
|
|
644
|
+
validateCandidate(value) {
|
|
645
|
+
return Number.isFinite(Number(value)) ? [] : [{ message: "Invalid index." }];
|
|
646
|
+
}
|
|
647
|
+
}]
|
|
648
|
+
}];
|
|
649
|
+
/** Per-instance, idempotent registration. Legacy hosts never acquire the fixed capability. */
|
|
650
|
+
function fixedInputRegistration(scratch) {
|
|
651
|
+
const host = scratch;
|
|
652
|
+
let active;
|
|
653
|
+
let removers = [];
|
|
654
|
+
let disposed = false;
|
|
655
|
+
const dispose = () => {
|
|
656
|
+
host.vm?.runtime?.off?.("RUNTIME_DISPOSED", shutdown);
|
|
657
|
+
for (const remove of removers.splice(0).reverse()) remove();
|
|
658
|
+
active = void 0;
|
|
659
|
+
};
|
|
660
|
+
const shutdown = () => {
|
|
661
|
+
disposed = true;
|
|
662
|
+
dispose();
|
|
663
|
+
};
|
|
664
|
+
return {
|
|
665
|
+
ensure(opcodes) {
|
|
666
|
+
const api = host.gui?.blockEditors;
|
|
667
|
+
if (disposed || api === active) return;
|
|
668
|
+
dispose();
|
|
669
|
+
if (api?.apiVersion !== 1 || typeof api.registerFixedInputEditor !== "function") return;
|
|
670
|
+
try {
|
|
671
|
+
for (const definition of fixedInputEditors) if (definition.opcodes.every((opcode) => opcodes.includes(opcode))) {
|
|
672
|
+
const remove = api.registerFixedInputEditor.call(api, definition);
|
|
673
|
+
if (typeof remove !== "function") throw new TypeError("Invalid fixed registration cleanup.");
|
|
674
|
+
removers.push(remove);
|
|
675
|
+
}
|
|
676
|
+
active = api;
|
|
677
|
+
host.vm?.runtime?.on?.("RUNTIME_DISPOSED", shutdown);
|
|
678
|
+
} catch (error) {
|
|
679
|
+
dispose();
|
|
680
|
+
throw error;
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
dispose: shutdown
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region node_modules/.pnpm/@kubohiroya+turbowarp-named-data@0.3.1/node_modules/@kubohiroya/turbowarp-named-data/dist/composition.js
|
|
291
688
|
var NAMED_DATA_REGISTRY_SYMBOL_KEY = "@kubohiroya/turbowarp-named-data/registry";
|
|
292
689
|
var NAMED_DATA_REGISTRY_SYMBOL = Symbol.for(NAMED_DATA_REGISTRY_SYMBOL_KEY);
|
|
293
690
|
var NAMED_DATA_NAMESPACE_PATTERN = /^[a-z][a-z0-9.-]{0,63}$/u;
|
|
@@ -308,6 +705,8 @@
|
|
|
308
705
|
"markdown",
|
|
309
706
|
"raw"
|
|
310
707
|
];
|
|
708
|
+
var NAMED_DATA_SCHEMA_ID_PATTERN = /^[a-z][a-z0-9.-]{0,127}$/u;
|
|
709
|
+
var NAMED_DATA_SCHEMA_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u;
|
|
311
710
|
var NAMED_DATA_ERROR_CODES = [
|
|
312
711
|
"NAMED_DATA_INVALID_REF",
|
|
313
712
|
"NAMED_DATA_INVALID_REGISTRY",
|
|
@@ -316,6 +715,9 @@
|
|
|
316
715
|
"NAMED_DATA_NOT_FOUND",
|
|
317
716
|
"NAMED_DATA_KIND_MISMATCH",
|
|
318
717
|
"NAMED_DATA_SCOPE_MISMATCH",
|
|
718
|
+
"NAMED_DATA_SCHEMA_NOT_FOUND",
|
|
719
|
+
"NAMED_DATA_SCHEMA_VERSION_MISMATCH",
|
|
720
|
+
"NAMED_DATA_SCHEMA_UNRESOLVED",
|
|
319
721
|
"NAMED_DATA_REPRESENTATION_UNSUPPORTED",
|
|
320
722
|
"NAMED_DATA_INVALID_METADATA",
|
|
321
723
|
"NAMED_DATA_BODY_TOO_LARGE",
|
|
@@ -536,9 +938,21 @@
|
|
|
536
938
|
if (!reference || typeof reference !== "object") throw invalidReference$1();
|
|
537
939
|
requireNamespace(reference.namespace);
|
|
538
940
|
if (typeof reference.name !== "string" || reference.name.length === 0 || reference.name.length > 256 || containsControlCharacter(reference.name) || !NAMED_DATA_KINDS.includes(reference.kind) || !NAMED_DATA_SCOPES.includes(reference.scope) || !NAMED_DATA_REPRESENTATIONS.includes(representation)) throw invalidReference$1();
|
|
941
|
+
if (reference.schemaRef !== void 0) validateSchemaRef(reference.kind, reference.schemaRef);
|
|
539
942
|
}
|
|
540
943
|
function validateMetadata(metadata, reference, representation) {
|
|
541
944
|
if (metadata.representation !== representation || !isNativeRepresentation(metadata.reference.kind, metadata.nativeRepresentation) || metadata.reference.namespace !== reference.namespace || metadata.reference.name !== reference.name || metadata.reference.kind !== reference.kind || metadata.reference.scope !== reference.scope || typeof metadata.mediaType !== "string" || metadata.mediaType.length === 0 || typeof metadata.revision !== "string" || metadata.revision.length === 0 || typeof metadata.replayable !== "boolean" || metadata.byteLength !== void 0 && (!Number.isSafeInteger(metadata.byteLength) || metadata.byteLength < 0) || metadata.digest !== void 0 && !/^sha256-[A-Za-z0-9_-]+$/u.test(metadata.digest)) throw new NamedDataError("NAMED_DATA_INVALID_METADATA", "Provider returned invalid metadata.");
|
|
945
|
+
const expectedSchema = reference.schemaRef;
|
|
946
|
+
const actualSchema = metadata.schemaRef;
|
|
947
|
+
if (actualSchema !== void 0) validateSchemaRef(metadata.reference.kind, actualSchema, "NAMED_DATA_INVALID_METADATA");
|
|
948
|
+
if (metadata.reference.schemaRef !== void 0) validateSchemaRef(metadata.reference.kind, metadata.reference.schemaRef, "NAMED_DATA_INVALID_METADATA");
|
|
949
|
+
if (!sameSchemaRef(expectedSchema, actualSchema) || !sameSchemaRef(expectedSchema, metadata.reference.schemaRef)) throw new NamedDataError("NAMED_DATA_SCHEMA_VERSION_MISMATCH", "Provider schemaRef does not match the requested reference.");
|
|
950
|
+
}
|
|
951
|
+
function validateSchemaRef(kind, schemaRef, errorCode = "NAMED_DATA_INVALID_REF") {
|
|
952
|
+
if (kind !== "structured" || typeof schemaRef !== "object" || schemaRef === null || !NAMED_DATA_SCHEMA_ID_PATTERN.test(String(schemaRef.id ?? "")) || !NAMED_DATA_SCHEMA_VERSION_PATTERN.test(String(schemaRef.version ?? "")) || Object.keys(schemaRef).some((key) => key !== "id" && key !== "version")) throw new NamedDataError(errorCode, "Invalid schemaRef; schema references require a structured value, stable id, and full SemVer version.");
|
|
953
|
+
}
|
|
954
|
+
function sameSchemaRef(left, right) {
|
|
955
|
+
return left === void 0 ? right === void 0 : right !== void 0 && left.id === right.id && left.version === right.version;
|
|
542
956
|
}
|
|
543
957
|
function isNativeRepresentation(kind, representation) {
|
|
544
958
|
if (kind === "structured") return representation === "json" || representation === "yaml";
|
|
@@ -575,7 +989,10 @@
|
|
|
575
989
|
const value = globalThis.__TW_NAMED_DATA_FEATURE_FLAGS__?.[name];
|
|
576
990
|
return value === true || value === "true";
|
|
577
991
|
}
|
|
578
|
-
Object.freeze({
|
|
992
|
+
Object.freeze({
|
|
993
|
+
NAMED_DATA_REGISTRY_MVP: configuredFlag$1("NAMED_DATA_REGISTRY_MVP"),
|
|
994
|
+
NAMED_DATA_SCHEMA_REF: configuredFlag$1("NAMED_DATA_SCHEMA_REF")
|
|
995
|
+
});
|
|
579
996
|
//#endregion
|
|
580
997
|
//#region \0@oxc-project+runtime@0.148.0/helpers/esm/typeof.js
|
|
581
998
|
function _typeof(o) {
|
|
@@ -994,88 +1411,6 @@
|
|
|
994
1411
|
if (signal?.aborted) throw namedBodyAbortError();
|
|
995
1412
|
}
|
|
996
1413
|
//#endregion
|
|
997
|
-
//#region src/text-style.ts
|
|
998
|
-
var TEXT_RUNTIME_NAMESPACE = "text";
|
|
999
|
-
var TEXT_STYLE_RUNTIME_NAMESPACE = "textStyle";
|
|
1000
|
-
var TEXT_STYLE_PROPERTIES = [
|
|
1001
|
-
"animation",
|
|
1002
|
-
"font",
|
|
1003
|
-
"color",
|
|
1004
|
-
"width",
|
|
1005
|
-
"align"
|
|
1006
|
-
];
|
|
1007
|
-
var DEFAULT_STAGE_WIDTH = 480;
|
|
1008
|
-
var DEFAULT_FONT = "Handwriting";
|
|
1009
|
-
var DEFAULT_COLOR = "#ffffff";
|
|
1010
|
-
var DEFAULT_ALIGNMENT = "center";
|
|
1011
|
-
var DEFAULT_OUTLINE_COLOR = "#000000";
|
|
1012
|
-
function textRuntimeVariableName(name) {
|
|
1013
|
-
return `${TEXT_RUNTIME_NAMESPACE}:${name}`;
|
|
1014
|
-
}
|
|
1015
|
-
function textStyleRuntimeVariableName(name, property) {
|
|
1016
|
-
return `${TEXT_STYLE_RUNTIME_NAMESPACE}:${name}:${property}`;
|
|
1017
|
-
}
|
|
1018
|
-
function normalizeTextStyleProperty(value) {
|
|
1019
|
-
const property = String(value ?? "").trim().toLowerCase();
|
|
1020
|
-
if (TEXT_STYLE_PROPERTIES.includes(property)) return property;
|
|
1021
|
-
throw new Error(`Unknown text style property: ${property || "(empty)"}`);
|
|
1022
|
-
}
|
|
1023
|
-
/**
|
|
1024
|
-
* Normalize a DSL-facing style value for runtime-variable storage.
|
|
1025
|
-
* An empty value intentionally resets the property to its default.
|
|
1026
|
-
*/
|
|
1027
|
-
function normalizeTextStyleValue(property, value) {
|
|
1028
|
-
const raw = String(value ?? "").trim();
|
|
1029
|
-
if (!raw) return "";
|
|
1030
|
-
switch (property) {
|
|
1031
|
-
case "animation": {
|
|
1032
|
-
const animation = raw.toLowerCase() === "typing" ? "type" : raw.toLowerCase();
|
|
1033
|
-
if (animation === "none" || animation === "type" || animation === "rainbow" || animation === "zoom" || animation === "shake") return animation;
|
|
1034
|
-
throw new Error(`Invalid text animation: ${raw}`);
|
|
1035
|
-
}
|
|
1036
|
-
case "font": return raw;
|
|
1037
|
-
case "color": {
|
|
1038
|
-
if (/^#[0-9a-f]{6}$/i.test(raw)) return raw.toLowerCase();
|
|
1039
|
-
const shortColor = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(raw);
|
|
1040
|
-
if (shortColor) return `#${shortColor[1]}${shortColor[1]}${shortColor[2]}${shortColor[2]}${shortColor[3]}${shortColor[3]}`.toLowerCase();
|
|
1041
|
-
throw new Error(`Invalid text color: ${raw}`);
|
|
1042
|
-
}
|
|
1043
|
-
case "width": {
|
|
1044
|
-
const width = Number(raw);
|
|
1045
|
-
if (!Number.isFinite(width) || width <= 0) throw new Error(`Text width must be a positive number: ${raw}`);
|
|
1046
|
-
return String(width);
|
|
1047
|
-
}
|
|
1048
|
-
case "align": {
|
|
1049
|
-
const align = raw.toLowerCase();
|
|
1050
|
-
if (align === "left" || align === "center" || align === "right") return align;
|
|
1051
|
-
throw new Error(`Invalid text alignment: ${raw}`);
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
function resolveTextStyle(name, stageWidth, getRuntimeVariable) {
|
|
1056
|
-
const width = Number(stageWidth);
|
|
1057
|
-
const defaults = {
|
|
1058
|
-
animation: "none",
|
|
1059
|
-
font: DEFAULT_FONT,
|
|
1060
|
-
color: DEFAULT_COLOR,
|
|
1061
|
-
width: Number.isFinite(width) && width > 0 ? width : DEFAULT_STAGE_WIDTH,
|
|
1062
|
-
align: DEFAULT_ALIGNMENT
|
|
1063
|
-
};
|
|
1064
|
-
const read = (property) => normalizeTextStyleValue(property, getRuntimeVariable(textStyleRuntimeVariableName(name, property)));
|
|
1065
|
-
const animation = read("animation");
|
|
1066
|
-
const font = read("font");
|
|
1067
|
-
const color = read("color");
|
|
1068
|
-
const configuredWidth = read("width");
|
|
1069
|
-
const align = read("align");
|
|
1070
|
-
return {
|
|
1071
|
-
animation: animation ? animation : defaults.animation,
|
|
1072
|
-
font: font || defaults.font,
|
|
1073
|
-
color: color || defaults.color,
|
|
1074
|
-
width: configuredWidth ? Number(configuredWidth) : defaults.width,
|
|
1075
|
-
align: align ? align : defaults.align
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
//#endregion
|
|
1079
1414
|
//#region src/extension.ts
|
|
1080
1415
|
var EXTENSION_ID = "kubohiroyaassetcache";
|
|
1081
1416
|
var EXTENSION_VERSION = "0.14.0";
|
|
@@ -1581,6 +1916,7 @@
|
|
|
1581
1916
|
this.unbindNamedDataRegistryLifecycle?.();
|
|
1582
1917
|
this.unbindNamedDataRegistryLifecycle = void 0;
|
|
1583
1918
|
});
|
|
1919
|
+
_defineProperty(this, "fixedEditors", fixedInputRegistration(Scratch));
|
|
1584
1920
|
this.featureFlags = Object.freeze({ ...featureFlags });
|
|
1585
1921
|
if (this.featureFlags.NAMED_ASSET_BODY_PROVIDER) {
|
|
1586
1922
|
this.namedBodyProviderValue = this.createNamedBodyProvider();
|
|
@@ -1646,6 +1982,8 @@
|
|
|
1646
1982
|
return loadingCostumes[((Number.isFinite(numericIndex) ? Math.max(1, Math.trunc(numericIndex)) : 1) - 1) % loadingCostumes.length];
|
|
1647
1983
|
}
|
|
1648
1984
|
getInfo() {
|
|
1985
|
+
const blocks = blockDefinitions.map((block) => this.toScratchBlock(block));
|
|
1986
|
+
this.fixedEditors.ensure(blocks.map((block) => `${EXTENSION_ID}_${block.opcode}`));
|
|
1649
1987
|
return {
|
|
1650
1988
|
id: EXTENSION_ID,
|
|
1651
1989
|
name: Scratch.translate(block_definitions_default.extensionName),
|
|
@@ -1654,9 +1992,13 @@
|
|
|
1654
1992
|
color1: "#5b7cfa",
|
|
1655
1993
|
color2: "#425ed8",
|
|
1656
1994
|
color3: "#2f46aa",
|
|
1657
|
-
blocks
|
|
1995
|
+
blocks
|
|
1658
1996
|
};
|
|
1659
1997
|
}
|
|
1998
|
+
/** Release only this optional editor registration; runtime data remains unchanged. */
|
|
1999
|
+
dispose() {
|
|
2000
|
+
this.fixedEditors.dispose();
|
|
2001
|
+
}
|
|
1660
2002
|
/**
|
|
1661
2003
|
* Exposes the stock extension registry through a host-neutral DOM image
|
|
1662
2004
|
* resource contract for other unsandboxed extensions.
|
package/dist/composition.js
CHANGED
|
@@ -278,7 +278,404 @@ var block_definitions_default = {
|
|
|
278
278
|
]
|
|
279
279
|
};
|
|
280
280
|
//#endregion
|
|
281
|
-
//#region node_modules/.pnpm/@kubohiroya+turbowarp-
|
|
281
|
+
//#region node_modules/.pnpm/@kubohiroya+turbowarp-extension-data-editor@0.2.1_react@18.3.1/node_modules/@kubohiroya/turbowarp-extension-data-editor/dist/fixed-input-schema.js
|
|
282
|
+
var numberToken = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
|
|
283
|
+
var invalidNumber = Object.freeze({
|
|
284
|
+
kind: "invalid",
|
|
285
|
+
code: "fixed-number-input-invalid"
|
|
286
|
+
});
|
|
287
|
+
/**
|
|
288
|
+
* Parse a NEW numeric draft according to NP-finite-new-input-v1.
|
|
289
|
+
* Never apply this to opening/no-op raw values or use it as an owner validator.
|
|
290
|
+
* Keep the validated token so negative zero, precision and exponent spelling survive.
|
|
291
|
+
*/
|
|
292
|
+
function parseFixedNumberInput(input) {
|
|
293
|
+
if (typeof input === "number") {
|
|
294
|
+
if (!Number.isFinite(input)) return invalidNumber;
|
|
295
|
+
return Object.freeze({
|
|
296
|
+
kind: "valid",
|
|
297
|
+
token: Object.is(input, -0) ? "-0" : String(input),
|
|
298
|
+
value: input
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
if (typeof input !== "string") return invalidNumber;
|
|
302
|
+
const token = input.trim();
|
|
303
|
+
if (!numberToken.test(token)) return invalidNumber;
|
|
304
|
+
const value = Number(token);
|
|
305
|
+
return Number.isFinite(value) ? Object.freeze({
|
|
306
|
+
kind: "valid",
|
|
307
|
+
token,
|
|
308
|
+
value
|
|
309
|
+
}) : invalidNumber;
|
|
310
|
+
}
|
|
311
|
+
var block_editor_fixed_inputs_schema_default = {
|
|
312
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
313
|
+
$id: "https://kubohiroya.github.io/turbowarp-asset-cache/schemas/block-editor-fixed-inputs.schema.json",
|
|
314
|
+
$defs: {
|
|
315
|
+
"setTextStyle": {
|
|
316
|
+
"type": "object",
|
|
317
|
+
"properties": {
|
|
318
|
+
"PROPERTY": {
|
|
319
|
+
"type": "string",
|
|
320
|
+
"enum": [
|
|
321
|
+
"animation",
|
|
322
|
+
"font",
|
|
323
|
+
"color",
|
|
324
|
+
"width",
|
|
325
|
+
"align"
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
"VALUE": { "type": "string" }
|
|
329
|
+
},
|
|
330
|
+
"additionalProperties": false
|
|
331
|
+
},
|
|
332
|
+
"animation": {
|
|
333
|
+
"type": "string",
|
|
334
|
+
"enum": [
|
|
335
|
+
"",
|
|
336
|
+
"none",
|
|
337
|
+
"type",
|
|
338
|
+
"rainbow",
|
|
339
|
+
"zoom",
|
|
340
|
+
"shake"
|
|
341
|
+
]
|
|
342
|
+
},
|
|
343
|
+
"font": { "type": "string" },
|
|
344
|
+
"color": {
|
|
345
|
+
"type": "string",
|
|
346
|
+
"pattern": "^(?:|#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})$"
|
|
347
|
+
},
|
|
348
|
+
"width": {
|
|
349
|
+
"type": "string",
|
|
350
|
+
"$comment": "Empty/trimmed empty resets; otherwise normalizeTextStyleValue requires Number(value) finite and positive. Preserve the existing STRING grammar, including hexadecimal and leading plus."
|
|
351
|
+
},
|
|
352
|
+
"align": {
|
|
353
|
+
"type": "string",
|
|
354
|
+
"enum": [
|
|
355
|
+
"",
|
|
356
|
+
"left",
|
|
357
|
+
"center",
|
|
358
|
+
"right"
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
"loadingCostumeAt": {
|
|
362
|
+
"type": "object",
|
|
363
|
+
"properties": { "INDEX": { "type": "number" } },
|
|
364
|
+
"additionalProperties": false
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/fixed-input-schema.ts
|
|
370
|
+
/** Canonical owner schema fragments; no network resources or runtime providers. */
|
|
371
|
+
function fixedInputBundle(fragment, schema) {
|
|
372
|
+
const source = {
|
|
373
|
+
repository: "turbowarp-asset-cache",
|
|
374
|
+
path: "schemas/block-editor-fixed-inputs.schema.json",
|
|
375
|
+
symbol: {
|
|
376
|
+
"setTextStyle-PROPERTY": "#/$defs/setTextStyle/properties/PROPERTY",
|
|
377
|
+
"setTextStyle-VALUE": "#/$defs/setTextStyle/properties/VALUE",
|
|
378
|
+
"loadingCostumeAt-INDEX": "#/$defs/loadingCostumeAt/properties/INDEX"
|
|
379
|
+
}[fragment] ?? `#/$defs/${fragment}`
|
|
380
|
+
};
|
|
381
|
+
return {
|
|
382
|
+
identity: {
|
|
383
|
+
ownerId: "turbowarp-asset-cache",
|
|
384
|
+
contractId: "fixed-inputs",
|
|
385
|
+
revision: "1",
|
|
386
|
+
variantId: fragment
|
|
387
|
+
},
|
|
388
|
+
dialect: "2020-12",
|
|
389
|
+
root: {
|
|
390
|
+
retrievalUri: block_editor_fixed_inputs_schema_default.$id,
|
|
391
|
+
document: schema,
|
|
392
|
+
artifact: {
|
|
393
|
+
role: "canonical-schema",
|
|
394
|
+
source
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
resources: [],
|
|
398
|
+
provenance: {
|
|
399
|
+
canonicalSources: [
|
|
400
|
+
source,
|
|
401
|
+
{
|
|
402
|
+
repository: "turbowarp-asset-cache",
|
|
403
|
+
path: "src/text-style.ts",
|
|
404
|
+
symbol: "normalizeTextStyleProperty / normalizeTextStyleValue"
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
repository: "turbowarp-asset-cache",
|
|
408
|
+
path: "src/extension.ts",
|
|
409
|
+
symbol: "getInfo / loadingCostumeAt"
|
|
410
|
+
}
|
|
411
|
+
],
|
|
412
|
+
generatedFiles: [],
|
|
413
|
+
referenceSchemas: [],
|
|
414
|
+
generationSources: []
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
var fixedSchemas = block_editor_fixed_inputs_schema_default.$defs;
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region src/text-style.ts
|
|
421
|
+
var TEXT_RUNTIME_NAMESPACE = "text";
|
|
422
|
+
var TEXT_STYLE_RUNTIME_NAMESPACE = "textStyle";
|
|
423
|
+
var TEXT_STYLE_PROPERTIES = [
|
|
424
|
+
"animation",
|
|
425
|
+
"font",
|
|
426
|
+
"color",
|
|
427
|
+
"width",
|
|
428
|
+
"align"
|
|
429
|
+
];
|
|
430
|
+
var DEFAULT_STAGE_WIDTH = 480;
|
|
431
|
+
var DEFAULT_FONT = "Handwriting";
|
|
432
|
+
var DEFAULT_COLOR = "#ffffff";
|
|
433
|
+
var DEFAULT_ALIGNMENT = "center";
|
|
434
|
+
var DEFAULT_OUTLINE_COLOR = "#000000";
|
|
435
|
+
function textRuntimeVariableName(name) {
|
|
436
|
+
return `${TEXT_RUNTIME_NAMESPACE}:${name}`;
|
|
437
|
+
}
|
|
438
|
+
function textStyleRuntimeVariableName(name, property) {
|
|
439
|
+
return `${TEXT_STYLE_RUNTIME_NAMESPACE}:${name}:${property}`;
|
|
440
|
+
}
|
|
441
|
+
function normalizeTextStyleProperty(value) {
|
|
442
|
+
const property = String(value ?? "").trim().toLowerCase();
|
|
443
|
+
if (TEXT_STYLE_PROPERTIES.includes(property)) return property;
|
|
444
|
+
throw new Error(`Unknown text style property: ${property || "(empty)"}`);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Normalize a DSL-facing style value for runtime-variable storage.
|
|
448
|
+
* An empty value intentionally resets the property to its default.
|
|
449
|
+
*/
|
|
450
|
+
function normalizeTextStyleValue(property, value) {
|
|
451
|
+
const raw = String(value ?? "").trim();
|
|
452
|
+
if (!raw) return "";
|
|
453
|
+
switch (property) {
|
|
454
|
+
case "animation": {
|
|
455
|
+
const animation = raw.toLowerCase() === "typing" ? "type" : raw.toLowerCase();
|
|
456
|
+
if (animation === "none" || animation === "type" || animation === "rainbow" || animation === "zoom" || animation === "shake") return animation;
|
|
457
|
+
throw new Error(`Invalid text animation: ${raw}`);
|
|
458
|
+
}
|
|
459
|
+
case "font": return raw;
|
|
460
|
+
case "color": {
|
|
461
|
+
if (/^#[0-9a-f]{6}$/i.test(raw)) return raw.toLowerCase();
|
|
462
|
+
const shortColor = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(raw);
|
|
463
|
+
if (shortColor) return `#${shortColor[1]}${shortColor[1]}${shortColor[2]}${shortColor[2]}${shortColor[3]}${shortColor[3]}`.toLowerCase();
|
|
464
|
+
throw new Error(`Invalid text color: ${raw}`);
|
|
465
|
+
}
|
|
466
|
+
case "width": {
|
|
467
|
+
const width = Number(raw);
|
|
468
|
+
if (!Number.isFinite(width) || width <= 0) throw new Error(`Text width must be a positive number: ${raw}`);
|
|
469
|
+
return String(width);
|
|
470
|
+
}
|
|
471
|
+
case "align": {
|
|
472
|
+
const align = raw.toLowerCase();
|
|
473
|
+
if (align === "left" || align === "center" || align === "right") return align;
|
|
474
|
+
throw new Error(`Invalid text alignment: ${raw}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function resolveTextStyle(name, stageWidth, getRuntimeVariable) {
|
|
479
|
+
const width = Number(stageWidth);
|
|
480
|
+
const defaults = {
|
|
481
|
+
animation: "none",
|
|
482
|
+
font: DEFAULT_FONT,
|
|
483
|
+
color: DEFAULT_COLOR,
|
|
484
|
+
width: Number.isFinite(width) && width > 0 ? width : DEFAULT_STAGE_WIDTH,
|
|
485
|
+
align: DEFAULT_ALIGNMENT
|
|
486
|
+
};
|
|
487
|
+
const read = (property) => normalizeTextStyleValue(property, getRuntimeVariable(textStyleRuntimeVariableName(name, property)));
|
|
488
|
+
const animation = read("animation");
|
|
489
|
+
const font = read("font");
|
|
490
|
+
const color = read("color");
|
|
491
|
+
const configuredWidth = read("width");
|
|
492
|
+
const align = read("align");
|
|
493
|
+
return {
|
|
494
|
+
animation: animation ? animation : defaults.animation,
|
|
495
|
+
font: font || defaults.font,
|
|
496
|
+
color: color || defaults.color,
|
|
497
|
+
width: configuredWidth ? Number(configuredWidth) : defaults.width,
|
|
498
|
+
align: align ? align : defaults.align
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
//#endregion
|
|
502
|
+
//#region src/fixed-input-editors.ts
|
|
503
|
+
var extensionId = "kubohiroyaassetcache";
|
|
504
|
+
var choices = (values) => values.map((value) => ({ value }));
|
|
505
|
+
var context = () => ({
|
|
506
|
+
consumerId: "turbowarp-asset-cache",
|
|
507
|
+
nowMs: 0,
|
|
508
|
+
settings: null
|
|
509
|
+
});
|
|
510
|
+
var string = (value) => {
|
|
511
|
+
if (typeof value !== "string") throw new TypeError("Expected a string literal.");
|
|
512
|
+
return value;
|
|
513
|
+
};
|
|
514
|
+
var issue = () => [{ message: "Invalid asset style value." }];
|
|
515
|
+
/** New edits preserve the candidate token; existing aliases are display projections only. */
|
|
516
|
+
function styleBinding(property) {
|
|
517
|
+
const values = property === "animation" ? [
|
|
518
|
+
"",
|
|
519
|
+
"none",
|
|
520
|
+
"type",
|
|
521
|
+
"rainbow",
|
|
522
|
+
"zoom",
|
|
523
|
+
"shake"
|
|
524
|
+
] : property === "align" ? [
|
|
525
|
+
"",
|
|
526
|
+
"left",
|
|
527
|
+
"center",
|
|
528
|
+
"right"
|
|
529
|
+
] : void 0;
|
|
530
|
+
return {
|
|
531
|
+
argument: "VALUE",
|
|
532
|
+
schemaBundle: fixedInputBundle(property, fixedSchemas[property]),
|
|
533
|
+
control: {
|
|
534
|
+
kind: values ? "enum" : property === "color" ? "color" : property === "width" ? "number" : "text",
|
|
535
|
+
reset: "",
|
|
536
|
+
...values ? { choices: choices(values) } : {}
|
|
537
|
+
},
|
|
538
|
+
read(value) {
|
|
539
|
+
return normalizeTextStyleValue(property, string(value));
|
|
540
|
+
},
|
|
541
|
+
encode(value) {
|
|
542
|
+
const raw = string(value);
|
|
543
|
+
if (property !== "width" || raw === "") return raw;
|
|
544
|
+
normalizeTextStyleValue(property, raw);
|
|
545
|
+
return raw;
|
|
546
|
+
},
|
|
547
|
+
validateCandidate(value) {
|
|
548
|
+
try {
|
|
549
|
+
normalizeTextStyleValue(property, string(value));
|
|
550
|
+
return [];
|
|
551
|
+
} catch {
|
|
552
|
+
return issue();
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
var fixedInputEditors = [{
|
|
558
|
+
apiVersion: 1,
|
|
559
|
+
extensionId,
|
|
560
|
+
editorId: "text-style-fixed",
|
|
561
|
+
opcodes: [`${extensionId}_setTextStyle`],
|
|
562
|
+
contractId: "CP-asset-cache",
|
|
563
|
+
contractRevision: "1",
|
|
564
|
+
validationContext: context,
|
|
565
|
+
bindings: [{
|
|
566
|
+
argument: "PROPERTY",
|
|
567
|
+
schemaBundle: fixedInputBundle("setTextStyle-PROPERTY", fixedSchemas.setTextStyle.properties.PROPERTY),
|
|
568
|
+
control: {
|
|
569
|
+
kind: "enum",
|
|
570
|
+
choices: choices(TEXT_STYLE_PROPERTIES)
|
|
571
|
+
},
|
|
572
|
+
read(value) {
|
|
573
|
+
const raw = string(value);
|
|
574
|
+
try {
|
|
575
|
+
return normalizeTextStyleProperty(raw);
|
|
576
|
+
} catch {
|
|
577
|
+
return raw;
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
encode: (value) => string(value),
|
|
581
|
+
validateCandidate(value) {
|
|
582
|
+
try {
|
|
583
|
+
normalizeTextStyleProperty(value);
|
|
584
|
+
return [];
|
|
585
|
+
} catch {
|
|
586
|
+
return issue();
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}, {
|
|
590
|
+
argument: "VALUE",
|
|
591
|
+
schemaBundle: fixedInputBundle("setTextStyle-VALUE", fixedSchemas.setTextStyle.properties.VALUE),
|
|
592
|
+
read: (value) => string(value),
|
|
593
|
+
encode: (value) => string(value),
|
|
594
|
+
validateCandidate: () => []
|
|
595
|
+
}],
|
|
596
|
+
dependencies: [{
|
|
597
|
+
selector: "PROPERTY",
|
|
598
|
+
dependents: ["VALUE"]
|
|
599
|
+
}],
|
|
600
|
+
branchPolicies: [{
|
|
601
|
+
selector: "PROPERTY",
|
|
602
|
+
normalize: {
|
|
603
|
+
trim: true,
|
|
604
|
+
lowercase: true
|
|
605
|
+
},
|
|
606
|
+
cases: TEXT_STYLE_PROPERTIES.map((property) => ({
|
|
607
|
+
values: [property],
|
|
608
|
+
activeDependents: ["VALUE"],
|
|
609
|
+
bindings: [styleBinding(property)]
|
|
610
|
+
}))
|
|
611
|
+
}]
|
|
612
|
+
}, {
|
|
613
|
+
apiVersion: 1,
|
|
614
|
+
extensionId,
|
|
615
|
+
editorId: "loading-costume-index-fixed",
|
|
616
|
+
opcodes: [`${extensionId}_loadingCostumeAt`],
|
|
617
|
+
contractId: "turbowarp-asset-cache/loadingCostumeAt.INDEX",
|
|
618
|
+
contractRevision: "1",
|
|
619
|
+
validationContext: context,
|
|
620
|
+
bindings: [{
|
|
621
|
+
argument: "INDEX",
|
|
622
|
+
schemaBundle: fixedInputBundle("loadingCostumeAt-INDEX", fixedSchemas.loadingCostumeAt.properties.INDEX),
|
|
623
|
+
control: { kind: "number" },
|
|
624
|
+
read(value) {
|
|
625
|
+
if (typeof value !== "number" && typeof value !== "string" || typeof value === "string" && value.trim() === "") throw new TypeError("Non-numeric index.");
|
|
626
|
+
const number = Number(value);
|
|
627
|
+
if (!Number.isFinite(number)) throw new TypeError("Nonfinite index.");
|
|
628
|
+
return number;
|
|
629
|
+
},
|
|
630
|
+
encode(value) {
|
|
631
|
+
const parsed = parseFixedNumberInput(value);
|
|
632
|
+
if (parsed.kind !== "valid") throw new TypeError("Invalid index.");
|
|
633
|
+
return parsed.token;
|
|
634
|
+
},
|
|
635
|
+
validateCandidate(value) {
|
|
636
|
+
return Number.isFinite(Number(value)) ? [] : [{ message: "Invalid index." }];
|
|
637
|
+
}
|
|
638
|
+
}]
|
|
639
|
+
}];
|
|
640
|
+
/** Per-instance, idempotent registration. Legacy hosts never acquire the fixed capability. */
|
|
641
|
+
function fixedInputRegistration(scratch) {
|
|
642
|
+
const host = scratch;
|
|
643
|
+
let active;
|
|
644
|
+
let removers = [];
|
|
645
|
+
let disposed = false;
|
|
646
|
+
const dispose = () => {
|
|
647
|
+
host.vm?.runtime?.off?.("RUNTIME_DISPOSED", shutdown);
|
|
648
|
+
for (const remove of removers.splice(0).reverse()) remove();
|
|
649
|
+
active = void 0;
|
|
650
|
+
};
|
|
651
|
+
const shutdown = () => {
|
|
652
|
+
disposed = true;
|
|
653
|
+
dispose();
|
|
654
|
+
};
|
|
655
|
+
return {
|
|
656
|
+
ensure(opcodes) {
|
|
657
|
+
const api = host.gui?.blockEditors;
|
|
658
|
+
if (disposed || api === active) return;
|
|
659
|
+
dispose();
|
|
660
|
+
if (api?.apiVersion !== 1 || typeof api.registerFixedInputEditor !== "function") return;
|
|
661
|
+
try {
|
|
662
|
+
for (const definition of fixedInputEditors) if (definition.opcodes.every((opcode) => opcodes.includes(opcode))) {
|
|
663
|
+
const remove = api.registerFixedInputEditor.call(api, definition);
|
|
664
|
+
if (typeof remove !== "function") throw new TypeError("Invalid fixed registration cleanup.");
|
|
665
|
+
removers.push(remove);
|
|
666
|
+
}
|
|
667
|
+
active = api;
|
|
668
|
+
host.vm?.runtime?.on?.("RUNTIME_DISPOSED", shutdown);
|
|
669
|
+
} catch (error) {
|
|
670
|
+
dispose();
|
|
671
|
+
throw error;
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
dispose: shutdown
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
//#endregion
|
|
678
|
+
//#region node_modules/.pnpm/@kubohiroya+turbowarp-named-data@0.3.1/node_modules/@kubohiroya/turbowarp-named-data/dist/composition.js
|
|
282
679
|
var NAMED_DATA_REGISTRY_SYMBOL_KEY = "@kubohiroya/turbowarp-named-data/registry";
|
|
283
680
|
var NAMED_DATA_REGISTRY_SYMBOL = Symbol.for(NAMED_DATA_REGISTRY_SYMBOL_KEY);
|
|
284
681
|
var NAMED_DATA_NAMESPACE_PATTERN = /^[a-z][a-z0-9.-]{0,63}$/u;
|
|
@@ -299,6 +696,8 @@ var NAMED_DATA_REPRESENTATIONS = [
|
|
|
299
696
|
"markdown",
|
|
300
697
|
"raw"
|
|
301
698
|
];
|
|
699
|
+
var NAMED_DATA_SCHEMA_ID_PATTERN = /^[a-z][a-z0-9.-]{0,127}$/u;
|
|
700
|
+
var NAMED_DATA_SCHEMA_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u;
|
|
302
701
|
var NAMED_DATA_ERROR_CODES = [
|
|
303
702
|
"NAMED_DATA_INVALID_REF",
|
|
304
703
|
"NAMED_DATA_INVALID_REGISTRY",
|
|
@@ -307,6 +706,9 @@ var NAMED_DATA_ERROR_CODES = [
|
|
|
307
706
|
"NAMED_DATA_NOT_FOUND",
|
|
308
707
|
"NAMED_DATA_KIND_MISMATCH",
|
|
309
708
|
"NAMED_DATA_SCOPE_MISMATCH",
|
|
709
|
+
"NAMED_DATA_SCHEMA_NOT_FOUND",
|
|
710
|
+
"NAMED_DATA_SCHEMA_VERSION_MISMATCH",
|
|
711
|
+
"NAMED_DATA_SCHEMA_UNRESOLVED",
|
|
310
712
|
"NAMED_DATA_REPRESENTATION_UNSUPPORTED",
|
|
311
713
|
"NAMED_DATA_INVALID_METADATA",
|
|
312
714
|
"NAMED_DATA_BODY_TOO_LARGE",
|
|
@@ -527,9 +929,21 @@ function validateReferenceShape(reference, representation) {
|
|
|
527
929
|
if (!reference || typeof reference !== "object") throw invalidReference$1();
|
|
528
930
|
requireNamespace(reference.namespace);
|
|
529
931
|
if (typeof reference.name !== "string" || reference.name.length === 0 || reference.name.length > 256 || containsControlCharacter(reference.name) || !NAMED_DATA_KINDS.includes(reference.kind) || !NAMED_DATA_SCOPES.includes(reference.scope) || !NAMED_DATA_REPRESENTATIONS.includes(representation)) throw invalidReference$1();
|
|
932
|
+
if (reference.schemaRef !== void 0) validateSchemaRef(reference.kind, reference.schemaRef);
|
|
530
933
|
}
|
|
531
934
|
function validateMetadata(metadata, reference, representation) {
|
|
532
935
|
if (metadata.representation !== representation || !isNativeRepresentation(metadata.reference.kind, metadata.nativeRepresentation) || metadata.reference.namespace !== reference.namespace || metadata.reference.name !== reference.name || metadata.reference.kind !== reference.kind || metadata.reference.scope !== reference.scope || typeof metadata.mediaType !== "string" || metadata.mediaType.length === 0 || typeof metadata.revision !== "string" || metadata.revision.length === 0 || typeof metadata.replayable !== "boolean" || metadata.byteLength !== void 0 && (!Number.isSafeInteger(metadata.byteLength) || metadata.byteLength < 0) || metadata.digest !== void 0 && !/^sha256-[A-Za-z0-9_-]+$/u.test(metadata.digest)) throw new NamedDataError("NAMED_DATA_INVALID_METADATA", "Provider returned invalid metadata.");
|
|
936
|
+
const expectedSchema = reference.schemaRef;
|
|
937
|
+
const actualSchema = metadata.schemaRef;
|
|
938
|
+
if (actualSchema !== void 0) validateSchemaRef(metadata.reference.kind, actualSchema, "NAMED_DATA_INVALID_METADATA");
|
|
939
|
+
if (metadata.reference.schemaRef !== void 0) validateSchemaRef(metadata.reference.kind, metadata.reference.schemaRef, "NAMED_DATA_INVALID_METADATA");
|
|
940
|
+
if (!sameSchemaRef(expectedSchema, actualSchema) || !sameSchemaRef(expectedSchema, metadata.reference.schemaRef)) throw new NamedDataError("NAMED_DATA_SCHEMA_VERSION_MISMATCH", "Provider schemaRef does not match the requested reference.");
|
|
941
|
+
}
|
|
942
|
+
function validateSchemaRef(kind, schemaRef, errorCode = "NAMED_DATA_INVALID_REF") {
|
|
943
|
+
if (kind !== "structured" || typeof schemaRef !== "object" || schemaRef === null || !NAMED_DATA_SCHEMA_ID_PATTERN.test(String(schemaRef.id ?? "")) || !NAMED_DATA_SCHEMA_VERSION_PATTERN.test(String(schemaRef.version ?? "")) || Object.keys(schemaRef).some((key) => key !== "id" && key !== "version")) throw new NamedDataError(errorCode, "Invalid schemaRef; schema references require a structured value, stable id, and full SemVer version.");
|
|
944
|
+
}
|
|
945
|
+
function sameSchemaRef(left, right) {
|
|
946
|
+
return left === void 0 ? right === void 0 : right !== void 0 && left.id === right.id && left.version === right.version;
|
|
533
947
|
}
|
|
534
948
|
function isNativeRepresentation(kind, representation) {
|
|
535
949
|
if (kind === "structured") return representation === "json" || representation === "yaml";
|
|
@@ -566,7 +980,10 @@ function configuredFlag$1(name) {
|
|
|
566
980
|
const value = globalThis.__TW_NAMED_DATA_FEATURE_FLAGS__?.[name];
|
|
567
981
|
return value === true || value === "true";
|
|
568
982
|
}
|
|
569
|
-
Object.freeze({
|
|
983
|
+
Object.freeze({
|
|
984
|
+
NAMED_DATA_REGISTRY_MVP: configuredFlag$1("NAMED_DATA_REGISTRY_MVP"),
|
|
985
|
+
NAMED_DATA_SCHEMA_REF: configuredFlag$1("NAMED_DATA_SCHEMA_REF")
|
|
986
|
+
});
|
|
570
987
|
//#endregion
|
|
571
988
|
//#region src/asset-cache-error.ts
|
|
572
989
|
var AssetManagerError = class extends Error {
|
|
@@ -948,88 +1365,6 @@ function throwIfNamedBodyAborted(signal) {
|
|
|
948
1365
|
if (signal?.aborted) throw namedBodyAbortError();
|
|
949
1366
|
}
|
|
950
1367
|
//#endregion
|
|
951
|
-
//#region src/text-style.ts
|
|
952
|
-
var TEXT_RUNTIME_NAMESPACE = "text";
|
|
953
|
-
var TEXT_STYLE_RUNTIME_NAMESPACE = "textStyle";
|
|
954
|
-
var TEXT_STYLE_PROPERTIES = [
|
|
955
|
-
"animation",
|
|
956
|
-
"font",
|
|
957
|
-
"color",
|
|
958
|
-
"width",
|
|
959
|
-
"align"
|
|
960
|
-
];
|
|
961
|
-
var DEFAULT_STAGE_WIDTH = 480;
|
|
962
|
-
var DEFAULT_FONT = "Handwriting";
|
|
963
|
-
var DEFAULT_COLOR = "#ffffff";
|
|
964
|
-
var DEFAULT_ALIGNMENT = "center";
|
|
965
|
-
var DEFAULT_OUTLINE_COLOR = "#000000";
|
|
966
|
-
function textRuntimeVariableName(name) {
|
|
967
|
-
return `${TEXT_RUNTIME_NAMESPACE}:${name}`;
|
|
968
|
-
}
|
|
969
|
-
function textStyleRuntimeVariableName(name, property) {
|
|
970
|
-
return `${TEXT_STYLE_RUNTIME_NAMESPACE}:${name}:${property}`;
|
|
971
|
-
}
|
|
972
|
-
function normalizeTextStyleProperty(value) {
|
|
973
|
-
const property = String(value ?? "").trim().toLowerCase();
|
|
974
|
-
if (TEXT_STYLE_PROPERTIES.includes(property)) return property;
|
|
975
|
-
throw new Error(`Unknown text style property: ${property || "(empty)"}`);
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* Normalize a DSL-facing style value for runtime-variable storage.
|
|
979
|
-
* An empty value intentionally resets the property to its default.
|
|
980
|
-
*/
|
|
981
|
-
function normalizeTextStyleValue(property, value) {
|
|
982
|
-
const raw = String(value ?? "").trim();
|
|
983
|
-
if (!raw) return "";
|
|
984
|
-
switch (property) {
|
|
985
|
-
case "animation": {
|
|
986
|
-
const animation = raw.toLowerCase() === "typing" ? "type" : raw.toLowerCase();
|
|
987
|
-
if (animation === "none" || animation === "type" || animation === "rainbow" || animation === "zoom" || animation === "shake") return animation;
|
|
988
|
-
throw new Error(`Invalid text animation: ${raw}`);
|
|
989
|
-
}
|
|
990
|
-
case "font": return raw;
|
|
991
|
-
case "color": {
|
|
992
|
-
if (/^#[0-9a-f]{6}$/i.test(raw)) return raw.toLowerCase();
|
|
993
|
-
const shortColor = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(raw);
|
|
994
|
-
if (shortColor) return `#${shortColor[1]}${shortColor[1]}${shortColor[2]}${shortColor[2]}${shortColor[3]}${shortColor[3]}`.toLowerCase();
|
|
995
|
-
throw new Error(`Invalid text color: ${raw}`);
|
|
996
|
-
}
|
|
997
|
-
case "width": {
|
|
998
|
-
const width = Number(raw);
|
|
999
|
-
if (!Number.isFinite(width) || width <= 0) throw new Error(`Text width must be a positive number: ${raw}`);
|
|
1000
|
-
return String(width);
|
|
1001
|
-
}
|
|
1002
|
-
case "align": {
|
|
1003
|
-
const align = raw.toLowerCase();
|
|
1004
|
-
if (align === "left" || align === "center" || align === "right") return align;
|
|
1005
|
-
throw new Error(`Invalid text alignment: ${raw}`);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
function resolveTextStyle(name, stageWidth, getRuntimeVariable) {
|
|
1010
|
-
const width = Number(stageWidth);
|
|
1011
|
-
const defaults = {
|
|
1012
|
-
animation: "none",
|
|
1013
|
-
font: DEFAULT_FONT,
|
|
1014
|
-
color: DEFAULT_COLOR,
|
|
1015
|
-
width: Number.isFinite(width) && width > 0 ? width : DEFAULT_STAGE_WIDTH,
|
|
1016
|
-
align: DEFAULT_ALIGNMENT
|
|
1017
|
-
};
|
|
1018
|
-
const read = (property) => normalizeTextStyleValue(property, getRuntimeVariable(textStyleRuntimeVariableName(name, property)));
|
|
1019
|
-
const animation = read("animation");
|
|
1020
|
-
const font = read("font");
|
|
1021
|
-
const color = read("color");
|
|
1022
|
-
const configuredWidth = read("width");
|
|
1023
|
-
const align = read("align");
|
|
1024
|
-
return {
|
|
1025
|
-
animation: animation ? animation : defaults.animation,
|
|
1026
|
-
font: font || defaults.font,
|
|
1027
|
-
color: color || defaults.color,
|
|
1028
|
-
width: configuredWidth ? Number(configuredWidth) : defaults.width,
|
|
1029
|
-
align: align ? align : defaults.align
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
//#endregion
|
|
1033
1368
|
//#region src/extension.ts
|
|
1034
1369
|
var EXTENSION_ID = "kubohiroyaassetcache";
|
|
1035
1370
|
var EXTENSION_VERSION = "0.14.0";
|
|
@@ -1534,6 +1869,7 @@ var AssetManagerExtension = class {
|
|
|
1534
1869
|
this.unbindNamedDataRegistryLifecycle?.();
|
|
1535
1870
|
this.unbindNamedDataRegistryLifecycle = void 0;
|
|
1536
1871
|
};
|
|
1872
|
+
fixedEditors = fixedInputRegistration(Scratch);
|
|
1537
1873
|
constructor(featureFlags = FEATURE_FLAGS) {
|
|
1538
1874
|
this.featureFlags = Object.freeze({ ...featureFlags });
|
|
1539
1875
|
if (this.featureFlags.NAMED_ASSET_BODY_PROVIDER) {
|
|
@@ -1600,6 +1936,8 @@ var AssetManagerExtension = class {
|
|
|
1600
1936
|
return loadingCostumes[((Number.isFinite(numericIndex) ? Math.max(1, Math.trunc(numericIndex)) : 1) - 1) % loadingCostumes.length];
|
|
1601
1937
|
}
|
|
1602
1938
|
getInfo() {
|
|
1939
|
+
const blocks = blockDefinitions.map((block) => this.toScratchBlock(block));
|
|
1940
|
+
this.fixedEditors.ensure(blocks.map((block) => `${EXTENSION_ID}_${block.opcode}`));
|
|
1603
1941
|
return {
|
|
1604
1942
|
id: EXTENSION_ID,
|
|
1605
1943
|
name: Scratch.translate(block_definitions_default.extensionName),
|
|
@@ -1608,9 +1946,13 @@ var AssetManagerExtension = class {
|
|
|
1608
1946
|
color1: "#5b7cfa",
|
|
1609
1947
|
color2: "#425ed8",
|
|
1610
1948
|
color3: "#2f46aa",
|
|
1611
|
-
blocks
|
|
1949
|
+
blocks
|
|
1612
1950
|
};
|
|
1613
1951
|
}
|
|
1952
|
+
/** Release only this optional editor registration; runtime data remains unchanged. */
|
|
1953
|
+
dispose() {
|
|
1954
|
+
this.fixedEditors.dispose();
|
|
1955
|
+
}
|
|
1614
1956
|
/**
|
|
1615
1957
|
* Exposes the stock extension registry through a host-neutral DOM image
|
|
1616
1958
|
* resource contract for other unsandboxed extensions.
|
|
@@ -121,6 +121,7 @@ export declare class AssetManagerExtension {
|
|
|
121
121
|
private readonly releaseDOMImageResourcesForRuntimeDispose;
|
|
122
122
|
private readonly releaseNamedBodySnapshotsForLifecycle;
|
|
123
123
|
private readonly unregisterNamedBodyProviderForRuntimeDispose;
|
|
124
|
+
private readonly fixedEditors;
|
|
124
125
|
constructor(featureFlags?: AssetManagerFeatureFlags);
|
|
125
126
|
setLoadingBackdrop(args: BlockArgs): void;
|
|
126
127
|
setLoadingCostumes(args: BlockArgs): void;
|
|
@@ -138,6 +139,8 @@ export declare class AssetManagerExtension {
|
|
|
138
139
|
color3: string;
|
|
139
140
|
blocks: Record<string, unknown>[];
|
|
140
141
|
};
|
|
142
|
+
/** Release only this optional editor registration; runtime data remains unchanged. */
|
|
143
|
+
dispose(): void;
|
|
141
144
|
/**
|
|
142
145
|
* Exposes the stock extension registry through a host-neutral DOM image
|
|
143
146
|
* resource contract for other unsandboxed extensions.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FixedInputBinding, FixedInputEditorOptions } from '@kubohiroya/turbowarp-extension-data-editor';
|
|
2
|
+
import { type TextStyleProperty } from './text-style.js';
|
|
3
|
+
/** New edits preserve the candidate token; existing aliases are display projections only. */
|
|
4
|
+
export declare function styleBinding(property: TextStyleProperty): FixedInputBinding;
|
|
5
|
+
export declare const fixedInputEditors: readonly FixedInputEditorOptions[];
|
|
6
|
+
/** Per-instance, idempotent registration. Legacy hosts never acquire the fixed capability. */
|
|
7
|
+
export declare function fixedInputRegistration(scratch: unknown): {
|
|
8
|
+
ensure(opcodes: readonly string[]): void;
|
|
9
|
+
dispose: () => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SchemaBundle, SchemaDocument } from '@kubohiroya/turbowarp-extension-data-editor/schema';
|
|
2
|
+
/** Canonical owner schema fragments; no network resources or runtime providers. */
|
|
3
|
+
export declare function fixedInputBundle(fragment: string, schema: SchemaDocument): SchemaBundle;
|
|
4
|
+
export declare const fixedSchemas: {
|
|
5
|
+
setTextStyle: {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: {
|
|
8
|
+
PROPERTY: {
|
|
9
|
+
type: string;
|
|
10
|
+
enum: string[];
|
|
11
|
+
};
|
|
12
|
+
VALUE: {
|
|
13
|
+
type: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
additionalProperties: boolean;
|
|
17
|
+
};
|
|
18
|
+
animation: {
|
|
19
|
+
type: string;
|
|
20
|
+
enum: string[];
|
|
21
|
+
};
|
|
22
|
+
font: {
|
|
23
|
+
type: string;
|
|
24
|
+
};
|
|
25
|
+
color: {
|
|
26
|
+
type: string;
|
|
27
|
+
pattern: string;
|
|
28
|
+
};
|
|
29
|
+
width: {
|
|
30
|
+
type: string;
|
|
31
|
+
$comment: string;
|
|
32
|
+
};
|
|
33
|
+
align: {
|
|
34
|
+
type: string;
|
|
35
|
+
enum: string[];
|
|
36
|
+
};
|
|
37
|
+
loadingCostumeAt: {
|
|
38
|
+
type: string;
|
|
39
|
+
properties: {
|
|
40
|
+
INDEX: {
|
|
41
|
+
type: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
additionalProperties: boolean;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 固定入力エディターの契約
|
|
2
|
+
|
|
3
|
+
対応GUIの起動時に`blockEditorDialogs=1&blockEditorFixedInputs=1`を指定し、再読込した場合だけ登録する。既定OFFで、旧GUIやCLIに固定登録APIがなければ何もしない。公開するブロック・引数・既定値・`docsURI`・既存データ形式は変更しない。
|
|
4
|
+
|
|
5
|
+
| ブロック | 対象 | UIと保存 |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| `setTextStyle` | `PROPERTY` / `VALUE` | PROPERTYの固定5選択とVALUEの有限分岐。animation/alignは選択、fontは自由入力、colorは色、widthは数値文字列。VALUEは常にSTRINGで空文字reset可能 |
|
|
8
|
+
| `loadingCostumeAt` | `INDEX` | 数値UI。新入力は有限の数値表記。小数・負数を許容し、既存runtimeの切捨て・下限補正・循環を維持。非表示の互換ブロック |
|
|
9
|
+
|
|
10
|
+
Schemaの正本は`schemas/block-editor-fixed-inputs.schema.json`。`getInfo()`と`src/text-style.ts`の`normalizeTextStyleProperty` / `normalizeTextStyleValue`、`src/extension.ts`の`loadingCostumeAt`がruntime契約の正本であり、棚卸しやUI候補だけを受け入れ根拠にしない。新Schemaは登録用の各fragmentに投影し、ネットワークSchema参照を行わない。NP-finite-new-input-v1の対象はINDEXであり、STRINGであるVALUE.widthへ一律適用しない。widthのSchemaはSTRING構造を確認し、CPの正の有限値/resetをpure normalizerで意味検証する。STRINGの数値UIとprogrammatic候補はともに`0x10`・`+20`等を既存runtimeと同じく受け入れる。JSON数値文法のbuffer検査はINDEX等のnumber型投影に限定し、widthと区別する。
|
|
11
|
+
|
|
12
|
+
既存alias(`typing`、短縮色、大小文字、旧数値表記)は表示投影だけでは書き換えない。PROPERTYの修復・変更時は最終branchで必要なVALUEを検査し、不適合なら修正/resetまで全patchを拒否する。selectorがreporter・欠落・非対応ならVALUEは読取専用。reporterを評価・置換しない。未知literal selectorは既知値へ修復可能で、未変更なら未知rawも保持する。NAMEや素材registry、font候補providerには触れない。
|
|
13
|
+
|
|
14
|
+
同じ画面で分岐を切り替えてもdraftを保持し、保存失敗後も保持する。取消・dispose・project/target/登録の失効では共通sessionが破棄する。再openは現在のrawから開始し、旧draftを復活させない。登録はgetInfoに存在するopcodeだけを対象とし、同じinstance/APIへの重複登録を行わず、API置換・部分失敗・runtime終了・disposeでcleanupする。
|
|
15
|
+
|
|
16
|
+
共通依存はGit commit `485f0e550e622235624b5e9176820161aeeba252`に固定する。開発用の型とpure数値parserを使い、登録はhostの`registerFixedInputEditor`へoptionsを渡す。既存composition APIにGUI/React実行依存を追加しない。runtime同梱JSと公開入口の型が外部common参照を要求しないことをbuildとpack consumerで確認する。
|
|
17
|
+
|
|
18
|
+
`tests/fixed-input-editors.test.ts`でCP-asset-cacheのBC01〜05/14全6fixture、全5branchのruntime比較、空文字reset、有限数値と精度表記、旧raw保持、登録とcleanupを検証する。Asset Managerは別ownerであり、この結果を流用して合格とはしない。文書入口は`docs/index.html`と`docs/ja/index.html`の各固定アンカーから到達でき、Markdown再生成ではこれらの静的HTML説明を削除しない。
|
|
19
|
+
|
|
20
|
+
切戻しは固定フラグをOFFにして再読込する。依存を戻す場合はmanifest・lock・実解決を一組で戻す。既存raw値やsb3の移行は不要。今回の作業はローカルのみで、commit・push・PR・merge・Pages公開・npm公開・Issue操作は含まない。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubohiroya/turbowarp-asset-cache",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A browser-local image, audio, and runtime-text asset cache for TurboWarp projects.",
|
|
5
5
|
"author": "Hiroya Kubo <hiroya@cuc.ac.jp>",
|
|
6
6
|
"type": "module",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist/",
|
|
25
|
+
"schemas/",
|
|
26
|
+
"docs/fixed-input-editors.ja.md",
|
|
25
27
|
"README.md",
|
|
26
28
|
"LICENSE"
|
|
27
29
|
],
|
|
@@ -60,9 +62,10 @@
|
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
64
|
"@eslint/js": "^9.39.5",
|
|
63
|
-
"@kubohiroya/turbowarp-extension-
|
|
64
|
-
"@kubohiroya/turbowarp-
|
|
65
|
-
"@kubohiroya/
|
|
65
|
+
"@kubohiroya/turbowarp-extension-data-editor": "0.2.1",
|
|
66
|
+
"@kubohiroya/turbowarp-extension-manifest": "0.3.2",
|
|
67
|
+
"@kubohiroya/turbowarp-named-data": "0.3.1",
|
|
68
|
+
"@kubohiroya/vite-plugin-turbowarp-extension": "0.6.1",
|
|
66
69
|
"@types/node": "^22.20.1",
|
|
67
70
|
"@xmldom/xmldom": "0.9.11",
|
|
68
71
|
"eslint": "^9.39.5",
|
|
@@ -73,7 +76,7 @@
|
|
|
73
76
|
"vitest": "^4.1.10"
|
|
74
77
|
},
|
|
75
78
|
"peerDependencies": {
|
|
76
|
-
"@kubohiroya/turbowarp-named-data": "
|
|
79
|
+
"@kubohiroya/turbowarp-named-data": "0.3.1"
|
|
77
80
|
},
|
|
78
81
|
"keywords": [
|
|
79
82
|
"turbowarp",
|
|
@@ -81,5 +84,11 @@
|
|
|
81
84
|
"extension",
|
|
82
85
|
"assets",
|
|
83
86
|
"indexeddb"
|
|
84
|
-
]
|
|
87
|
+
],
|
|
88
|
+
"gitHead": "9a1a4a1a016722eccf649207f8517c8533bf68b0",
|
|
89
|
+
"x-turbowarp-source": {
|
|
90
|
+
"revision": "9a1a4a1a016722eccf649207f8517c8533bf68b0",
|
|
91
|
+
"revisionRole": "base-commit",
|
|
92
|
+
"sourceState": "local-release-overlay"
|
|
93
|
+
}
|
|
85
94
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://kubohiroya.github.io/turbowarp-asset-cache/schemas/block-editor-fixed-inputs.schema.json",
|
|
4
|
+
"$defs": {
|
|
5
|
+
"setTextStyle": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"PROPERTY": {"type": "string", "enum": ["animation", "font", "color", "width", "align"]},
|
|
9
|
+
"VALUE": {"type": "string"}
|
|
10
|
+
},
|
|
11
|
+
"additionalProperties": false
|
|
12
|
+
},
|
|
13
|
+
"animation": {"type": "string", "enum": ["", "none", "type", "rainbow", "zoom", "shake"]},
|
|
14
|
+
"font": {"type": "string"},
|
|
15
|
+
"color": {"type": "string", "pattern": "^(?:|#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})$"},
|
|
16
|
+
"width": {"type": "string", "$comment": "Empty/trimmed empty resets; otherwise normalizeTextStyleValue requires Number(value) finite and positive. Preserve the existing STRING grammar, including hexadecimal and leading plus."},
|
|
17
|
+
"align": {"type": "string", "enum": ["", "left", "center", "right"]},
|
|
18
|
+
"loadingCostumeAt": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {"INDEX": {"type": "number"}},
|
|
21
|
+
"additionalProperties": false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|