typia 15.2.1 → 15.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/lib/internal/_stringLengthGte.d.ts +7 -3
- package/lib/internal/_stringLengthGte.js +9 -3
- package/lib/internal/_stringLengthGte.js.map +1 -1
- package/lib/internal/_stringLengthGte.mjs +8 -3
- package/lib/internal/_stringLengthGte.mjs.map +1 -1
- package/lib/internal/_stringLengthLte.d.ts +7 -3
- package/lib/internal/_stringLengthLte.js +9 -3
- package/lib/internal/_stringLengthLte.js.map +1 -1
- package/lib/internal/_stringLengthLte.mjs +8 -3
- package/lib/internal/_stringLengthLte.mjs.map +1 -1
- package/native/core/context/ImportProgrammer.go +19 -9
- package/native/core/context/ImportProgrammerPattern.go +36 -0
- package/native/core/programmers/iterate/check_string.go +41 -5
- package/native/core/programmers/iterate/check_string_pattern_test.go +91 -0
- package/native/core/programmers/iterate/check_template.go +4 -4
- package/package.json +3 -3
- package/src/internal/_stringLengthGte.ts +8 -3
- package/src/internal/_stringLengthLte.ts +8 -3
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test whether a string has at least the given number of code points.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Twice the requested minimum in UTF-16 units guarantees enough code points.
|
|
5
|
+
* Other inputs are counted only until the minimum is reached.
|
|
6
6
|
*
|
|
7
|
-
* @evidence contracts/common.md#principled-implementation
|
|
7
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies at most two UTF-16 units, so code-unit length at least twice the minimum proves the code-point bound. Otherwise iteration stops at the minimum; nonpositive minima remain true and NaN remains false.
|
|
8
8
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
9
9
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
10
10
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
11
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit lower bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
12
|
+
*
|
|
13
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
14
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
11
15
|
*/
|
|
12
16
|
export declare const _stringLengthGte: (value: string, length: number) => boolean;
|
|
@@ -4,15 +4,21 @@ exports._stringLengthGte = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* Test whether a string has at least the given number of code points.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Twice the requested minimum in UTF-16 units guarantees enough code points.
|
|
8
|
+
* Other inputs are counted only until the minimum is reached.
|
|
9
9
|
*
|
|
10
|
-
* @evidence contracts/common.md#principled-implementation
|
|
10
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies at most two UTF-16 units, so code-unit length at least twice the minimum proves the code-point bound. Otherwise iteration stops at the minimum; nonpositive minima remain true and NaN remains false.
|
|
11
11
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
12
12
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
13
13
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
14
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit lower bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
15
|
+
*
|
|
16
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
17
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
14
18
|
*/
|
|
15
19
|
const _stringLengthGte = (value, length) => {
|
|
20
|
+
if (value.length >= length * 2)
|
|
21
|
+
return true;
|
|
16
22
|
let count = 0;
|
|
17
23
|
if (length <= count)
|
|
18
24
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_stringLengthGte.js","sources":["../../src/internal/_stringLengthGte.ts"],"names":[],"mappings":";;;AAAA
|
|
1
|
+
{"version":3,"file":"_stringLengthGte.js","sources":["../../src/internal/_stringLengthGte.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;GAcG;AACI,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,MAAc,EAAW,EAAE;IACzE,IAAI,KAAK,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,KAAK,GAAW,CAAC,CAAC;IACtB,IAAI,MAAM,IAAI,KAAK;QAAE,OAAO,IAAI,CAAC;IACjC,KAAK,MAAM,GAAG,IAAI,KAAK;QAAE,IAAI,MAAM,IAAI,EAAE,KAAK;YAAE,OAAO,IAAI,CAAC;IAC5D,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AANW,QAAA,gBAAgB,GAAhB,gBAAgB,CAM3B"}
|
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Test whether a string has at least the given number of code points.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Twice the requested minimum in UTF-16 units guarantees enough code points.
|
|
6
|
+
* Other inputs are counted only until the minimum is reached.
|
|
7
7
|
*
|
|
8
|
-
* @evidence contracts/common.md#principled-implementation
|
|
8
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies at most two UTF-16 units, so code-unit length at least twice the minimum proves the code-point bound. Otherwise iteration stops at the minimum; nonpositive minima remain true and NaN remains false.
|
|
9
9
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
10
10
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
11
11
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
12
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit lower bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
13
|
+
*
|
|
14
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
15
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
12
16
|
*/
|
|
13
17
|
const _stringLengthGte = (value, length) => {
|
|
18
|
+
if (value.length >= length * 2) return true;
|
|
14
19
|
let count = 0;
|
|
15
20
|
if (length <= count) return true;
|
|
16
21
|
for (const _ch of value) if (length <= ++count) return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_stringLengthGte.mjs","names":[],"sources":["../../src/internal/_stringLengthGte.ts"],"sourcesContent":["/**\n * Test whether a string has at least the given number of code points.\n *\n *
|
|
1
|
+
{"version":3,"file":"_stringLengthGte.mjs","names":[],"sources":["../../src/internal/_stringLengthGte.ts"],"sourcesContent":["/**\n * Test whether a string has at least the given number of code points.\n *\n * Twice the requested minimum in UTF-16 units guarantees enough code points.\n * Other inputs are counted only until the minimum is reached.\n *\n * @evidence contracts/common.md#principled-implementation Each code point occupies at most two UTF-16 units, so code-unit length at least twice the minimum proves the code-point bound. Otherwise iteration stops at the minimum; nonpositive minima remain true and NaN remains false.\n * @evidence contracts/common.md#clear-and-simple-design One loop with an early return.\n * @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.\n * @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.\n * @evidence contracts/performance.md#efficient-algorithms The code-unit lower bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.\n *\n * @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.\n * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.\n */\nexport const _stringLengthGte = (value: string, length: number): boolean => {\n if (value.length >= length * 2) return true;\n let count: number = 0;\n if (length <= count) return true;\n for (const _ch of value) if (length <= ++count) return true;\n return false;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,oBAAoB,OAAe,WAA4B;CAC1E,IAAI,MAAM,UAAU,SAAS,GAAG,OAAO;CACvC,IAAI,QAAgB;CACpB,IAAI,UAAU,OAAO,OAAO;CAC5B,KAAK,MAAM,OAAO,OAAO,IAAI,UAAU,EAAE,OAAO,OAAO;CACvD,OAAO;AACT"}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test whether a string has at most the given number of code points.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* UTF-16 length decides inputs whose code units already fit the bound. Other
|
|
5
|
+
* inputs are counted only until the maximum is exceeded.
|
|
6
6
|
*
|
|
7
|
-
* @evidence contracts/common.md#principled-implementation
|
|
7
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies one or two UTF-16 units, so code-unit length at most the maximum proves the code-point bound. Otherwise iteration stops once the maximum is exceeded; negative and NaN maxima remain false.
|
|
8
8
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
9
9
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
10
10
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
11
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit upper bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
12
|
+
*
|
|
13
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
14
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
11
15
|
*/
|
|
12
16
|
export declare const _stringLengthLte: (value: string, length: number) => boolean;
|
|
@@ -4,15 +4,21 @@ exports._stringLengthLte = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* Test whether a string has at most the given number of code points.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* UTF-16 length decides inputs whose code units already fit the bound. Other
|
|
8
|
+
* inputs are counted only until the maximum is exceeded.
|
|
9
9
|
*
|
|
10
|
-
* @evidence contracts/common.md#principled-implementation
|
|
10
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies one or two UTF-16 units, so code-unit length at most the maximum proves the code-point bound. Otherwise iteration stops once the maximum is exceeded; negative and NaN maxima remain false.
|
|
11
11
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
12
12
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
13
13
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
14
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit upper bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
15
|
+
*
|
|
16
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
17
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
14
18
|
*/
|
|
15
19
|
const _stringLengthLte = (value, length) => {
|
|
20
|
+
if (value.length <= length)
|
|
21
|
+
return true;
|
|
16
22
|
let count = 0;
|
|
17
23
|
if (!(count <= length))
|
|
18
24
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_stringLengthLte.js","sources":["../../src/internal/_stringLengthLte.ts"],"names":[],"mappings":";;;AAAA
|
|
1
|
+
{"version":3,"file":"_stringLengthLte.js","sources":["../../src/internal/_stringLengthLte.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;GAcG;AACI,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,MAAc,EAAW,EAAE;IACzE,IAAI,KAAK,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,KAAK,GAAW,CAAC,CAAC;IACtB,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,KAAK;QAAE,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;IAChE,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AANW,QAAA,gBAAgB,GAAhB,gBAAgB,CAM3B"}
|
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Test whether a string has at most the given number of code points.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* UTF-16 length decides inputs whose code units already fit the bound. Other
|
|
6
|
+
* inputs are counted only until the maximum is exceeded.
|
|
7
7
|
*
|
|
8
|
-
* @evidence contracts/common.md#principled-implementation
|
|
8
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies one or two UTF-16 units, so code-unit length at most the maximum proves the code-point bound. Otherwise iteration stops once the maximum is exceeded; negative and NaN maxima remain false.
|
|
9
9
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
10
10
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
11
11
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
12
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit upper bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
13
|
+
*
|
|
14
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
15
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
12
16
|
*/
|
|
13
17
|
const _stringLengthLte = (value, length) => {
|
|
18
|
+
if (value.length <= length) return true;
|
|
14
19
|
let count = 0;
|
|
15
20
|
if (!(count <= length)) return false;
|
|
16
21
|
for (const _ch of value) if (!(++count <= length)) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_stringLengthLte.mjs","names":[],"sources":["../../src/internal/_stringLengthLte.ts"],"sourcesContent":["/**\n * Test whether a string has at most the given number of code points.\n *\n *
|
|
1
|
+
{"version":3,"file":"_stringLengthLte.mjs","names":[],"sources":["../../src/internal/_stringLengthLte.ts"],"sourcesContent":["/**\n * Test whether a string has at most the given number of code points.\n *\n * UTF-16 length decides inputs whose code units already fit the bound. Other\n * inputs are counted only until the maximum is exceeded.\n *\n * @evidence contracts/common.md#principled-implementation Each code point occupies one or two UTF-16 units, so code-unit length at most the maximum proves the code-point bound. Otherwise iteration stops once the maximum is exceeded; negative and NaN maxima remain false.\n * @evidence contracts/common.md#clear-and-simple-design One loop with an early return.\n * @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.\n * @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.\n * @evidence contracts/performance.md#efficient-algorithms The code-unit upper bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.\n *\n * @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.\n * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.\n */\nexport const _stringLengthLte = (value: string, length: number): boolean => {\n if (value.length <= length) return true;\n let count: number = 0;\n if (!(count <= length)) return false;\n for (const _ch of value) if (!(++count <= length)) return false;\n return true;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,oBAAoB,OAAe,WAA4B;CAC1E,IAAI,MAAM,UAAU,QAAQ,OAAO;CACnC,IAAI,QAAgB;CACpB,IAAI,EAAE,SAAS,SAAS,OAAO;CAC/B,KAAK,MAAM,OAAO,OAAO,IAAI,EAAE,EAAE,SAAS,SAAS,OAAO;CAC1D,OAAO;AACT"}
|
|
@@ -9,7 +9,7 @@ import (
|
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
// ImportProgrammer collects the imports that generated code needs and builds the
|
|
12
|
-
// references to them.
|
|
12
|
+
// references to them. It also collects lazily initialized pattern slots.
|
|
13
13
|
//
|
|
14
14
|
// In its default mode references are plain identifiers and ToStatements writes
|
|
15
15
|
// named, default and namespace imports. After SetEmitContext, every file becomes
|
|
@@ -17,14 +17,16 @@ import (
|
|
|
17
17
|
// name, so the compiler's module transform binds them. It is not safe for
|
|
18
18
|
// concurrent use.
|
|
19
19
|
//
|
|
20
|
-
// @evidence contracts/common.md#principled-implementation Requests are recorded per file with their insertion order and each file is emitted once, either as named, default and namespace imports in the legacy mode or as one namespace import with member accesses on a generated unique name in emit-context mode, so the compiler's module transform decides the final CommonJS aliasing. Internal helpers
|
|
20
|
+
// @evidence contracts/common.md#principled-implementation Requests are recorded per file with their insertion order and each file is emitted once, either as named, default and namespace imports in the legacy mode or as one namespace import with member accesses on a generated unique name in emit-context mode, so the compiler's module transform decides the final CommonJS aliasing. Internal helpers use typia's internal folder. Static pattern sources share file-local lazy slots only when the compiler can allocate collision-safe names.
|
|
21
21
|
// @evidence contracts/common.md#clear-and-simple-design One type with private asset records and helpers for module identifiers, ranks, member construction and aliases; the two emission modes share the recording code.
|
|
22
22
|
// @evidence contracts/common.md#prohibited-implementation-shortcuts Ordering uses a rank table over internal helper names and first use, not special-casing of a consumer. It is not safe for concurrent use, which the doc states.
|
|
23
23
|
// @evidence contracts/common.md#meaningful-documentation The doc describes both modes and the concurrency limit, and the field comment explains emit mode.
|
|
24
24
|
type ImportProgrammer struct {
|
|
25
|
-
assets_
|
|
26
|
-
order_
|
|
27
|
-
options_
|
|
25
|
+
assets_ map[string]*importProgrammer_asset
|
|
26
|
+
order_ []string
|
|
27
|
+
options_ ImportProgrammer_IOptions
|
|
28
|
+
patterns_ map[string]*shimast.Node
|
|
29
|
+
patternOrder_ []string
|
|
28
30
|
// emit_ switches import emission to AST-integration mode. When set, imports
|
|
29
31
|
// become namespace imports created by emit_.Factory, and every reference is a
|
|
30
32
|
// member access on a cloned unique name so tsgo's module transform owns the
|
|
@@ -332,14 +334,15 @@ func (p *ImportProgrammer) GetInternalText(name string) string {
|
|
|
332
334
|
return alias
|
|
333
335
|
}
|
|
334
336
|
|
|
335
|
-
// ToStatements returns the
|
|
336
|
-
// ordered by rank, with
|
|
337
|
-
// use within a rank.
|
|
337
|
+
// ToStatements returns the requested imports followed by lazy pattern slots.
|
|
338
|
+
// Import files are ordered by rank, with internal helpers grouped by kind, and
|
|
339
|
+
// by first use within a rank.
|
|
338
340
|
//
|
|
339
|
-
// @evidence contracts/common.md#principled-implementation Files are stable-sorted by a rank that groups internal helpers by kind and keeps insertion order within a rank, then emitted as one namespace import with optional constants in emit mode, or as namespace, default and named imports in the legacy mode, where a type-only default gets the type keyword.
|
|
341
|
+
// @evidence contracts/common.md#principled-implementation Files are stable-sorted by a rank that groups internal helpers by kind and keeps insertion order within a rank, then emitted as one namespace import with optional constants in emit mode, or as namespace, default and named imports in the legacy mode, where a type-only default gets the type keyword. Pattern slots follow as uninitialized var declarations in first-use order.
|
|
340
342
|
// @evidence contracts/common.md#clear-and-simple-design One method with the two mode branches and the rank helper.
|
|
341
343
|
// @evidence contracts/common.md#prohibited-implementation-shortcuts The ranking is a fixed table and the order is deterministic.
|
|
342
344
|
// @evidence contracts/common.md#meaningful-documentation The doc states the order and the two forms.
|
|
345
|
+
// @evidence contracts/performance.md#efficient-algorithms Sorting A import assets costs O(A log A); pattern declarations follow in one O(P) first-use walk. Output allocation is proportional to the declarations that must be emitted, without scanning authored input strings or allocating a runtime lookup table.
|
|
343
346
|
func (p *ImportProgrammer) ToStatements() []*shimast.Node {
|
|
344
347
|
f := NodeFactoryOf(p.emit_)
|
|
345
348
|
statements := []*shimast.Node{}
|
|
@@ -448,6 +451,13 @@ func (p *ImportProgrammer) ToStatements() []*shimast.Node {
|
|
|
448
451
|
))
|
|
449
452
|
}
|
|
450
453
|
}
|
|
454
|
+
for _, source := range p.patternOrder_ {
|
|
455
|
+
statements = append(statements, f.NewVariableStatement(nil,
|
|
456
|
+
f.NewVariableDeclarationList(f.NewNodeList([]*shimast.Node{
|
|
457
|
+
f.NewVariableDeclaration(p.patterns_[source].Clone(f), nil, nil, nil),
|
|
458
|
+
}), shimast.NodeFlagsNone),
|
|
459
|
+
))
|
|
460
|
+
}
|
|
451
461
|
return statements
|
|
452
462
|
}
|
|
453
463
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package context
|
|
2
|
+
|
|
3
|
+
import shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
4
|
+
|
|
5
|
+
// Pattern reuses a flag-free RegExp after its first successful construction.
|
|
6
|
+
// The constructor stays at the check site, so invalid sources still throw only
|
|
7
|
+
// when the string check is reached. File-scoped var slots also work when a
|
|
8
|
+
// circular import invokes a hoisted function before this module's body runs.
|
|
9
|
+
// Without an emit context, retain the constructor: the standalone factory has
|
|
10
|
+
// no compiler name-collision information for a file-scoped generated slot.
|
|
11
|
+
//
|
|
12
|
+
// @evidence contracts/common.md#principled-implementation A flag-free RegExp test does not advance lastIndex, so checks with the same source can share the compiled object. Nullish assignment records only successful construction and preserves lazy SyntaxError timing. Uninitialized var declarations are hoisted and do not reset an early circular-import initialization. The compiler supplies collision-safe names; without that capability, the original constructor is returned without introducing a binding.
|
|
13
|
+
// @evidence contracts/common.md#clear-and-simple-design The file's existing statement collector owns one generated slot per distinct source and returns its lazy initialization expression.
|
|
14
|
+
// @evidence contracts/common.md#prohibited-implementation-shortcuts Only the caller's verified static flag-free pattern expressions use this method; arbitrary custom validators remain untouched.
|
|
15
|
+
// @evidence contracts/common.md#meaningful-documentation The comment explains reuse, lazy construction and the var declaration.
|
|
16
|
+
// @evidence contracts/performance.md#efficient-algorithms Source lookup uses the file's map and each generated check performs one nullish guard instead of constructing another RegExp.
|
|
17
|
+
// @evidence contracts/performance.md#reuse-equivalent-work Standard JavaScript RegExp objects with identical source and no flags have equivalent stateless test behavior; the importer is scoped to one transformed source file and not shared between programs.
|
|
18
|
+
// @evidence contracts/performance.md#bound-retention-and-release-resources Generation retains one slot per distinct authored pattern until the file transform ends; runtime retains at most one RegExp per slot for the containing module's lifetime, with no runtime-keyed cache.
|
|
19
|
+
func (p *ImportProgrammer) Pattern(source string, constructor *shimast.Node) *shimast.Node {
|
|
20
|
+
if p.emit_ == nil {
|
|
21
|
+
return constructor
|
|
22
|
+
}
|
|
23
|
+
f := NodeFactoryOf(p.emit_)
|
|
24
|
+
name := p.patterns_[source]
|
|
25
|
+
if name == nil {
|
|
26
|
+
if p.patterns_ == nil {
|
|
27
|
+
p.patterns_ = map[string]*shimast.Node{}
|
|
28
|
+
}
|
|
29
|
+
name = p.emit_.Factory.NewUniqueName("__" + p.options_.InternalPrefix + "pattern")
|
|
30
|
+
p.patterns_[source] = name
|
|
31
|
+
p.patternOrder_ = append(p.patternOrder_, source)
|
|
32
|
+
}
|
|
33
|
+
return f.NewParenthesizedExpression(f.NewBinaryExpression(nil,
|
|
34
|
+
name.Clone(f), nil, f.NewToken(shimast.KindQuestionQuestionEqualsToken), constructor,
|
|
35
|
+
))
|
|
36
|
+
}
|
|
@@ -24,7 +24,7 @@ type Check_stringProps struct {
|
|
|
24
24
|
// Check_string builds the check entry of a string atomic: a `typeof input ===
|
|
25
25
|
// "string"` guard plus the atomic's type-tag conditions.
|
|
26
26
|
//
|
|
27
|
-
// @evidence contracts/common.md#principled-implementation It builds the
|
|
27
|
+
// @evidence contracts/common.md#principled-implementation It builds the string guard and type-tag conditions. A static flag-free RegExp(source).test(input) whose source agrees with pattern metadata uses the file's lazy reusable slot; other validation expressions retain their authored AST.
|
|
28
28
|
// @evidence contracts/common.md#clear-and-simple-design One exported function; the pieces that repeat live in private helpers of the same file.
|
|
29
29
|
// @evidence contracts/common.md#prohibited-implementation-shortcuts Its inputs are its arguments and the context they carry, and it keeps no state of its own.
|
|
30
30
|
// @evidence contracts/common.md#meaningful-documentation The doc states what it builds.
|
|
@@ -50,9 +50,10 @@ func check_string_type_tags(props Check_stringProps) [][]nativehelpers.ICheckEnt
|
|
|
50
50
|
tags := check_string_filter_validate(row)
|
|
51
51
|
conditions := make([]nativehelpers.ICheckEntry_ICondition, 0, len(tags))
|
|
52
52
|
for _, tag := range tags {
|
|
53
|
+
expression := check_string_transpile(props.Context, tag)(props.Input)
|
|
53
54
|
conditions = append(conditions, nativehelpers.ICheckEntry_ICondition{
|
|
54
55
|
Expected: "string & " + tag.Name,
|
|
55
|
-
Expression:
|
|
56
|
+
Expression: expression,
|
|
56
57
|
})
|
|
57
58
|
}
|
|
58
59
|
for _, tag := range row {
|
|
@@ -68,6 +69,36 @@ func check_string_type_tags(props Check_stringProps) [][]nativehelpers.ICheckEnt
|
|
|
68
69
|
return output
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
// Recognize only the standard flag-free RegExp(source).test(input) form. A
|
|
73
|
+
// custom pattern-kind tag may supply arbitrary validation code or flags, and
|
|
74
|
+
// must retain that code and its state rather than being lowered from value alone.
|
|
75
|
+
func check_string_pattern(context nativecontext.ITypiaContext, tag nativemetadata.IMetadataTypeTag, input *shimast.Expression, expression *shimast.Node) *shimast.Node {
|
|
76
|
+
source, ok := tag.Value.(string)
|
|
77
|
+
if !ok || tag.Kind != "pattern" || context.Importer == nil || expression.Kind != shimast.KindCallExpression {
|
|
78
|
+
return expression
|
|
79
|
+
}
|
|
80
|
+
test := expression.AsCallExpression()
|
|
81
|
+
if test.Arguments == nil || len(test.Arguments.Nodes) != 1 || test.Arguments.Nodes[0] != input || test.Expression.Kind != shimast.KindPropertyAccessExpression {
|
|
82
|
+
return expression
|
|
83
|
+
}
|
|
84
|
+
member := test.Expression.AsPropertyAccessExpression()
|
|
85
|
+
if member.Name().Text() != "test" || member.Expression.Kind != shimast.KindCallExpression {
|
|
86
|
+
return expression
|
|
87
|
+
}
|
|
88
|
+
constructor := member.Expression.AsCallExpression()
|
|
89
|
+
if constructor.Expression.Kind != shimast.KindIdentifier || constructor.Expression.Text() != "RegExp" || constructor.Arguments == nil || len(constructor.Arguments.Nodes) != 1 {
|
|
90
|
+
return expression
|
|
91
|
+
}
|
|
92
|
+
argument := constructor.Arguments.Nodes[0]
|
|
93
|
+
if !shimast.IsStringLiteral(argument) || argument.Text() != source {
|
|
94
|
+
return expression
|
|
95
|
+
}
|
|
96
|
+
f := nativecontext.NodeFactoryOf(context.Emit)
|
|
97
|
+
return f.NewCallExpression(f.NewPropertyAccessExpression(
|
|
98
|
+
context.Importer.Pattern(source, member.Expression), nil, f.NewIdentifier("test"), shimast.NodeFlagsNone,
|
|
99
|
+
), nil, nil, test.Arguments, shimast.NodeFlagsNone)
|
|
100
|
+
}
|
|
101
|
+
|
|
71
102
|
func check_string_filter_validate(row []nativemetadata.IMetadataTypeTag) []nativemetadata.IMetadataTypeTag {
|
|
72
103
|
tags := []nativemetadata.IMetadataTypeTag{}
|
|
73
104
|
for _, tag := range row {
|
|
@@ -78,13 +109,18 @@ func check_string_filter_validate(row []nativemetadata.IMetadataTypeTag) []nativ
|
|
|
78
109
|
return tags
|
|
79
110
|
}
|
|
80
111
|
|
|
81
|
-
|
|
112
|
+
// The same lowering serves ordinary strings, whole-template tags and captured
|
|
113
|
+
// placeholder/backtracking checks, so every standard Pattern shares the cache.
|
|
114
|
+
func check_string_transpile(context nativecontext.ITypiaContext, tag nativemetadata.IMetadataTypeTag) func(input *shimast.Expression) *shimast.Node {
|
|
82
115
|
var importer nativefactories.ExpressionFactory_Importer
|
|
83
116
|
if v := context.Importer; v != nil {
|
|
84
117
|
importer = v
|
|
85
118
|
}
|
|
86
|
-
|
|
119
|
+
transpile := nativefactories.ExpressionFactory.Transpile(nativefactories.ExpressionFactory_TranspileProps{
|
|
87
120
|
Importer: importer,
|
|
88
|
-
Script:
|
|
121
|
+
Script: tag.Validate,
|
|
89
122
|
}, context.Emit)
|
|
123
|
+
return func(input *shimast.Expression) *shimast.Node {
|
|
124
|
+
return check_string_pattern(context, tag, input, transpile(input))
|
|
125
|
+
}
|
|
90
126
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
package iterate
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"testing"
|
|
5
|
+
|
|
6
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
7
|
+
shimprinter "github.com/microsoft/typescript-go/shim/printer"
|
|
8
|
+
nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
|
|
9
|
+
nativemetadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// TestCheckStringCachesOnlyStaticPatterns verifies the string check's cache boundary.
|
|
13
|
+
//
|
|
14
|
+
// Pattern-kind metadata alone cannot justify replacing arbitrary validation
|
|
15
|
+
// code. Only a flag-free constructor with the authored source and input has
|
|
16
|
+
// the standard tag's stateless behavior.
|
|
17
|
+
//
|
|
18
|
+
// 1. Build real string-check expressions for standard and custom tag forms.
|
|
19
|
+
// 2. Require one lazy var slot for repeated standard sources in compiler mode.
|
|
20
|
+
// 3. Preserve inline checks without new names in standalone mode, and preserve
|
|
21
|
+
// custom expressions in both modes.
|
|
22
|
+
//
|
|
23
|
+
// @evidence contracts/testing.md#behavioral-verification Check_string builds AST checks from tag metadata. Standard and empty sources register one lazy uninitialized var after repeated compiler-integrated calls; flags, altered source, altered input, arbitrary predicates and other tag kinds register none. Standalone mode retains the inline constructor and emits no potentially conflicting name.
|
|
24
|
+
// @evidence contracts/testing.md#independent-expectations A flag-free RegExp(source).test(input) can reuse one stateless object. Additional flags or authored expressions are independent behavior and must remain unchanged; uninitialized var slots preserve lazy and early-module use.
|
|
25
|
+
// @evidence contracts/testing.md#distinguishing-cases Standard, empty and invalid sources have custom flags, mismatched source, mismatched input, custom predicate, non-pattern kind and absent importer negative twins. Two distinct sources require two slots; repeated requests reuse one. Standalone mode contrasts with compiler mode because it cannot safely allocate a name beside authored declarations.
|
|
26
|
+
// @evidence contracts/testing.md#execution-ownership The native Go suite discovers this in-process unit test. It calls the real checker builder and importer with in-memory AST and metadata; no compiler artifact or JavaScript subprocess is needed. The schema E2E case owns actual module lowering and construction counts.
|
|
27
|
+
func TestCheckStringCachesOnlyStaticPatterns(t *testing.T) {
|
|
28
|
+
for _, emit := range []*shimprinter.EmitContext{nil, shimprinter.NewEmitContext()} {
|
|
29
|
+
for _, row := range []struct {
|
|
30
|
+
source string
|
|
31
|
+
script string
|
|
32
|
+
kind string
|
|
33
|
+
cached bool
|
|
34
|
+
}{
|
|
35
|
+
{"x", `RegExp("x").test($input)`, "pattern", true},
|
|
36
|
+
{"", `RegExp("").test($input)`, "pattern", true},
|
|
37
|
+
{"[", `RegExp("[").test($input)`, "pattern", true},
|
|
38
|
+
{"x", `RegExp("x", "g").test($input)`, "pattern", false},
|
|
39
|
+
{"x", `RegExp("y").test($input)`, "pattern", false},
|
|
40
|
+
{"x", `RegExp("x").test("other")`, "pattern", false},
|
|
41
|
+
{"x", `$input === "allow"`, "pattern", false},
|
|
42
|
+
{"x", `RegExp("x").test($input)`, "custom", false},
|
|
43
|
+
} {
|
|
44
|
+
importer := nativecontext.NewImportProgrammer()
|
|
45
|
+
if emit != nil {
|
|
46
|
+
importer.SetEmitContext(emit)
|
|
47
|
+
}
|
|
48
|
+
props := Check_stringProps{
|
|
49
|
+
Context: nativecontext.ITypiaContext{Emit: emit, Importer: importer},
|
|
50
|
+
Input: nativecontext.NodeFactoryOf(emit).NewIdentifier("input"),
|
|
51
|
+
Atomic: &nativemetadata.MetadataAtomic{Type: "string", Tags: [][]nativemetadata.IMetadataTypeTag{{{
|
|
52
|
+
Target: "string", Name: "test", Kind: row.kind, Value: row.source, Validate: row.script,
|
|
53
|
+
}}}},
|
|
54
|
+
}
|
|
55
|
+
first := Check_string(props).Conditions[0][0].Expression
|
|
56
|
+
Check_string(props)
|
|
57
|
+
statements := importer.ToStatements()
|
|
58
|
+
expected := 0
|
|
59
|
+
if row.cached && emit != nil {
|
|
60
|
+
expected = 1
|
|
61
|
+
}
|
|
62
|
+
if len(statements) != expected {
|
|
63
|
+
t.Fatalf("%s: expected %d cache slots, got %d", row.script, expected, len(statements))
|
|
64
|
+
}
|
|
65
|
+
if row.cached && emit == nil {
|
|
66
|
+
receiver := first.AsCallExpression().Expression.AsPropertyAccessExpression().Expression
|
|
67
|
+
if receiver.Kind != shimast.KindCallExpression {
|
|
68
|
+
t.Fatal("standalone mode must preserve the inline constructor without a new binding")
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if expected != 0 {
|
|
72
|
+
declaration := statements[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList()
|
|
73
|
+
if declaration.Flags&(shimast.NodeFlagsLet|shimast.NodeFlagsConst) != 0 || declaration.Declarations.Nodes[0].AsVariableDeclaration().Initializer != nil {
|
|
74
|
+
t.Fatalf("%s: cache must use an uninitialized var", row.script)
|
|
75
|
+
}
|
|
76
|
+
receiver := first.AsCallExpression().Expression.AsPropertyAccessExpression().Expression
|
|
77
|
+
if receiver.Kind != shimast.KindParenthesizedExpression || receiver.AsParenthesizedExpression().Expression.AsBinaryExpression().OperatorToken.Kind != shimast.KindQuestionQuestionEqualsToken {
|
|
78
|
+
t.Fatalf("%s: construction must be lazy", row.script)
|
|
79
|
+
}
|
|
80
|
+
props.Atomic.Tags[0][0].Value = "different"
|
|
81
|
+
props.Atomic.Tags[0][0].Validate = `RegExp("different").test($input)`
|
|
82
|
+
Check_string(props)
|
|
83
|
+
if len(importer.ToStatements()) != 2 {
|
|
84
|
+
t.Fatal("distinct sources must have distinct slots")
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
props.Context.Importer = nil
|
|
88
|
+
Check_string(props)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -30,7 +30,7 @@ type Check_templateProps struct {
|
|
|
30
30
|
// guard plus one `RegExp(...).test` per template, with the type tags inlined
|
|
31
31
|
// into the member when several templates are neighbors.
|
|
32
32
|
//
|
|
33
|
-
// @evidence contracts/common.md#principled-implementation It builds the check entry of template literal types: a string guard plus one
|
|
33
|
+
// @evidence contracts/common.md#principled-implementation It builds the check entry of template literal types: a string guard plus one structural regex per template. Whole-string and captured-placeholder tag conditions use the common string-tag lowering, including backtracking and union members, so standard Pattern tags share the file cache without changing structural matching.
|
|
34
34
|
// @evidence contracts/common.md#clear-and-simple-design One exported function; the pieces that repeat live in private helpers of the same file.
|
|
35
35
|
// @evidence contracts/common.md#prohibited-implementation-shortcuts Its inputs are its arguments and the context they carry, and it keeps no state of its own.
|
|
36
36
|
// @evidence contracts/common.md#meaningful-documentation The doc states what it builds.
|
|
@@ -125,7 +125,7 @@ func check_template_type_tags(props Check_templateProps, tpl *nativemetadata.Met
|
|
|
125
125
|
for _, tag := range tags {
|
|
126
126
|
conditions = append(conditions, nativehelpers.ICheckEntry_ICondition{
|
|
127
127
|
Expected: tpl.GetBaseName() + " & " + tag.Name,
|
|
128
|
-
Expression: check_string_transpile(props.Context, tag
|
|
128
|
+
Expression: check_string_transpile(props.Context, tag)(props.Input),
|
|
129
129
|
})
|
|
130
130
|
}
|
|
131
131
|
for _, tag := range row {
|
|
@@ -253,7 +253,7 @@ func check_template_value_conditions(props Check_templateProps, base string, ato
|
|
|
253
253
|
for _, tag := range check_string_filter_validate(row) {
|
|
254
254
|
conditions = append(conditions, nativehelpers.ICheckEntry_ICondition{
|
|
255
255
|
Expected: base + " & " + tag.Name,
|
|
256
|
-
Expression: check_string_transpile(props.Context, tag
|
|
256
|
+
Expression: check_string_transpile(props.Context, tag)(input),
|
|
257
257
|
})
|
|
258
258
|
}
|
|
259
259
|
for _, tag := range row {
|
|
@@ -611,7 +611,7 @@ func check_template_inline_tags(props Check_templateProps, tpl *nativemetadata.M
|
|
|
611
611
|
tags := check_string_filter_validate(row)
|
|
612
612
|
expressions := make([]*shimast.Node, 0, len(tags))
|
|
613
613
|
for _, tag := range tags {
|
|
614
|
-
expressions = append(expressions, check_string_transpile(props.Context, tag
|
|
614
|
+
expressions = append(expressions, check_string_transpile(props.Context, tag)(props.Input))
|
|
615
615
|
}
|
|
616
616
|
for _, tag := range row {
|
|
617
617
|
if condition := check_exclude_condition("string", tag, props.Input, props.Emit); condition != nil {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typia",
|
|
3
|
-
"version": "15.2.
|
|
3
|
+
"version": "15.2.2",
|
|
4
4
|
"description": "Superfast runtime validators with only one line",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"homepage": "https://typia.io",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"randexp": "^0.5.3",
|
|
46
|
-
"@typia/interface": "^15.2.
|
|
47
|
-
"@typia/utils": "^15.2.
|
|
46
|
+
"@typia/interface": "^15.2.2",
|
|
47
|
+
"@typia/utils": "^15.2.2"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"ttsc": ">=0.34.1"
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test whether a string has at least the given number of code points.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Twice the requested minimum in UTF-16 units guarantees enough code points.
|
|
5
|
+
* Other inputs are counted only until the minimum is reached.
|
|
6
6
|
*
|
|
7
|
-
* @evidence contracts/common.md#principled-implementation
|
|
7
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies at most two UTF-16 units, so code-unit length at least twice the minimum proves the code-point bound. Otherwise iteration stops at the minimum; nonpositive minima remain true and NaN remains false.
|
|
8
8
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
9
9
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
10
10
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
11
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit lower bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
12
|
+
*
|
|
13
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
14
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
11
15
|
*/
|
|
12
16
|
export const _stringLengthGte = (value: string, length: number): boolean => {
|
|
17
|
+
if (value.length >= length * 2) return true;
|
|
13
18
|
let count: number = 0;
|
|
14
19
|
if (length <= count) return true;
|
|
15
20
|
for (const _ch of value) if (length <= ++count) return true;
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test whether a string has at most the given number of code points.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* UTF-16 length decides inputs whose code units already fit the bound. Other
|
|
5
|
+
* inputs are counted only until the maximum is exceeded.
|
|
6
6
|
*
|
|
7
|
-
* @evidence contracts/common.md#principled-implementation
|
|
7
|
+
* @evidence contracts/common.md#principled-implementation Each code point occupies one or two UTF-16 units, so code-unit length at most the maximum proves the code-point bound. Otherwise iteration stops once the maximum is exceeded; negative and NaN maxima remain false.
|
|
8
8
|
* @evidence contracts/common.md#clear-and-simple-design One loop with an early return.
|
|
9
9
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The unit is code points.
|
|
10
10
|
* @evidence contracts/common.md#meaningful-documentation The doc states the early return and the code point unit.
|
|
11
|
+
* @evidence contracts/performance.md#efficient-algorithms The code-unit upper bound accepts in constant time without allocating an iterator; ambiguous inputs retain the bounded code-point walk and constant auxiliary space.
|
|
12
|
+
*
|
|
13
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call depends on its own primitive string and bound; this predicate coordinates no repeated requests or shared computation.
|
|
14
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The predicate retains no state or handles after returning; iteration and scalar counters are call-local.
|
|
11
15
|
*/
|
|
12
16
|
export const _stringLengthLte = (value: string, length: number): boolean => {
|
|
17
|
+
if (value.length <= length) return true;
|
|
13
18
|
let count: number = 0;
|
|
14
19
|
if (!(count <= length)) return false;
|
|
15
20
|
for (const _ch of value) if (!(++count <= length)) return false;
|