hikkaku 0.3.2 → 0.3.4

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.
@@ -1,9 +1,27 @@
1
+ import { InputType } from "sb3-types/enum";
1
2
  import * as sb3 from "sb3-types";
2
3
  import { Costume, Sound } from "sb3-types";
3
4
 
4
5
  //#region src/core/types.d.ts
5
6
  type PrimitiveAvailableOnScratch = number | boolean | string;
6
- type PrimitiveSource<T extends PrimitiveAvailableOnScratch> = T | HikkakuBlock;
7
+ type HikkakuTypeTag = 'number' | 'bool' | 'string';
8
+ type HikkakuBrand<T extends HikkakuTypeTag> = {
9
+ readonly __hikkakuType: T;
10
+ };
11
+ type HikkakuNumber = HikkakuBrand<'number'>;
12
+ type HikkakuBool = HikkakuBrand<'bool'>;
13
+ type HikkakuString = HikkakuBrand<'string'>;
14
+ type HikkakuType = HikkakuNumber | HikkakuBool | HikkakuString;
15
+ type PrimitiveToHikkakuType<T extends PrimitiveAvailableOnScratch> = T extends number ? HikkakuNumber : T extends boolean ? HikkakuBool : T extends string ? HikkakuString : never;
16
+ type HikkakuTypeToPrimitive<T extends HikkakuType> = T extends HikkakuNumber ? number : T extends HikkakuBool ? boolean : T extends HikkakuString ? string : never;
17
+ interface HikkakuBlock {
18
+ isBlock: true;
19
+ id: string;
20
+ }
21
+ interface HikkakuReporterBlock<T extends HikkakuType = HikkakuType> extends HikkakuBlock {
22
+ readonly __hikkakuType: T['__hikkakuType'];
23
+ }
24
+ type PrimitiveSource<T extends HikkakuType> = HikkakuTypeToPrimitive<T> | HikkakuReporterBlock;
7
25
  interface VariableBase {
8
26
  id: string;
9
27
  name: string;
@@ -36,8 +54,8 @@ interface VariableReference extends VariableBase {
36
54
  type: 'variable';
37
55
  }
38
56
  interface VariableDefinition extends VariableReference {
39
- get(): HikkakuBlock;
40
- set(value: PrimitiveSource<number | string>): HikkakuBlock;
57
+ get(): HikkakuReporterBlock<HikkakuNumber | HikkakuString>;
58
+ set(value: PrimitiveSource<HikkakuNumber | HikkakuString>): HikkakuBlock;
41
59
  }
42
60
  interface ListReference extends VariableBase {
43
61
  type: 'list';
@@ -46,16 +64,12 @@ interface CostumeReference {
46
64
  name: string;
47
65
  type: 'costume';
48
66
  }
49
- type CostumeSource = PrimitiveSource<string> | CostumeReference;
67
+ type CostumeSource = PrimitiveSource<HikkakuString> | CostumeReference;
50
68
  interface SoundReference {
51
69
  name: string;
52
70
  type: 'sound';
53
71
  }
54
- type SoundSource = PrimitiveSource<string> | SoundReference;
55
- interface HikkakuBlock {
56
- isBlock: true;
57
- id: string;
58
- }
72
+ type SoundSource = PrimitiveSource<HikkakuString> | SoundReference;
59
73
  type CostumeData = Costume & {
60
74
  _data?: Uint8Array;
61
75
  };
@@ -64,17 +78,45 @@ type SoundData = Sound & {
64
78
  };
65
79
  //#endregion
66
80
  //#region src/core/block-helper.d.ts
67
- declare const fromPrimitiveSource: <T extends PrimitiveAvailableOnScratch>(source: PrimitiveSource<T>) => sb3.Input;
68
- declare const fromPrimitiveSourceColor: (color: PrimitiveSource<`#${string}` | (string & {})>) => sb3.Input;
69
- declare const unwrapCostumeSource: (source: CostumeSource) => PrimitiveSource<string>;
70
- declare const unwrapSoundSource: (source: SoundSource) => PrimitiveSource<string>;
81
+ type MappingToPrimitive<T extends PrimitiveInputType> = T extends InputType.Number ? number : T extends InputType.PositiveNumber ? number : T extends InputType.Integer ? number : T extends InputType.Angle ? number : T extends InputType.PositiveInteger ? number : T extends InputType.String ? string | number : T extends InputType.Broadcast ? string : T extends InputType.Color ? string : never;
82
+ type PrimitiveInputType = sb3.InputPrimitive['0'];
83
+ declare function fromPrimitiveSource<T extends PrimitiveInputType>(inputType: T, source: PrimitiveSource<PrimitiveToHikkakuType<MappingToPrimitive<T>>>, defaultValue?: MappingToPrimitive<T>): sb3.Input;
84
+ declare function fromBooleanSource(source: PrimitiveSource<HikkakuBool>): sb3.Input;
85
+ declare const unwrapCostumeSource: (source: CostumeSource) => PrimitiveSource<HikkakuString>;
86
+ declare const unwrapSoundSource: (source: SoundSource) => PrimitiveSource<HikkakuString>;
71
87
  declare const isHikkakuBlock: (block: unknown) => block is HikkakuBlock;
72
- declare const menuInput: <T extends PrimitiveAvailableOnScratch>(source: PrimitiveSource<T>, createMenu: (source?: T) => HikkakuBlock) => sb3.Input;
88
+ declare const menuInput: <T extends PrimitiveAvailableOnScratch>(source: PrimitiveSource<PrimitiveToHikkakuType<T>>, createMenu: (source?: T) => HikkakuReporterBlock<HikkakuString>) => sb3.Input;
73
89
  declare const isCostumeReference: (source: unknown) => source is CostumeReference;
74
90
  declare const isSoundReference: (source: unknown) => source is SoundReference;
75
91
  //#endregion
76
92
  //#region src/core/composer.d.ts
77
93
  type Handler = () => void;
94
+ type BuildScopeKind = 'run' | 'stack';
95
+ interface BuildScopeFrame {
96
+ id: number;
97
+ kind: BuildScopeKind;
98
+ forbidStop: boolean;
99
+ onExit: Set<() => void>;
100
+ }
101
+ interface RootContext {
102
+ blocks: Record<string, sb3.Block>;
103
+ adder?: (id: string, block: sb3.Block) => void;
104
+ usedAsValueSet: WeakSet<sb3.Block>;
105
+ valueBlockSet: WeakSet<sb3.Block>;
106
+ blockToId: WeakMap<sb3.Block, string>;
107
+ scopeStack: BuildScopeFrame[];
108
+ nextScopeId: number;
109
+ }
110
+ declare const getRootContext: () => RootContext;
111
+ interface BuildScopeFrameSnapshot {
112
+ id: number;
113
+ kind: BuildScopeKind;
114
+ depth: number;
115
+ forbidStop: boolean;
116
+ }
117
+ declare const __unstable_getBuildScopeFrame: () => BuildScopeFrameSnapshot | null;
118
+ declare const __unstable_onBuildScopeExit: (callback: () => void) => void;
119
+ declare const __unstable_forbidStopInCurrentScope: () => void;
78
120
  interface BlockInit {
79
121
  inputs?: Record<string, sb3.Input>;
80
122
  fields?: Record<string, sb3.Fields>;
@@ -84,7 +126,7 @@ interface BlockInit {
84
126
  isValue?: boolean;
85
127
  }
86
128
  declare const block: (opcode: string, init: BlockInit) => HikkakuBlock;
87
- declare const valueBlock: (opcode: string, init: BlockInit) => HikkakuBlock;
129
+ declare const valueBlock: <T extends HikkakuType>(opcode: string, init: BlockInit) => HikkakuReporterBlock<T>;
88
130
  declare const substack: (handler: Handler) => string | null;
89
131
  declare const attachStack: (parentId: string, handler?: Handler) => string | null;
90
132
  declare const createBlocks: (handler: Handler) => Record<string, sb3.Block>;
@@ -131,6 +173,7 @@ interface SpriteOptions {
131
173
  x?: number;
132
174
  y?: number;
133
175
  }
176
+ declare const __unstable_getBuildTarget: () => Target | null;
134
177
  declare class Target<IsStage extends boolean = boolean> {
135
178
  #private;
136
179
  readonly isStage: IsStage;
@@ -157,4 +200,4 @@ declare class Project {
157
200
  getAdditionalAssets(): Map<string, Uint8Array>;
158
201
  }
159
202
  //#endregion
160
- export { SoundData as A, CreateVariableOptions as C, MonitorPosition as D, ListReference as E, VariableMonitorMode as F, VariableMonitorOptions as I, VariableReference as L, SoundSource as M, VariableBase as N, PrimitiveAvailableOnScratch as O, VariableDefinition as P, CreateListOptions as S, ListMonitorOptions as T, unwrapCostumeSource as _, Handler as a, CostumeReference as b, createBlocks as c, fromPrimitiveSource as d, fromPrimitiveSourceColor as f, menuInput as g, isSoundReference as h, BlockInit as i, SoundReference as j, PrimitiveSource as k, substack as l, isHikkakuBlock as m, SpriteOptions as n, attachStack as o, isCostumeReference as p, Target as r, block as s, Project as t, valueBlock as u, unwrapSoundSource as v, HikkakuBlock as w, CostumeSource as x, CostumeData as y };
203
+ export { CreateVariableOptions as A, MonitorPosition as B, menuInput as C, CostumeReference as D, CostumeData as E, HikkakuString as F, SoundReference as G, PrimitiveSource as H, HikkakuType as I, VariableDefinition as J, SoundSource as K, HikkakuTypeToPrimitive as L, HikkakuBool as M, HikkakuNumber as N, CostumeSource as O, HikkakuReporterBlock as P, ListMonitorOptions as R, isSoundReference as S, unwrapSoundSource as T, PrimitiveToHikkakuType as U, PrimitiveAvailableOnScratch as V, SoundData as W, VariableMonitorOptions as X, VariableMonitorMode as Y, VariableReference as Z, valueBlock as _, BlockInit as a, isCostumeReference as b, Handler as c, __unstable_onBuildScopeExit as d, attachStack as f, substack as g, getRootContext as h, __unstable_getBuildTarget as i, HikkakuBlock as j, CreateListOptions as k, __unstable_forbidStopInCurrentScope as l, createBlocks as m, SpriteOptions as n, BuildScopeFrameSnapshot as o, block as p, VariableBase as q, Target as r, BuildScopeKind as s, Project as t, __unstable_getBuildScopeFrame as u, fromBooleanSource as v, unwrapCostumeSource as w, isHikkakuBlock as x, fromPrimitiveSource as y, ListReference as z };
package/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as SoundData, C as CreateVariableOptions, D as MonitorPosition, E as ListReference, F as VariableMonitorMode, I as VariableMonitorOptions, L as VariableReference, M as SoundSource, N as VariableBase, O as PrimitiveAvailableOnScratch, P as VariableDefinition, S as CreateListOptions, T as ListMonitorOptions, _ as unwrapCostumeSource, a as Handler, b as CostumeReference, c as createBlocks, d as fromPrimitiveSource, f as fromPrimitiveSourceColor, g as menuInput, h as isSoundReference, i as BlockInit, j as SoundReference, k as PrimitiveSource, l as substack, m as isHikkakuBlock, n as SpriteOptions, o as attachStack, p as isCostumeReference, r as Target, s as block, t as Project, u as valueBlock, v as unwrapSoundSource, w as HikkakuBlock, x as CostumeSource, y as CostumeData } from "./project-CpV5Dm-X.mjs";
2
- export { BlockInit, CostumeData, CostumeReference, CostumeSource, CreateListOptions, CreateVariableOptions, Handler, HikkakuBlock, ListMonitorOptions, ListReference, MonitorPosition, PrimitiveAvailableOnScratch, PrimitiveSource, Project, SoundData, SoundReference, SoundSource, SpriteOptions, Target, VariableBase, VariableDefinition, VariableMonitorMode, VariableMonitorOptions, VariableReference, attachStack, block, createBlocks, fromPrimitiveSource, fromPrimitiveSourceColor, isCostumeReference, isHikkakuBlock, isSoundReference, menuInput, substack, unwrapCostumeSource, unwrapSoundSource, valueBlock };
1
+ import { A as CreateVariableOptions, B as MonitorPosition, C as menuInput, D as CostumeReference, E as CostumeData, F as HikkakuString, G as SoundReference, H as PrimitiveSource, I as HikkakuType, J as VariableDefinition, K as SoundSource, L as HikkakuTypeToPrimitive, M as HikkakuBool, N as HikkakuNumber, O as CostumeSource, P as HikkakuReporterBlock, R as ListMonitorOptions, S as isSoundReference, T as unwrapSoundSource, U as PrimitiveToHikkakuType, V as PrimitiveAvailableOnScratch, W as SoundData, X as VariableMonitorOptions, Y as VariableMonitorMode, Z as VariableReference, _ as valueBlock, a as BlockInit, b as isCostumeReference, c as Handler, d as __unstable_onBuildScopeExit, f as attachStack, g as substack, h as getRootContext, i as __unstable_getBuildTarget, j as HikkakuBlock, k as CreateListOptions, l as __unstable_forbidStopInCurrentScope, m as createBlocks, n as SpriteOptions, o as BuildScopeFrameSnapshot, p as block, q as VariableBase, r as Target, s as BuildScopeKind, t as Project, u as __unstable_getBuildScopeFrame, v as fromBooleanSource, w as unwrapCostumeSource, x as isHikkakuBlock, y as fromPrimitiveSource, z as ListReference } from "./index-kUDvI5sE.mjs";
2
+ export { BlockInit, BuildScopeFrameSnapshot, BuildScopeKind, CostumeData, CostumeReference, CostumeSource, CreateListOptions, CreateVariableOptions, Handler, HikkakuBlock, HikkakuBool, HikkakuNumber, HikkakuReporterBlock, HikkakuString, HikkakuType, HikkakuTypeToPrimitive, ListMonitorOptions, ListReference, MonitorPosition, PrimitiveAvailableOnScratch, PrimitiveSource, PrimitiveToHikkakuType, Project, SoundData, SoundReference, SoundSource, SpriteOptions, Target, VariableBase, VariableDefinition, VariableMonitorMode, VariableMonitorOptions, VariableReference, __unstable_forbidStopInCurrentScope, __unstable_getBuildScopeFrame, __unstable_getBuildTarget, __unstable_onBuildScopeExit, attachStack, block, createBlocks, fromBooleanSource, fromPrimitiveSource, getRootContext, isCostumeReference, isHikkakuBlock, isSoundReference, menuInput, substack, unwrapCostumeSource, unwrapSoundSource, valueBlock };
package/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import { a as valueBlock, c as isCostumeReference, d as menuInput, f as unwrapCostumeSource, i as substack, l as isHikkakuBlock, n as block, o as fromPrimitiveSource, p as unwrapSoundSource, r as createBlocks, s as fromPrimitiveSourceColor, t as attachStack, u as isSoundReference } from "./composer-bPcsVhIg.mjs";
1
+ import { _ as valueBlock, a as isSoundReference, c as unwrapSoundSource, d as __unstable_onBuildScopeExit, f as attachStack, g as substack, h as getRootContext, i as isHikkakuBlock, l as __unstable_forbidStopInCurrentScope, m as createBlocks, n as fromPrimitiveSource, o as menuInput, p as block, r as isCostumeReference, s as unwrapCostumeSource, t as fromBooleanSource, u as __unstable_getBuildScopeFrame } from "./block-helper-DaOyXkRZ.mjs";
2
+ import { InputType } from "sb3-types/enum";
2
3
 
3
4
  //#region src/core/monitors.ts
4
5
  const createVariableMonitor = (id, name, defaultValue, spriteName, options) => {
@@ -76,6 +77,10 @@ const collectExtensions = (targets) => {
76
77
  }
77
78
  return Array.from(extensions).sort();
78
79
  };
80
+ const buildTargetStack = [];
81
+ const __unstable_getBuildTarget = () => {
82
+ return buildTargetStack[buildTargetStack.length - 1] ?? null;
83
+ };
79
84
  var Target = class {
80
85
  isStage;
81
86
  name;
@@ -97,9 +102,15 @@ var Target = class {
97
102
  this.#y = options?.y;
98
103
  }
99
104
  run(handler) {
100
- const blocks = createBlocks(() => {
101
- handler(this);
102
- });
105
+ buildTargetStack.push(this);
106
+ let blocks = {};
107
+ try {
108
+ blocks = createBlocks(() => {
109
+ handler(this);
110
+ });
111
+ } finally {
112
+ buildTargetStack.pop();
113
+ }
103
114
  this.#blocks = {
104
115
  ...this.#blocks,
105
116
  ...blocks
@@ -120,7 +131,7 @@ var Target = class {
120
131
  type: "variable",
121
132
  get: () => valueBlock("data_variable", { fields: { VARIABLE: [name, id] } }),
122
133
  set: (value) => block("data_setvariableto", {
123
- inputs: { VALUE: fromPrimitiveSource(value) },
134
+ inputs: { VALUE: fromPrimitiveSource(InputType.String, value) },
124
135
  fields: { VARIABLE: [name, id] }
125
136
  })
126
137
  };
@@ -229,4 +240,4 @@ var Project = class {
229
240
  };
230
241
 
231
242
  //#endregion
232
- export { Project, Target, attachStack, block, createBlocks, fromPrimitiveSource, fromPrimitiveSourceColor, isCostumeReference, isHikkakuBlock, isSoundReference, menuInput, substack, unwrapCostumeSource, unwrapSoundSource, valueBlock };
243
+ export { Project, Target, __unstable_forbidStopInCurrentScope, __unstable_getBuildScopeFrame, __unstable_getBuildTarget, __unstable_onBuildScopeExit, attachStack, block, createBlocks, fromBooleanSource, fromPrimitiveSource, getRootContext, isCostumeReference, isHikkakuBlock, isSoundReference, menuInput, substack, unwrapCostumeSource, unwrapSoundSource, valueBlock };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hikkaku",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "exports": {
@@ -31,14 +31,17 @@
31
31
  },
32
32
  "scripts": {
33
33
  "build": "bun --bun tsdown",
34
+ "test": "vp test run",
34
35
  "typecheck": "tsgo"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@turbowarp/packager": "^3.11.0",
38
39
  "@types/bun": "latest",
39
40
  "@typescript/native-preview": "^7.0.0-dev.20260127.1",
41
+ "@vitest/coverage-v8": "4.0.18",
40
42
  "rolldown": "1.0.0-rc.4",
41
- "tsdown": "^0.20.0-beta.4"
43
+ "tsdown": "^0.20.0-beta.4",
44
+ "vite-plus": "^0.0.0-3262bda4.20260210-0221"
42
45
  },
43
46
  "peerDependencies": {
44
47
  "typescript": "^5"
package/types.d.mts CHANGED
@@ -18,4 +18,11 @@ declare module '*.mp3?scratch' {
18
18
  import * as sb3 from 'sb3-types';
19
19
  const content: sb3.Sound;
20
20
  export default content;
21
+ }
22
+ declare module 'vite-plus' {
23
+ export function defineConfig<T>(config: T): T;
24
+ }
25
+ declare module 'vite-plus/test' {
26
+ export { describe, expect, it, test } from 'bun:test';
27
+ export type { TestInterface } from 'bun:test';
21
28
  }
package/vite/index.mjs CHANGED
@@ -1,9 +1,8 @@
1
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
1
+ import { mkdir, rm, writeFile } from "node:fs/promises";
2
2
  import * as path from "node:path";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import { pathToFileURL } from "node:url";
4
4
  import { zip, zipSync } from "fflate/node";
5
5
  import { createServerModuleRunner } from "vite";
6
- import crypto from "node:crypto";
7
6
 
8
7
  //#region src/vite/plugin-scratch-import.ts
9
8
  const pluginScratchImport = () => ({
@@ -22,22 +21,28 @@ const pluginScratchImport = () => ({
22
21
  const url = new URL(id.slice(9, -8));
23
22
  const ext = url.pathname.split(".").pop();
24
23
  if (!ext) throw new Error(`Unsupported scratch asset type: ${url.pathname}`);
25
- const file = await readFile(fileURLToPath(url));
26
- const hash = crypto.createHash("md5");
27
- hash.update(file);
28
- const md5 = hash.digest("hex");
29
- const data = {
30
- name: path.basename(url.pathname),
31
- _data: Buffer.from(file).toString("base64"),
32
- assetId: md5,
33
- dataFormat: ext,
34
- md5ext: `${md5}.${ext}`
35
- };
36
24
  return `
37
- const data = ${JSON.stringify(data)}
38
- // to Uint8Array
39
- data._data = Uint8Array.from(atob(data._data), c => c.charCodeAt(0));
25
+ import crypto from 'node:crypto';
26
+ import { readFile } from 'node:fs/promises';
27
+ import * as path from 'node:path';
28
+ import { fileURLToPath } from 'node:url';
29
+
30
+ const pathUrl = new URL(${JSON.stringify(url.href)});
31
+ const ext = ${JSON.stringify(ext)};
32
+ const file = await readFile(fileURLToPath(pathUrl));
40
33
 
34
+ const hash = crypto.createHash('md5');
35
+ hash.update(file);
36
+ const md5 = hash.digest('hex');
37
+
38
+ const data = {
39
+ name: path.basename(pathUrl.pathname),
40
+ _data: Uint8Array.from(file),
41
+ assetId: md5,
42
+ dataFormat: ext,
43
+ md5ext: md5 + "." + ext,
44
+ }
45
+
41
46
  export default data
42
47
  `;
43
48
  }