Skip to content

Commit f46e3a0

Browse files
authored
fix: procedures 引数参照の混乱を減らす API と docs を整理 (#39)
* fix: improve procedure argument references and docs * lock
1 parent 4f5e9b5 commit f46e3a0

4 files changed

Lines changed: 137 additions & 85 deletions

File tree

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/hikkaku/src/blocks/procedures.ts

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,10 @@ export type ProcedureProc =
2222
| ProcedureProcStringOrNumber
2323

2424
/**
25-
* Label fragment for custom block.
25+
* Creates a label fragment used in `defineProcedure`.
2626
*
27-
* Input: `text`.
28-
* Output: Scratch statement block definition that is appended to the current script stack.
29-
*
30-
* @param text See function signature for accepted input values.
31-
* @returns Scratch statement block definition that is appended to the current script stack.
27+
* @param text Static text shown in the custom block signature.
28+
* @returns A procedure fragment describing a label segment.
3229
* @example
3330
* ```ts
3431
* import { procedureLabel } from 'hikkaku/blocks'
@@ -44,13 +41,10 @@ export const procedureLabel = (text: string): ProcedureProcLabel => {
4441
}
4542

4643
/**
47-
* Boolean argument fragment.
48-
*
49-
* Input: `name`.
50-
* Output: Scratch statement block definition that is appended to the current script stack.
44+
* Creates a boolean argument fragment used in `defineProcedure`.
5145
*
52-
* @param name See function signature for accepted input values.
53-
* @returns Scratch statement block definition that is appended to the current script stack.
46+
* @param name Argument name shown in the custom block signature.
47+
* @returns A procedure fragment describing a boolean input.
5448
* @example
5549
* ```ts
5650
* import { procedureBoolean } from 'hikkaku/blocks'
@@ -68,13 +62,10 @@ export const procedureBoolean = <T extends string>(
6862
}
6963

7064
/**
71-
* String/number argument fragment.
65+
* Creates a string/number argument fragment used in `defineProcedure`.
7266
*
73-
* Input: `name`.
74-
* Output: Scratch statement block definition that is appended to the current script stack.
75-
*
76-
* @param name See function signature for accepted input values.
77-
* @returns Scratch statement block definition that is appended to the current script stack.
67+
* @param name Argument name shown in the custom block signature.
68+
* @returns A procedure fragment describing a string/number input.
7869
* @example
7970
* ```ts
8071
* import { procedureStringOrNumber } from 'hikkaku/blocks'
@@ -99,6 +90,11 @@ export interface ProcedureReferenceBase {
9990
name: string
10091
type: 'boolean' | 'stringOrNumber'
10192
id: string
93+
94+
/**
95+
* Creates a reporter block for this argument reference.
96+
*/
97+
getter(): HikkakuBlock
10298
}
10399
export interface ProcedureBooleanReference extends ProcedureReferenceBase {
104100
type: 'boolean'
@@ -145,25 +141,29 @@ type ReferencesByProcs<T extends ProcedureProc[]> = {
145141
}
146142

147143
/**
148-
* Defines a custom procedure.
149-
*
150-
* Input: `proclist`, `stack?`, `warp?`.
151-
* Output: Scratch statement block definition that is appended to the current script stack.
144+
* Defines a custom procedure and returns its definition block.
152145
*
153146
* @param proclist List of procedure parts (labels and arguments) that define the procedure's signature.
154-
* @param stack Optional callback that receives references to the procedure arguments and composes the body of the procedure.
155-
* @param warp Optional flag (default `false`). If true, the procedure will run without screen refresh until it completes.
156-
* @returns Scratch statement block definition that is appended to the current script stack.
147+
* @param stack Optional callback that composes the procedure body. Return `undefined` from this callback (implicit return is fine).
148+
* Argument references include `getter()` to create reporter blocks.
149+
* @param warp If `true`, run the procedure without screen refresh until completion.
150+
* @returns A procedure definition block with `reference` metadata for safe calls.
157151
* @example
158152
* ```ts
159-
* import { defineProcedure } from 'hikkaku/blocks'
153+
* import { defineProcedure, procedureLabel, procedureStringOrNumber, say } from 'hikkaku/blocks'
160154
*
161-
* defineProcedure(list as any, () => {}, true)
155+
* const greet = defineProcedure(
156+
* [procedureLabel('greet'), procedureStringOrNumber('name')],
157+
* ({ name }) => {
158+
* say(name.getter())
159+
* },
160+
* )
162161
* ```
163162
*/
164163
export const defineProcedure = <T extends ProcedureProc[]>(
165164
proclist: T,
166-
stack?: (references: ReferencesByProcs<T>) => void,
165+
// specify returning undefined to avoid returning value in procedure body
166+
stack?: (references: ReferencesByProcs<T>) => undefined,
167167
/**
168168
* If true, the procedure will run without screen refresh until it completes.
169169
* This can make the procedure run faster, but the screen will not update until the procedure is done.
@@ -229,15 +229,33 @@ export const defineProcedure = <T extends ProcedureProc[]>(
229229
})
230230
const references = Object.fromEntries(
231231
argumentProcs.map((proc, index) => {
232-
return [
233-
proc.name,
234-
{
235-
isProcedureArgument: true,
232+
const argumentid = argumentids[index]
233+
if (!argumentid) {
234+
throw new Error('Argument ID not found')
235+
}
236+
let reference: ProcedureReference
237+
if (proc.type === 'boolean') {
238+
const boolReference: ProcedureBooleanReference = {
239+
isProcedureArgument: true as const,
236240
name: proc.name,
237241
type: proc.type,
238-
id: argumentids[index],
239-
} as ProcedureReference,
240-
]
242+
id: argumentid,
243+
getter: () => argumentReporterBoolean(boolReference),
244+
}
245+
reference = boolReference
246+
} else if (proc.type === 'stringOrNumber') {
247+
const strNumReference: ProcedureStringOrNumberReference = {
248+
isProcedureArgument: true as const,
249+
name: proc.name,
250+
type: proc.type,
251+
id: argumentid,
252+
getter: () => argumentReporterStringNumber(strNumReference),
253+
}
254+
reference = strNumReference
255+
} else {
256+
throw new Error('Unknown procedure proc type')
257+
}
258+
return [proc.name, reference]
241259
}),
242260
) as ReferencesByProcs<T>
243261

@@ -263,20 +281,28 @@ export const defineProcedure = <T extends ProcedureProc[]>(
263281

264282
/**
265283
* Calls a custom procedure.
284+
* Supports three call styles:
285+
* 1) Low-level: `callProcedure(proccode, argumentIds, inputs?, warp?)`
286+
* 2) Reference + array: `callProcedure(definitionOrReference, [{ reference, value }], warp?)`
287+
* 3) Reference + object: `callProcedure(definitionOrReference, { [argumentId]: value }, warp?)`
266288
*
267-
* Input: either (`proccode`, `argumentIds`, `inputs`, `warp`) or (`definitionOrReference`, `inputsByReference`, `warp`).
268-
* Output: Scratch statement block definition that is appended to the current script stack.
269-
*
270-
* @param proccodeOrReference See function signature for accepted input values.
271-
* @param argumentIdsOrInputs See function signature for accepted input values.
272-
* @param inputsOrWarp See function signature for accepted input values.
273-
* @param warp See function signature for accepted input values.
274-
* @returns Scratch statement block definition that is appended to the current script stack.
289+
* @param proccodeOrReference Procedure code or the definition/reference returned by `defineProcedure`.
290+
* @param argumentIdsOrInputs Argument IDs for low-level calls, or argument inputs for reference-based calls.
291+
* @param inputsOrWarp Optional low-level inputs object or a warp override for reference-based calls.
292+
* @param warp Warp flag used by low-level calls.
293+
* @returns A `procedures_call` block.
275294
* @example
276295
* ```ts
277-
* import { callProcedure } from 'hikkaku/blocks'
296+
* import { callProcedure, defineProcedure, procedureLabel, procedureStringOrNumber } from 'hikkaku/blocks'
297+
*
298+
* const greet = defineProcedure([
299+
* procedureLabel('greet'),
300+
* procedureStringOrNumber('name'),
301+
* ])
278302
*
279-
* callProcedure([] as any, undefined as any, undefined as any, undefined as any)
303+
* callProcedure(greet, [
304+
* { reference: greet.reference.arguments.name, value: 'Ada' },
305+
* ])
280306
* ```
281307
*/
282308
export const callProcedure = (
@@ -351,13 +377,10 @@ export const callProcedure = (
351377
}
352378

353379
/**
354-
* Reporter for string/number argument.
380+
* Creates a reporter block for a string/number procedure argument.
355381
*
356-
* Input: `reference`.
357-
* Output: Scratch reporter block definition that can be used as an input value in other blocks.
358-
*
359-
* @param reference See function signature for accepted input values.
360-
* @returns Scratch reporter block definition that can be used as an input value in other blocks.
382+
* @param reference String/number argument reference from `defineProcedure`.
383+
* @returns A reporter block that reads the current argument value.
361384
* @example
362385
* ```ts
363386
* import { argumentReporterStringNumber } from 'hikkaku/blocks'
@@ -376,13 +399,10 @@ export const argumentReporterStringNumber = (
376399
}
377400

378401
/**
379-
* Reporter for boolean argument.
380-
*
381-
* Input: `reference`.
382-
* Output: Scratch reporter block definition that can be used as an input value in other blocks.
402+
* Creates a reporter block for a boolean procedure argument.
383403
*
384-
* @param reference See function signature for accepted input values.
385-
* @returns Scratch reporter block definition that can be used as an input value in other blocks.
404+
* @param reference Boolean argument reference from `defineProcedure`.
405+
* @returns A reporter block that reads the current argument value.
386406
* @example
387407
* ```ts
388408
* import { argumentReporterBoolean } from 'hikkaku/blocks'

packages/skill/hikkaku/rules/blocks/procedures.md

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ impact: HIGH
77

88
## procedureLabel(text)
99

10-
Label fragment for custom block.
10+
Create a static label fragment for a custom block signature.
1111

1212
Input: `text`.
1313

14-
Output: Scratch statement block definition that is appended to the current script stack.
14+
Output: Procedure signature fragment.
1515

1616
* `text: See function signature for accepted input values`
1717

@@ -24,11 +24,11 @@ procedureLabel('Hello')
2424

2525
## procedureBoolean(name)
2626

27-
Boolean argument fragment.
27+
Create a boolean argument fragment for a custom block signature.
2828

2929
Input: `name`.
3030

31-
Output: Scratch statement block definition that is appended to the current script stack.
31+
Output: Procedure signature fragment.
3232

3333
* `name: See function signature for accepted input values`
3434

@@ -41,11 +41,11 @@ procedureBoolean(undefined as any)
4141

4242
## procedureStringOrNumber(name)
4343

44-
String/number argument fragment.
44+
Create a string/number argument fragment for a custom block signature.
4545

4646
Input: `name`.
4747

48-
Output: Scratch statement block definition that is appended to the current script stack.
48+
Output: Procedure signature fragment.
4949

5050
* `name: See function signature for accepted input values`
5151

@@ -56,24 +56,34 @@ import { procedureStringOrNumber } from 'hikkaku/blocks'
5656
procedureStringOrNumber(undefined as any)
5757
```
5858

59-
## defineProcedure(proclist, stack)
59+
## defineProcedure(proclist, stack?, warp?)
6060

61-
Defines a custom procedure.
61+
Define a custom procedure from signature fragments.
6262

63-
Input: `proclist`, `stack`, `the`, `but`.
63+
Input: `proclist`, optional `stack`, optional `warp`.
6464

6565
Output: Scratch statement block definition that is appended to the current script stack.
6666

6767
* `proclist: T` - ProcedureProc[]
68-
* `stack: (references) => void Optional`
69-
* `the: Input value used by this block`
70-
* `but: Input value used by this block`
68+
* `stack: (references) => undefined Optional`
69+
* `warp: boolean Optional. If true, run without screen refresh until completion.`
70+
* `references.*.getter(): HikkakuBlock` is available inside `stack` to read arguments.
7171

7272
Example:
7373
```ts
74-
import { defineProcedure } from 'hikkaku/blocks'
75-
76-
defineProcedure(list as any, () => {}, undefined as any, undefined as any)
74+
import {
75+
defineProcedure,
76+
procedureLabel,
77+
procedureStringOrNumber,
78+
say,
79+
} from 'hikkaku/blocks'
80+
81+
defineProcedure(
82+
[procedureLabel('greet'), procedureStringOrNumber('name')],
83+
({ name }) => {
84+
say(name.getter())
85+
},
86+
)
7787
```
7888

7989
## callProcedure(...)
@@ -84,16 +94,30 @@ Input: either (`proccode`, `argumentIds`, `inputs`, `warp`) or (`definitionOrRef
8494

8595
Output: Scratch statement block definition that is appended to the current script stack.
8696

87-
* `proccodeOrReference: See function signature for accepted input values`
88-
* `argumentIdsOrInputs: See function signature for accepted input values`
89-
* `inputsOrWarp: See function signature for accepted input values`
90-
* `warp: See function signature for accepted input values`
97+
* Low-level style:
98+
`callProcedure(proccode, argumentIds, inputs?, warp?)`
99+
* Reference style (recommended):
100+
`callProcedure(definitionOrReference, [{ reference, value }], warp?)`
101+
* Reference style with object:
102+
`callProcedure(definitionOrReference, { [argumentId]: value }, warp?)`
91103

92104
Example:
93105
```ts
94-
import { callProcedure } from 'hikkaku/blocks'
95-
96-
callProcedure(reference as any, [] as any, undefined as any)
106+
import {
107+
callProcedure,
108+
defineProcedure,
109+
procedureLabel,
110+
procedureStringOrNumber,
111+
} from 'hikkaku/blocks'
112+
113+
const greet = defineProcedure([
114+
procedureLabel('greet'),
115+
procedureStringOrNumber('name'),
116+
])
117+
118+
callProcedure(greet, [
119+
{ reference: greet.reference.arguments.name, value: 'Ada' },
120+
])
97121
```
98122

99123
## argumentReporterStringNumber(reference)

packages/skill/hikkaku/rules/custom-blocks.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ Custom blocks are defined with `defineProcedure` using a list of procedure parts
1212
* `procedureStringOrNumber(name)` for string/number inputs
1313

1414
Inside the procedure body, use argument reporter blocks to read inputs.
15+
`defineProcedure` argument references also provide `.getter()` as a shorthand.
1516

1617
## Define a Procedure
1718

1819
```ts
1920
import { Project } from 'hikkaku'
2021
import {
21-
argumentReporterBoolean,
22-
argumentReporterStringNumber,
2322
defineProcedure,
2423
procedureBoolean,
2524
procedureLabel,
@@ -41,8 +40,8 @@ sprite.run(() => {
4140
procedureBoolean('excited'),
4241
],
4342
({ name, excited }) => {
44-
ifThen(argumentReporterBoolean(excited), () => {
45-
say(argumentReporterStringNumber(name))
43+
ifThen(excited.getter(), () => {
44+
say(name.getter())
4645
})
4746
},
4847
)
@@ -70,5 +69,13 @@ callProcedure(greet, [
7069
])
7170
```
7271

73-
Low-level invocation with explicit `proccode` / `argumentIds` still works for
74-
interop scenarios, but prefer references when possible to avoid mismatches.
72+
You can also pass an object keyed by argument ID:
73+
74+
```ts
75+
callProcedure(greet, {
76+
[greet.reference.arguments.name.id]: 'Ada',
77+
[greet.reference.arguments.excited.id]: true,
78+
})
79+
```
80+
81+
Low-level invocation with explicit `proccode` / `argumentIds` still works for interop scenarios, but prefer references when possible to avoid mismatches.

0 commit comments

Comments
 (0)