@yakcc/cli 0.5.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +214 -0
- package/LICENSE-ATOMS +38 -0
- package/README.md +76 -0
- package/dist/bin.js +10884 -0
- package/dist/bin.js.map +1 -0
- package/dist/blocks/ascii-char/impl.ts +16 -0
- package/dist/blocks/ascii-char/proof/manifest.json +8 -0
- package/dist/blocks/ascii-char/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/ascii-char/spec.yak +80 -0
- package/dist/blocks/ascii-digit-set/impl.ts +9 -0
- package/dist/blocks/ascii-digit-set/proof/manifest.json +8 -0
- package/dist/blocks/ascii-digit-set/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/ascii-digit-set/spec.yak +66 -0
- package/dist/blocks/base64-alphabet/impl.ts +98 -0
- package/dist/blocks/base64-alphabet/proof/manifest.json +8 -0
- package/dist/blocks/base64-alphabet/proof/tests.fast-check.ts +18 -0
- package/dist/blocks/base64-alphabet/spec.yak +110 -0
- package/dist/blocks/bracket/impl.ts +20 -0
- package/dist/blocks/bracket/proof/manifest.json +8 -0
- package/dist/blocks/bracket/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/bracket/spec.yak +85 -0
- package/dist/blocks/char-code/impl.ts +15 -0
- package/dist/blocks/char-code/proof/manifest.json +8 -0
- package/dist/blocks/char-code/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/char-code/spec.yak +80 -0
- package/dist/blocks/comma/impl.ts +20 -0
- package/dist/blocks/comma/proof/manifest.json +8 -0
- package/dist/blocks/comma/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/comma/spec.yak +80 -0
- package/dist/blocks/comma-separated-integers/impl.ts +85 -0
- package/dist/blocks/comma-separated-integers/proof/manifest.json +8 -0
- package/dist/blocks/comma-separated-integers/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/comma-separated-integers/spec.yak +84 -0
- package/dist/blocks/digit/impl.ts +12 -0
- package/dist/blocks/digit/proof/manifest.json +8 -0
- package/dist/blocks/digit/proof/tests.fast-check.ts +21 -0
- package/dist/blocks/digit/spec.yak +79 -0
- package/dist/blocks/digit-or-throw/impl.ts +20 -0
- package/dist/blocks/digit-or-throw/proof/manifest.json +8 -0
- package/dist/blocks/digit-or-throw/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/digit-or-throw/spec.yak +80 -0
- package/dist/blocks/empty-list-content/impl.ts +20 -0
- package/dist/blocks/empty-list-content/proof/manifest.json +8 -0
- package/dist/blocks/empty-list-content/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/empty-list-content/spec.yak +80 -0
- package/dist/blocks/eof-check/impl.ts +16 -0
- package/dist/blocks/eof-check/proof/manifest.json +8 -0
- package/dist/blocks/eof-check/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/eof-check/spec.yak +76 -0
- package/dist/blocks/integer/impl.ts +29 -0
- package/dist/blocks/integer/proof/manifest.json +8 -0
- package/dist/blocks/integer/proof/tests.fast-check.ts +21 -0
- package/dist/blocks/integer/spec.yak +84 -0
- package/dist/blocks/list-of-ints/impl.ts +168 -0
- package/dist/blocks/list-of-ints/proof/manifest.json +8 -0
- package/dist/blocks/list-of-ints/proof/tests.fast-check.ts +23 -0
- package/dist/blocks/list-of-ints/spec.yak +103 -0
- package/dist/blocks/lru-node/impl.ts +50 -0
- package/dist/blocks/lru-node/proof/manifest.json +8 -0
- package/dist/blocks/lru-node/proof/tests.fast-check.ts +16 -0
- package/dist/blocks/lru-node/spec.yak +92 -0
- package/dist/blocks/memoize/impl.ts +60 -0
- package/dist/blocks/memoize/proof/manifest.json +8 -0
- package/dist/blocks/memoize/proof/tests.fast-check.ts +15 -0
- package/dist/blocks/memoize/spec.yak +91 -0
- package/dist/blocks/non-ascii-rejector/impl.ts +14 -0
- package/dist/blocks/non-ascii-rejector/proof/manifest.json +8 -0
- package/dist/blocks/non-ascii-rejector/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/non-ascii-rejector/spec.yak +67 -0
- package/dist/blocks/nonempty-list-content/impl.ts +116 -0
- package/dist/blocks/nonempty-list-content/proof/manifest.json +8 -0
- package/dist/blocks/nonempty-list-content/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/nonempty-list-content/spec.yak +88 -0
- package/dist/blocks/optional-whitespace/impl.ts +21 -0
- package/dist/blocks/optional-whitespace/proof/manifest.json +8 -0
- package/dist/blocks/optional-whitespace/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/optional-whitespace/spec.yak +76 -0
- package/dist/blocks/peek-char/impl.ts +15 -0
- package/dist/blocks/peek-char/proof/manifest.json +8 -0
- package/dist/blocks/peek-char/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/peek-char/spec.yak +76 -0
- package/dist/blocks/position-step/impl.ts +21 -0
- package/dist/blocks/position-step/proof/manifest.json +8 -0
- package/dist/blocks/position-step/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/position-step/spec.yak +85 -0
- package/dist/blocks/queue-drain/impl.ts +74 -0
- package/dist/blocks/queue-drain/proof/manifest.json +8 -0
- package/dist/blocks/queue-drain/proof/tests.fast-check.ts +16 -0
- package/dist/blocks/queue-drain/spec.yak +119 -0
- package/dist/blocks/semver-component-parser/impl.ts +115 -0
- package/dist/blocks/semver-component-parser/proof/manifest.json +8 -0
- package/dist/blocks/semver-component-parser/proof/tests.fast-check.ts +19 -0
- package/dist/blocks/semver-component-parser/spec.yak +109 -0
- package/dist/blocks/signed-integer/impl.ts +40 -0
- package/dist/blocks/signed-integer/proof/manifest.json +8 -0
- package/dist/blocks/signed-integer/proof/tests.fast-check.ts +21 -0
- package/dist/blocks/signed-integer/spec.yak +84 -0
- package/dist/blocks/string-from-position/impl.ts +18 -0
- package/dist/blocks/string-from-position/proof/manifest.json +8 -0
- package/dist/blocks/string-from-position/proof/tests.fast-check.ts +20 -0
- package/dist/blocks/string-from-position/spec.yak +85 -0
- package/dist/blocks/timer-handle/impl.ts +66 -0
- package/dist/blocks/timer-handle/proof/manifest.json +8 -0
- package/dist/blocks/timer-handle/proof/tests.fast-check.ts +18 -0
- package/dist/blocks/timer-handle/spec.yak +67 -0
- package/dist/blocks/whitespace/impl.ts +20 -0
- package/dist/blocks/whitespace/proof/manifest.json +8 -0
- package/dist/blocks/whitespace/proof/tests.fast-check.ts +21 -0
- package/dist/blocks/whitespace/spec.yak +80 -0
- package/dist/bootstrap/expected-failures.json +4 -0
- package/dist/bootstrap/expected-roots.json +49890 -0
- package/dist/bootstrap/yakcc.registry.sqlite +0 -0
- package/dist/index.js +10826 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Property tests for the string-from-position block.
|
|
3
|
+
// These tests exercise the contract declared in ../spec.yak against the
|
|
4
|
+
// implementation in ../impl.ts.
|
|
5
|
+
//
|
|
6
|
+
// The definitive property-test corpus lives in the parent seed package's
|
|
7
|
+
// seed.test.ts (Suite 4: "property-test corpora"). This file satisfies the
|
|
8
|
+
// L0 proof/manifest.json "property_tests" artifact requirement and makes
|
|
9
|
+
// the test IDs declared in spec.yak traceable to this directory.
|
|
10
|
+
//
|
|
11
|
+
// Test IDs declared in spec.yak:
|
|
12
|
+
// strfrompos-basic
|
|
13
|
+
// strfrompos-empty
|
|
14
|
+
// strfrompos-negative-start
|
|
15
|
+
// strfrompos-start-gt-end
|
|
16
|
+
// strfrompos-end-oob
|
|
17
|
+
|
|
18
|
+
// Re-export the implementation so runners importing this artifact directly
|
|
19
|
+
// can access the block function.
|
|
20
|
+
export * from "../impl.js";
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "string-from-position",
|
|
3
|
+
"inputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "input",
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "The full input string."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "start",
|
|
11
|
+
"type": "number",
|
|
12
|
+
"description": "Zero-based start index (inclusive)."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "end",
|
|
16
|
+
"type": "number",
|
|
17
|
+
"description": "Zero-based end index (exclusive)."
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"outputs": [
|
|
21
|
+
{
|
|
22
|
+
"name": "result",
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Substring input[start..end]."
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"preconditions": [],
|
|
28
|
+
"postconditions": [],
|
|
29
|
+
"invariants": [],
|
|
30
|
+
"effects": [],
|
|
31
|
+
"level": "L0",
|
|
32
|
+
"behavior": "Return the substring of input from start (inclusive) to end (exclusive). Equivalent to input.slice(start, end) but with explicit bounds validation.",
|
|
33
|
+
"guarantees": [
|
|
34
|
+
{
|
|
35
|
+
"id": "pure",
|
|
36
|
+
"description": "Referentially transparent; no side effects."
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "length",
|
|
40
|
+
"description": "Result length equals end - start when inputs are valid."
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"errorConditions": [
|
|
44
|
+
{
|
|
45
|
+
"description": "start < 0 or end < 0.",
|
|
46
|
+
"errorType": "RangeError"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"description": "start > end.",
|
|
50
|
+
"errorType": "RangeError"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"description": "end > input.length.",
|
|
54
|
+
"errorType": "RangeError"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"nonFunctional": {
|
|
58
|
+
"time": "O(n)",
|
|
59
|
+
"space": "O(n)",
|
|
60
|
+
"purity": "pure",
|
|
61
|
+
"threadSafety": "safe"
|
|
62
|
+
},
|
|
63
|
+
"propertyTests": [
|
|
64
|
+
{
|
|
65
|
+
"id": "strfrompos-basic",
|
|
66
|
+
"description": "stringFromPosition('abcde', 1, 3) returns 'bc'"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "strfrompos-empty",
|
|
70
|
+
"description": "stringFromPosition('abc', 1, 1) returns ''"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "strfrompos-negative-start",
|
|
74
|
+
"description": "stringFromPosition('abc', -1, 2) throws RangeError"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "strfrompos-start-gt-end",
|
|
78
|
+
"description": "stringFromPosition('abc', 2, 1) throws RangeError"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "strfrompos-end-oob",
|
|
82
|
+
"description": "stringFromPosition('abc', 0, 4) throws RangeError"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// @decision DEC-SEED-TIMER-001
|
|
4
|
+
// @title timer-handle atom: setTimeout/clearTimeout closure pattern; closes #454
|
|
5
|
+
// @status accepted
|
|
6
|
+
// @rationale
|
|
7
|
+
// The debounce-with-cancel task (B4 benchmark) requires a timer-management
|
|
8
|
+
// primitive as a registry atom. The timer-handle block encapsulates the
|
|
9
|
+
// setTimeout/clearTimeout pattern as a reusable atom with a cancel handle.
|
|
10
|
+
//
|
|
11
|
+
// Design decisions:
|
|
12
|
+
// (A) CLOSURE OVER TIMER ID: The timer ID returned by setTimeout is captured
|
|
13
|
+
// in a closure and cleared on cancel(). This is the idiomatic JS pattern.
|
|
14
|
+
// Using ReturnType<typeof setTimeout> (= NodeJS.Timeout | number) avoids
|
|
15
|
+
// platform-specific typing. A null sentinel signals "already fired or
|
|
16
|
+
// cancelled" so cancel() is safely idempotent.
|
|
17
|
+
//
|
|
18
|
+
// (B) PURITY: This atom is deliberately "impure" — it schedules real side
|
|
19
|
+
// effects (timer scheduling). This is correct. The strict-subset validator
|
|
20
|
+
// does not forbid impure atoms; it only forbids top-level side effects.
|
|
21
|
+
// The setTimeout call is inside the exported function body, not at module
|
|
22
|
+
// scope, which satisfies the no-top-level-side-effects rule.
|
|
23
|
+
//
|
|
24
|
+
// (C) L0 LEVEL: Despite being impure, L0 is appropriate — this is a thin
|
|
25
|
+
// wrapper over a well-understood browser/Node built-in. The risk is
|
|
26
|
+
// lower than an algorithm that could be wrong. L1+ would require property
|
|
27
|
+
// tests beyond the current fast-check corpus.
|
|
28
|
+
//
|
|
29
|
+
// (D) SEED CORPUS METHODOLOGY: Per DEC-BENCH-METHODOLOGY-NEVER-SYNTHETIC-001,
|
|
30
|
+
// this atom represents a real implementation pattern used in production
|
|
31
|
+
// debounce/throttle implementations. It is not hallucinated or generated
|
|
32
|
+
// by an LLM for the purpose of this benchmark.
|
|
33
|
+
//
|
|
34
|
+
// Cross-reference:
|
|
35
|
+
// bench/B4-tokens/TASKS_RATIONALE.md DEC-BENCH-B4-NON-ENGAGEMENT-001 (debounce non-engagement)
|
|
36
|
+
// bench/B4-tokens/harness/mcp-server.mjs DEC-V0-B4-MCP-001 (MCP server decision)
|
|
37
|
+
// GitHub issue #454 (timer-atom-seed -- closed by this block)
|
|
38
|
+
|
|
39
|
+
/** Return type of timerHandle -- a cancellable timer reference. */
|
|
40
|
+
export interface TimerHandleResult {
|
|
41
|
+
readonly cancel: () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Schedule a one-shot timer that invokes callback after delayMs milliseconds.
|
|
46
|
+
* Returns a handle with cancel() to prevent invocation.
|
|
47
|
+
*
|
|
48
|
+
* @param callback - Called once when the timer fires.
|
|
49
|
+
* @param delayMs - Delay in milliseconds (0 = next event loop tick).
|
|
50
|
+
*/
|
|
51
|
+
export function timerHandle(callback: () => void, delayMs: number): TimerHandleResult {
|
|
52
|
+
// Capture timer id in closure. null means "fired or cancelled".
|
|
53
|
+
let id: ReturnType<typeof setTimeout> | null = setTimeout(() => {
|
|
54
|
+
id = null;
|
|
55
|
+
callback();
|
|
56
|
+
}, delayMs);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
cancel(): void {
|
|
60
|
+
if (id !== null) {
|
|
61
|
+
clearTimeout(id);
|
|
62
|
+
id = null;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Property tests for the timer-handle block.
|
|
3
|
+
// These tests exercise the contract declared in ../spec.yak against the
|
|
4
|
+
// implementation in ../impl.ts.
|
|
5
|
+
//
|
|
6
|
+
// The definitive property-test corpus lives in the parent seed package's
|
|
7
|
+
// seed.test.ts (Suite 4: "property-test corpora"). This file satisfies the
|
|
8
|
+
// L0 proof/manifest.json "property_tests" artifact requirement and makes
|
|
9
|
+
// the test IDs declared in spec.yak traceable to this directory.
|
|
10
|
+
//
|
|
11
|
+
// Test IDs declared in spec.yak:
|
|
12
|
+
// timer-fires
|
|
13
|
+
// timer-cancel-prevents-fire
|
|
14
|
+
// timer-cancel-idempotent
|
|
15
|
+
|
|
16
|
+
// Re-export the implementation so runners importing this artifact directly
|
|
17
|
+
// can access the block function.
|
|
18
|
+
export * from "../impl.js";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "timer-handle",
|
|
3
|
+
"inputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "callback",
|
|
6
|
+
"type": "() => void",
|
|
7
|
+
"description": "The function to call when the timer fires."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "delayMs",
|
|
11
|
+
"type": "number",
|
|
12
|
+
"description": "Delay in milliseconds before the callback is invoked."
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"outputs": [
|
|
16
|
+
{
|
|
17
|
+
"name": "result",
|
|
18
|
+
"type": "{ readonly cancel: () => void }",
|
|
19
|
+
"description": "Handle with a cancel() method. Calling cancel() clears the pending timer and prevents callback invocation."
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"preconditions": [],
|
|
23
|
+
"postconditions": [],
|
|
24
|
+
"invariants": [],
|
|
25
|
+
"effects": [
|
|
26
|
+
{
|
|
27
|
+
"description": "Schedules a timer via setTimeout. Cancellation via clearTimeout."
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"level": "L0",
|
|
31
|
+
"behavior": "Schedule a one-shot timer that invokes callback after delayMs milliseconds. Returns a handle object with a single cancel() method. Calling cancel() before the timer fires prevents the callback from being invoked. Calling cancel() after the timer has already fired is a no-op. Multiple cancel() calls are safe (idempotent).",
|
|
32
|
+
"guarantees": [
|
|
33
|
+
{
|
|
34
|
+
"id": "one-shot",
|
|
35
|
+
"description": "The callback is invoked at most once."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "cancel-idempotent",
|
|
39
|
+
"description": "Calling cancel() multiple times does not throw and has no additional effect after the first call."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "cancel-after-fire-noop",
|
|
43
|
+
"description": "Calling cancel() after the callback has already fired is a safe no-op."
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"errorConditions": [],
|
|
47
|
+
"nonFunctional": {
|
|
48
|
+
"time": "O(1)",
|
|
49
|
+
"space": "O(1)",
|
|
50
|
+
"purity": "impure",
|
|
51
|
+
"threadSafety": "safe"
|
|
52
|
+
},
|
|
53
|
+
"propertyTests": [
|
|
54
|
+
{
|
|
55
|
+
"id": "timer-fires",
|
|
56
|
+
"description": "timerHandle(fn, 0).cancel is a function; callback fires after delayMs elapses (fake timer)"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "timer-cancel-prevents-fire",
|
|
60
|
+
"description": "cancel() called before timer elapses prevents callback from firing"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "timer-cancel-idempotent",
|
|
64
|
+
"description": "cancel() called twice does not throw"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// @decision DEC-SEEDS-WHITESPACE-001: whitespace skipping returns a new position, not stripped text.
|
|
3
|
+
// Status: implemented (WI-006)
|
|
4
|
+
// Rationale: Position-returning parsers compose without allocating substrings.
|
|
5
|
+
// Returning the new position after whitespace is cheaper and composable with all other blocks.
|
|
6
|
+
|
|
7
|
+
export function whitespace(input: string, position: number): number {
|
|
8
|
+
if (position < 0) {
|
|
9
|
+
throw new RangeError(`Position ${position} is negative`);
|
|
10
|
+
}
|
|
11
|
+
let pos = position;
|
|
12
|
+
while (pos < input.length) {
|
|
13
|
+
const c = input[pos];
|
|
14
|
+
if (c !== " " && c !== "\t") {
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
pos++;
|
|
18
|
+
}
|
|
19
|
+
return pos;
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Property tests for the whitespace block.
|
|
3
|
+
// These tests exercise the contract declared in ../spec.yak against the
|
|
4
|
+
// implementation in ../impl.ts.
|
|
5
|
+
//
|
|
6
|
+
// The definitive property-test corpus lives in the parent seed package's
|
|
7
|
+
// seed.test.ts (Suite 4: "property-test corpora"). This file satisfies the
|
|
8
|
+
// L0 proof/manifest.json "property_tests" artifact requirement and makes
|
|
9
|
+
// the test IDs declared in spec.yak traceable to this directory.
|
|
10
|
+
//
|
|
11
|
+
// Test IDs declared in spec.yak:
|
|
12
|
+
// whitespace-spaces
|
|
13
|
+
// whitespace-tab
|
|
14
|
+
// whitespace-none
|
|
15
|
+
// whitespace-mid
|
|
16
|
+
// whitespace-negative
|
|
17
|
+
// whitespace-eof
|
|
18
|
+
|
|
19
|
+
// Re-export the implementation so runners importing this artifact directly
|
|
20
|
+
// can access the block function.
|
|
21
|
+
export * from "../impl.js";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "whitespace",
|
|
3
|
+
"inputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "input",
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "The full input string."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "position",
|
|
11
|
+
"type": "number",
|
|
12
|
+
"description": "Zero-based start position."
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"outputs": [
|
|
16
|
+
{
|
|
17
|
+
"name": "newPosition",
|
|
18
|
+
"type": "number",
|
|
19
|
+
"description": "Position after skipping all leading spaces and tabs."
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"preconditions": [],
|
|
23
|
+
"postconditions": [],
|
|
24
|
+
"invariants": [],
|
|
25
|
+
"effects": [],
|
|
26
|
+
"level": "L0",
|
|
27
|
+
"behavior": "Skip zero or more space (U+0020) or tab (U+0009) characters starting at position. Return the first position that is not a space or tab. If no whitespace is present, returns position unchanged.",
|
|
28
|
+
"guarantees": [
|
|
29
|
+
{
|
|
30
|
+
"id": "pure",
|
|
31
|
+
"description": "Referentially transparent; no side effects."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "monotonic",
|
|
35
|
+
"description": "Result is always >= position."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "idempotent",
|
|
39
|
+
"description": "whitespace(whitespace(input, p)) === whitespace(input, p)."
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"errorConditions": [
|
|
43
|
+
{
|
|
44
|
+
"description": "position < 0.",
|
|
45
|
+
"errorType": "RangeError"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"nonFunctional": {
|
|
49
|
+
"time": "O(n)",
|
|
50
|
+
"space": "O(1)",
|
|
51
|
+
"purity": "pure",
|
|
52
|
+
"threadSafety": "safe"
|
|
53
|
+
},
|
|
54
|
+
"propertyTests": [
|
|
55
|
+
{
|
|
56
|
+
"id": "whitespace-spaces",
|
|
57
|
+
"description": "whitespace(' x', 0) returns 3"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "whitespace-tab",
|
|
61
|
+
"description": "whitespace('\\tx', 0) returns 1"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "whitespace-none",
|
|
65
|
+
"description": "whitespace('abc', 0) returns 0"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "whitespace-mid",
|
|
69
|
+
"description": "whitespace('a b', 1) returns 4"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "whitespace-negative",
|
|
73
|
+
"description": "whitespace('abc', -1) throws RangeError"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "whitespace-eof",
|
|
77
|
+
"description": "whitespace('abc', 3) returns 3"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|