@limaformat/lima 0.6.0 → 0.7.1

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/CHANGELOG.md CHANGED
@@ -5,11 +5,62 @@ All notable changes to `@limaformat/lima` are documented in this file.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
  This package's version number tracks its own release history and is
7
7
  independent of the Lima specification versions — [Lima Core
8
- 1.1](https://github.com/limaformat/lima/blob/main/docs/lima-core-1.0-spec.md)
8
+ 1.2](https://github.com/limaformat/lima/blob/main/docs/lima-core-1.0-spec.md)
9
9
  and [Lima References
10
- 2.0](https://github.com/limaformat/lima/blob/main/docs/lima-references-2.0-spec.md)
10
+ 2.1](https://github.com/limaformat/lima/blob/main/docs/lima-references-2.0-spec.md)
11
11
  carry their own.
12
12
 
13
+ ## [Unreleased]
14
+
15
+ ## [0.7.1] — 2026-10-31
16
+
17
+ ### Security
18
+
19
+ - A few KB of references could copy millions of nodes before the limit on the result stopped them, and interpolation
20
+ kept growing a value past its limit. Resolution now counts what it copies and stops (References §4.1), with the
21
+ error of an oversized result.
22
+
23
+ ### Fixed
24
+
25
+ - A value or sequence item followed by whitespace other than spaces kept it at the top level: `draft: false` with a no-break space
26
+ after it is now the boolean, as in a block (Core §4).
27
+ - `.0` and `-.0` are zero, not an underflow.
28
+ - A line with an empty key in a block is an unrecognised line.
29
+ - Spaces before a flow value in a sequence item threw an error without a Lima code.
30
+ - Messages no longer quote control or direction characters of the source, and shorten a long line.
31
+
32
+ ### Added
33
+
34
+ - `LimaError` is exported.
35
+
36
+ ## [0.7.0] — 2026-10-30
37
+
38
+ Lima Core 1.2 and References 2.1: an unquoted key may be written in any
39
+ script. It starts with a letter or number of Unicode 18.0 or `_`, and after
40
+ its first character also holds marks, `*` and `·`, so keys can be written
41
+ in any language and gendered (`größe`, `題名`, `autor*in`, `autor·in`);
42
+ references reach every such key. Core 1.2 also states in one table what
43
+ each kind of line does where it stands (§7.1), without changing an outcome.
44
+
45
+ ### Added
46
+
47
+ - Unquoted keys and reference names take Unicode letters, marks and numbers
48
+ (Unicode 18.0, fixed by the specification) and `*` and `·` after their
49
+ first character. The categories come from a generated table, not the
50
+ host's Unicode support, and no dependency; ASCII keys are read as fast as
51
+ before.
52
+ - Hints: whitespace other than spaces before a key, a FULLWIDTH COLON
53
+ (U+FF1A) in place of `: `, and the key-grammar hint for a key such as
54
+ `x y: 2` at every level.
55
+
56
+ ### Changed
57
+
58
+ - A line whose key Core 1.1 rejected for its characters, and Core 1.2
59
+ admits, is an entry now; non-strict mode skipped it, strict mode threw.
60
+ - A document with a lone surrogate is rejected with `INVALID_DOCUMENT` and
61
+ the line it is on (Core §1), in both modes.
62
+ - Node.js 22 or later (`String.prototype.isWellFormed`).
63
+
13
64
  ## [0.6.0] — 2026-10-28
14
65
 
15
66
  Lima Core 1.1: strict mode rejects a content line that belongs to no
package/README.md CHANGED
@@ -38,10 +38,10 @@ tags:
38
38
  Three functions are exported:
39
39
 
40
40
  - `parseCore(input, options?)` — the base format only.
41
- - `parse(input, options?)` — the primary References 2.0 parser; adds
41
+ - `parse(input, options?)` — the primary References <!-- facts:language.references_version -->2.1<!-- /facts --> parser; adds
42
42
  `${key}` document references and `$(key)` external partials.
43
43
  - `parseReferences(input, options?)` — deprecated compatibility alias for
44
- `parse` with the same References 2.0 semantics.
44
+ `parse` with the same References <!-- facts:language.references_version -->2.1<!-- /facts --> semantics.
45
45
 
46
46
  ```ts
47
47
  parse(frontmatter, { strict: true })
@@ -50,15 +50,15 @@ parse(frontmatter, { mode: 'core' }) // same reference-unaware path as parseCore
50
50
  ```
51
51
 
52
52
  The **[guide](https://github.com/limaformat/lima/blob/main/docs/guide.md)**
53
- covers Core and References 2.0 syntax, resource limits, strict mode, and the
53
+ covers Core <!-- facts:language.core_version -->1.2<!-- /facts --> and References <!-- facts:language.references_version -->2.1<!-- /facts --> syntax, resource limits, strict mode, and the
54
54
  public API. The normative rules are defined in the
55
- **[References 2.0 specification](https://github.com/limaformat/lima/blob/main/docs/lima-references-2.0-spec.md)**.
55
+ **[References <!-- facts:language.references_version -->2.1<!-- /facts --> specification](https://github.com/limaformat/lima/blob/main/docs/lima-references-2.0-spec.md)**.
56
56
 
57
57
  Why Lima exists, the case against YAML, and security rationale:
58
58
  **[repository README](https://github.com/limaformat/lima#readme)**.
59
59
 
60
- The [Lima Core 1.1](https://github.com/limaformat/lima/blob/main/docs/lima-core-1.0-spec.md)
61
- and [Lima References 2.0](https://github.com/limaformat/lima/blob/main/docs/lima-references-2.0-spec.md)
60
+ The [Lima Core <!-- facts:language.core_version -->1.2<!-- /facts -->](https://github.com/limaformat/lima/blob/main/docs/lima-core-1.0-spec.md)
61
+ and [Lima References <!-- facts:language.references_version -->2.1<!-- /facts -->](https://github.com/limaformat/lima/blob/main/docs/lima-references-2.0-spec.md)
62
62
  specifications are the source of truth for these public entry points. The
63
63
  frozen References 1.0 implementation remains available internally to run its
64
64
  independent conformance suite.
package/dist/block.js CHANGED
@@ -10,9 +10,10 @@
10
10
  */
11
11
  import { checkKeyLength, checkDuplicateKey, NESTING_DEPTH_LIMIT } from './normalize.js';
12
12
  import { stripKeyQuotes, stripComment, stripCommentKeepEscapes, parseQuotedOrTyped, closingQuoteIndex, isValidKey, } from './scalars.js';
13
+ import { KEY_GRAMMAR_HINT, specificKeyHint } from './key-hints.js';
13
14
  import { parseFlowOrScalarValue, parseFlowSequence } from './flow.js';
14
15
  import { buildBlockScalar } from './block-scalar.js';
15
- import { LimaError } from './errors.js';
16
+ import { LimaError, printableLine } from './errors.js';
16
17
  import { isTrimWhitespace } from './chars.js';
17
18
  import { BlockCursor } from './block-cursor.js';
18
19
  const DASH_PREFIX_RE = /^-\s+/;
@@ -166,7 +167,7 @@ const cursorAfterDash = (cursor) => {
166
167
  /** Core 1.1 §10.1: a line in a block whose key the key grammar (§5.1) rejects, in strict mode. */
167
168
  const unrecognizedKeyLine = (line, trimmed) => new LimaError({
168
169
  code: 'UNRECOGNIZED_LINE', line,
169
- message: `Lima: unrecognised line at line ${line}: "${trimmed}" (an unquoted key has letters, digits, "_", "-" and ":" only; quote any other)`,
170
+ message: `Lima: unrecognised line at line ${line}: "${printableLine(trimmed)}"${specificKeyHint(trimmed) ?? KEY_GRAMMAR_HINT}`,
170
171
  });
171
172
  /** Shared block grammar consuming one mutable physical-line cursor. */
172
173
  const parseCursorBlock = (cursor, baseIndent, ctx, baseLine, builder, compact = false) => {
@@ -207,7 +208,7 @@ const parseCursorBlock = (cursor, baseIndent, ctx, baseLine, builder, compact =
207
208
  const keyRaw = colonPos !== -1
208
209
  ? trimEndSlice(trimmed, 0, colonPos)
209
210
  : bareKey ? trimEndSlice(trimmed, 0, trimmed.length - 1) : '';
210
- if (keyRaw !== '' && !isValidKey(keyRaw)) {
211
+ if ((keyRaw !== '' || colonPos !== -1) && !isValidKey(keyRaw)) {
211
212
  // §5.1: not a usable key — an unrecognised line, skipped in non-strict mode and an error in strict
212
213
  // mode, as at the top level (Core 1.1 §10.1)
213
214
  if (ctx.strict)
@@ -267,9 +268,7 @@ const parseCursorBlock = (cursor, baseIndent, ctx, baseLine, builder, compact =
267
268
  if (items === null)
268
269
  items = [];
269
270
  const afterDashRaw = cursorAfterDash(cursor);
270
- let afterDash = afterDashRaw;
271
- if (afterDash.includes('#'))
272
- afterDash = stripComment(afterDash);
271
+ const afterDash = afterDashRaw.includes('#') ? stripComment(afterDashRaw) : afterDashRaw.trimEnd();
273
272
  const afterDashCol = wantSource ? cursor.indent + dashPrefixLen(cursor) : 0;
274
273
  const afterDashTab = wantSource && ctx.tabAdjust ? [ctx.tabAdjust[line - 1] ?? 0] : undefined;
275
274
  const dashSource = wantSource ? ({
@@ -330,7 +329,7 @@ const parseCursorBlock = (cursor, baseIndent, ctx, baseLine, builder, compact =
330
329
  // The key sits after `- `, two columns past the dash.
331
330
  const valueCol = wantSource ? afterDashCol + valueStart + leadingWsLen(afterDash.slice(valueStart)) : 0;
332
331
  pendingColumn = cursor.indent + dashPrefixLen(cursor);
333
- pendingItem = builder.createMappingWith(key, inlineOrBlockScalar(raw, trimSlice(afterDashRaw, valueStart, afterDashRaw.length) === '|', pendingColumn, line, valueCol, wantSource ? afterDashRaw.slice(valueStart) : raw, cursor, ctx, builder));
332
+ pendingItem = builder.createMappingWith(key, inlineOrBlockScalar(raw, trimSlice(afterDashRaw, valueStart, afterDashRaw.length) === '|', pendingColumn, line, valueCol, wantSource ? trimSlice(afterDashRaw, valueStart, afterDashRaw.length) : raw, cursor, ctx, builder));
334
333
  // the item's later keys at its key column; any other line is the block loop's (§7.2)
335
334
  while (cursor.valid && cursor.indent === pendingColumn) {
336
335
  const continuationLine = baseLine + cursor.lineIndex;
@@ -398,7 +397,7 @@ const parseCursorBlock = (cursor, baseIndent, ctx, baseLine, builder, compact =
398
397
  const keyRaw = colonPos !== -1
399
398
  ? trimEndSlice(trimmed, 0, colonPos)
400
399
  : bareKey ? trimEndSlice(trimmed, 0, trimmed.length - 1) : '';
401
- if (keyRaw !== '' && !isValidKey(keyRaw)) {
400
+ if ((keyRaw !== '' || colonPos !== -1) && !isValidKey(keyRaw)) {
402
401
  // §5.1: not a usable key — an unrecognised line, skipped in non-strict mode and an error in strict
403
402
  // mode, as at the top level (Core 1.1 §10.1)
404
403
  if (ctx.strict)
package/dist/core.d.ts CHANGED
@@ -81,4 +81,5 @@ export declare const toNativeFromPositioned: (v: PositionedValue) => NativeValue
81
81
  * contain no references, except that here reference-shaped text is
82
82
  * guaranteed to always pass through unresolved, even in strict mode.
83
83
  */
84
+ export declare const parseCoreValidated: <T extends Record<string, unknown> = Meta>(frontMatter: string, options?: CoreOptions) => T;
84
85
  export declare const parseCore: <T extends Record<string, unknown> = Meta>(frontMatter: string, options?: CoreOptions) => T;
package/dist/core.js CHANGED
@@ -19,6 +19,7 @@
19
19
  * and mappings) — this file is the orchestrator that ties them together.
20
20
  */
21
21
  import { checkKeyLength, byteLength, DOCUMENT_SIZE_LIMIT, TOP_LEVEL_KEY_LIMIT, NESTING_DEPTH_LIMIT, } from './normalize.js';
22
+ import { validateDocument } from './document.js';
22
23
  import { unescapeDQ, stripComment, stripCommentKeepEscapes, positionedBuilder, NO_SPAN_VALUE, parseSimpleScalarSpan, } from './scalars.js';
23
24
  import { isTrimWhitespace } from './chars.js';
24
25
  import { parseFlowOrScalarValue } from './flow.js';
@@ -220,7 +221,7 @@ const parseCoreGeneric = (frontMatter, ctx, builder, computeDepth) => {
220
221
  }
221
222
  const val = frontMatter.slice(rawStart, valueEnd);
222
223
  const hasHash = val.includes('#');
223
- const uncommented = hasHash ? stripComment(val) : val;
224
+ const uncommented = hasHash ? stripComment(val) : val.trimEnd();
224
225
  // The physical anchor keeps `\#` but drops a real comment, so a
225
226
  // `${…}`-shaped token inside a trailing comment is not scanned (§2.4).
226
227
  const source = wantSource ? {
@@ -458,7 +459,11 @@ export const toNativeFromPositioned = (v) => {
458
459
  * contain no references, except that here reference-shaped text is
459
460
  * guaranteed to always pass through unresolved, even in strict mode.
460
461
  */
461
- export const parseCore = (frontMatter, options) => {
462
+ export const parseCoreValidated = (frontMatter, options) => {
462
463
  const ctx = { strict: options?.strict ?? false, onWarning: options?.onWarning };
463
464
  return parseCoreGeneric(frontMatter, ctx, nativeBuilder, depthOfNative);
464
465
  };
466
+ export const parseCore = (frontMatter, options) => {
467
+ validateDocument(frontMatter);
468
+ return parseCoreValidated(frontMatter, options);
469
+ };
@@ -0,0 +1,2 @@
1
+ /** Core §1: a document is a sequence of Unicode scalar values. */
2
+ export declare const validateDocument: (document: string) => void;
@@ -0,0 +1,29 @@
1
+ import { LimaError } from './errors.js';
2
+ /** Core §1: a document is a sequence of Unicode scalar values. */
3
+ export const validateDocument = (document) => {
4
+ // Node 22's native scalar-value check keeps the common valid path out of
5
+ // JavaScript. Only malformed input pays for the line-attribution walk.
6
+ if (document.isWellFormed())
7
+ return;
8
+ let line = 1;
9
+ for (let i = 0; i < document.length; i++) {
10
+ const c = document.charCodeAt(i);
11
+ if (c === 10) {
12
+ line++;
13
+ continue;
14
+ }
15
+ if (c >= 0xd800 && c <= 0xdbff && i + 1 < document.length) {
16
+ const low = document.charCodeAt(i + 1);
17
+ if (low >= 0xdc00 && low <= 0xdfff) {
18
+ i++;
19
+ continue;
20
+ }
21
+ }
22
+ if (c >= 0xd800 && c <= 0xdfff) {
23
+ throw new LimaError({
24
+ code: 'INVALID_DOCUMENT', line,
25
+ message: `Lima: document contains an invalid Unicode scalar value at line ${line}`,
26
+ });
27
+ }
28
+ }
29
+ };
package/dist/errors.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * module directly rather than duplicating it) inspect *why* a parse failed
9
9
  * without re-parsing the message string.
10
10
  */
11
- export type LimaDiagnosticCode = 'INVALID_ESCAPE' | 'INVALID_QUOTE' | 'INVALID_DATE' | 'INVALID_NUMBER' | 'INVALID_REFERENCE_SHAPE' | 'INVALID_INDENTATION' | 'UNRECOGNIZED_LINE' | 'INVALID_FLOW_SYNTAX' | 'DUPLICATE_KEY' | 'RESOURCE_LIMIT' | 'UNRESOLVED_REFERENCE' | 'INVALID_INTERPOLATION' | 'INVALID_PARTIAL';
11
+ export type LimaDiagnosticCode = 'INVALID_DOCUMENT' | 'INVALID_ESCAPE' | 'INVALID_QUOTE' | 'INVALID_DATE' | 'INVALID_NUMBER' | 'INVALID_REFERENCE_SHAPE' | 'INVALID_INDENTATION' | 'UNRECOGNIZED_LINE' | 'INVALID_FLOW_SYNTAX' | 'DUPLICATE_KEY' | 'RESOURCE_LIMIT' | 'UNRESOLVED_REFERENCE' | 'INVALID_INTERPOLATION' | 'INVALID_PARTIAL';
12
12
  export interface LimaDiagnostic {
13
13
  code: LimaDiagnosticCode;
14
14
  message: string;
@@ -19,6 +19,8 @@ export interface LimaDiagnostic {
19
19
  partial?: string;
20
20
  path?: string;
21
21
  }
22
+ /** A line of the source for a message: shortened, and no control or direction character reaches a terminal. */
23
+ export declare const printableLine: (text: string) => string;
22
24
  export declare class LimaError extends Error {
23
25
  readonly code: LimaDiagnosticCode;
24
26
  readonly line?: number;
package/dist/errors.js CHANGED
@@ -8,6 +8,8 @@
8
8
  * module directly rather than duplicating it) inspect *why* a parse failed
9
9
  * without re-parsing the message string.
10
10
  */
11
+ /** A line of the source for a message: shortened, and no control or direction character reaches a terminal. */
12
+ export const printableLine = (text) => (text.length > 120 ? `${text.slice(0, 120)}…` : text).replace(/[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
11
13
  export class LimaError extends Error {
12
14
  code;
13
15
  line;
package/dist/index.d.ts CHANGED
@@ -3,14 +3,15 @@
3
3
  *
4
4
  * Public entry point. The implementation is split per Appendix B's own
5
5
  * layering:
6
- * - `core.ts` — Lima Core 1.1, reference-unaware by construction.
7
- * - `references2.ts` — the References 2.0 extension layered on Core.
6
+ * - `core.ts` — Lima Core 1.2, reference-unaware by construction.
7
+ * - `references2.ts` — the References 2.1 extension layered on Core.
8
8
  * - `references.ts` — the frozen internal References 1.0 implementation.
9
9
  * - `value.ts` — the shared Lima Value Model both build on.
10
10
  *
11
- * `parse` is the primary References 2.0 entry point. `parseReferences` is
11
+ * `parse` is the primary References 2.1 entry point. `parseReferences` is
12
12
  * retained as its deprecated compatibility alias.
13
13
  */
14
14
  export { parseCore, type CoreOptions, type Diagnostic } from './core.js';
15
+ export { LimaError, type LimaDiagnostic, type LimaDiagnosticCode } from './errors.js';
15
16
  export { parseReferences, parse, type ParseMode, type ParseOptions } from './references2.js';
16
17
  export type ReferencesOptions = import('./references2.js').ParseOptions;
package/dist/index.js CHANGED
@@ -3,13 +3,14 @@
3
3
  *
4
4
  * Public entry point. The implementation is split per Appendix B's own
5
5
  * layering:
6
- * - `core.ts` — Lima Core 1.1, reference-unaware by construction.
7
- * - `references2.ts` — the References 2.0 extension layered on Core.
6
+ * - `core.ts` — Lima Core 1.2, reference-unaware by construction.
7
+ * - `references2.ts` — the References 2.1 extension layered on Core.
8
8
  * - `references.ts` — the frozen internal References 1.0 implementation.
9
9
  * - `value.ts` — the shared Lima Value Model both build on.
10
10
  *
11
- * `parse` is the primary References 2.0 entry point. `parseReferences` is
11
+ * `parse` is the primary References 2.1 entry point. `parseReferences` is
12
12
  * retained as its deprecated compatibility alias.
13
13
  */
14
14
  export { parseCore } from './core.js';
15
+ export { LimaError } from './errors.js';
15
16
  export { parseReferences, parse } from './references2.js';
@@ -0,0 +1,3 @@
1
+ export declare const isKeyInitialCodePoint: (c: number) => boolean;
2
+ export declare const isKeyCharacterCodePoint: (c: number) => boolean;
3
+ export declare const isValidUnquotedKey: (raw: string, allowSlash?: boolean) => boolean;
@@ -0,0 +1,58 @@
1
+ import { UNICODE_KEY_RANGES } from './unicode-key-table.js';
2
+ const unicodeKeyCategory = (codePoint) => {
3
+ let low = 0;
4
+ let high = UNICODE_KEY_RANGES.length / 3;
5
+ while (low < high) {
6
+ const mid = (low + high) >>> 1;
7
+ const offset = mid * 3;
8
+ if (codePoint < UNICODE_KEY_RANGES[offset])
9
+ high = mid;
10
+ else if (codePoint > UNICODE_KEY_RANGES[offset + 1])
11
+ low = mid + 1;
12
+ else
13
+ return UNICODE_KEY_RANGES[offset + 2];
14
+ }
15
+ return 0;
16
+ };
17
+ export const isKeyInitialCodePoint = (c) => {
18
+ if (c <= 0x7f)
19
+ return c === 95 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122;
20
+ return (unicodeKeyCategory(c) & 5) !== 0; // L or N
21
+ };
22
+ export const isKeyCharacterCodePoint = (c) => {
23
+ if (c <= 0x7f)
24
+ return isKeyInitialCodePoint(c) || c === 58 || c === 45 || c === 42;
25
+ return c === 0xb7 || unicodeKeyCategory(c) !== 0; // L, M or N
26
+ };
27
+ export const isValidUnquotedKey = (raw, allowSlash = false) => {
28
+ if (raw.length === 0)
29
+ return false;
30
+ let i = 0;
31
+ let cp = raw.charCodeAt(0);
32
+ if (cp <= 0x7f) {
33
+ if (!(cp === 95 || cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122))
34
+ return false;
35
+ i = 1;
36
+ }
37
+ else {
38
+ cp = raw.codePointAt(0);
39
+ if (!isKeyInitialCodePoint(cp))
40
+ return false;
41
+ i = cp > 0xffff ? 2 : 1;
42
+ }
43
+ while (i < raw.length) {
44
+ cp = raw.charCodeAt(i);
45
+ if (cp <= 0x7f) {
46
+ if (!(cp === 95 || cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 ||
47
+ cp === 58 || cp === 45 || cp === 42 || allowSlash && cp === 47))
48
+ return false;
49
+ }
50
+ else {
51
+ cp = raw.codePointAt(i);
52
+ if (!isKeyCharacterCodePoint(cp))
53
+ return false;
54
+ }
55
+ i += cp > 0xffff ? 2 : 1;
56
+ }
57
+ return true;
58
+ };
@@ -0,0 +1,2 @@
1
+ export declare const KEY_GRAMMAR_HINT = " (an unquoted key starts with a Unicode letter or number or \"_\", then has letters, marks, numbers, \"_\", \":\", \"-\", \"*\" and \"\u00B7\"; quote any other)";
2
+ export declare const specificKeyHint: (text: string) => string | undefined;
@@ -0,0 +1,17 @@
1
+ import { isTrimWhitespace } from './chars.js';
2
+ import { isValidUnquotedKey } from './key-grammar.js';
3
+ export const KEY_GRAMMAR_HINT = ' (an unquoted key starts with a Unicode letter or number or "_", then has letters, marks, numbers, "_", ":", "-", "*" and "·"; quote any other)';
4
+ export const specificKeyHint = (text) => {
5
+ let i = 0;
6
+ while (text.charCodeAt(i) === 32)
7
+ i++;
8
+ const cp = text.codePointAt(i);
9
+ if (cp !== undefined && cp !== 32 && isTrimWhitespace(cp)) {
10
+ return ` (U+${cp.toString(16).toUpperCase().padStart(4, '0')} before the key; Lima indents by spaces only)`;
11
+ }
12
+ const colon = text.indexOf('\uFF1A');
13
+ if (colon > 0 && isValidUnquotedKey(text.slice(0, colon))) {
14
+ return ' (the key-value separator is ": " (U+003A and a space), not U+FF1A FULLWIDTH COLON)';
15
+ }
16
+ return undefined;
17
+ };
@@ -39,11 +39,6 @@ export type ReferenceSource = {
39
39
  col: number;
40
40
  tabAdjust?: number[];
41
41
  };
42
- export declare const SEGMENT = "[a-zA-Z0-9_][a-zA-Z0-9_:-]*";
43
- export declare const DOC_PATH = "[a-zA-Z0-9_][a-zA-Z0-9_:-]*(?:\\.[a-zA-Z0-9_][a-zA-Z0-9_:-]*)*";
44
- export declare const PARTIAL_NAME = "[a-zA-Z0-9_][a-zA-Z0-9_:/-]*";
45
- export declare const PARTIAL_PATH = "[a-zA-Z0-9_][a-zA-Z0-9_:/-]*(?:\\.[a-zA-Z0-9_][a-zA-Z0-9_:-]*)*";
46
- export declare const PURE_REFERENCE_2: RegExp;
47
42
  /** Converts a 0-based codepoint offset to JavaScript/LSP UTF-16 units. */
48
43
  export declare const codepointOffsetToUtf16: (text: string, codepointOffset: number) => number;
49
44
  /** Converts a 0-based JavaScript/LSP UTF-16 offset to a codepoint offset. */
@@ -1,11 +1,8 @@
1
1
  /** Reference tokens recorded while the annotated Core tree is being built. */
2
- export const SEGMENT = '[a-zA-Z0-9_][a-zA-Z0-9_:-]*';
3
- export const DOC_PATH = `${SEGMENT}(?:\\.${SEGMENT})*`;
4
- export const PARTIAL_NAME = '[a-zA-Z0-9_][a-zA-Z0-9_:/-]*';
5
- export const PARTIAL_PATH = `${PARTIAL_NAME}(?:\\.${SEGMENT})*`;
6
- export const PURE_REFERENCE_2 = new RegExp(`^(?:\\$\\{(${DOC_PATH})\\}|\\$\\((${PARTIAL_PATH})\\))$`);
7
- const REFERENCE_2 = new RegExp(`\\$\\{(${DOC_PATH})\\}|\\$\\((${PARTIAL_PATH})\\)`, 'g');
2
+ import { isKeyCharacterCodePoint, isKeyInitialCodePoint } from './key-grammar.js';
8
3
  const NO_TOKENS = [];
4
+ const isAsciiReferenceInitial = (c) => (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 95;
5
+ const isAsciiReferenceCharacter = (c, allowSlash) => isAsciiReferenceInitial(c) || c === 58 || c === 45 || c === 42 || allowSlash && c === 47;
9
6
  const utf16WidthAt = (text, offset) => text.codePointAt(offset) > 0xffff ? 2 : 1;
10
7
  /** Codepoint length of the UTF-16 slice `[a, b)` of `s`. */
11
8
  const codepointLen = (s, a, b) => {
@@ -38,27 +35,80 @@ export const utf16OffsetToCodepoint = (text, utf16Offset) => {
38
35
  return codepoints;
39
36
  };
40
37
  /** Splice points (decoded value order): token text, UTF-16 index, path. */
38
+ const scanComponent = (value, start, allowSlash) => {
39
+ let i = start;
40
+ if (i >= value.length)
41
+ return -1;
42
+ let cp = value.charCodeAt(i);
43
+ if (cp <= 0x7f) {
44
+ if (!isAsciiReferenceInitial(cp))
45
+ return -1;
46
+ }
47
+ else {
48
+ cp = value.codePointAt(i);
49
+ if (!isKeyInitialCodePoint(cp))
50
+ return -1;
51
+ }
52
+ i += cp > 0xffff ? 2 : 1;
53
+ while (i < value.length && isAsciiReferenceCharacter(value.charCodeAt(i), allowSlash))
54
+ i++;
55
+ while (i < value.length) {
56
+ cp = value.charCodeAt(i);
57
+ if (cp <= 0x7f)
58
+ break;
59
+ cp = value.codePointAt(i);
60
+ if (!isKeyCharacterCodePoint(cp))
61
+ break;
62
+ i += cp > 0xffff ? 2 : 1;
63
+ while (i < value.length && isAsciiReferenceCharacter(value.charCodeAt(i), allowSlash))
64
+ i++;
65
+ }
66
+ return i;
67
+ };
68
+ const scanPath = (value, start, partial) => {
69
+ let i = scanComponent(value, start, partial);
70
+ if (i < 0)
71
+ return -1;
72
+ while (value.charCodeAt(i) === 46) {
73
+ const next = scanComponent(value, i + 1, false);
74
+ if (next < 0)
75
+ return -1;
76
+ i = next;
77
+ }
78
+ return i;
79
+ };
41
80
  const scanDecoded = (value) => {
42
- REFERENCE_2.lastIndex = 0;
43
81
  const out = [];
44
- for (const m of value.matchAll(REFERENCE_2)) {
45
- out.push({
46
- token: m[0], index: m.index ?? 0,
47
- ...(m[1] !== undefined ? { documentPath: m[1] } : { partialPath: m[2] }),
48
- });
82
+ for (let i = 0; i + 2 < value.length;) {
83
+ const partial = value.startsWith('$(', i);
84
+ const document = !partial && value.startsWith('${', i);
85
+ if (!partial && !document) {
86
+ const cp = value.codePointAt(i);
87
+ i += cp > 0xffff ? 2 : 1;
88
+ continue;
89
+ }
90
+ const end = scanPath(value, i + 2, partial);
91
+ const close = partial ? 41 : 125;
92
+ if (end >= 0 && value.charCodeAt(end) === close) {
93
+ const token = value.slice(i, end + 1);
94
+ const path = value.slice(i + 2, end);
95
+ out.push({ token, index: i, ...(partial ? { partialPath: path } : { documentPath: path }) });
96
+ i = end + 1;
97
+ }
98
+ else
99
+ i++;
49
100
  }
50
101
  return out;
51
102
  };
52
103
  /** Physical `(line, offset)` of each token, in source order, from the raw text. */
53
104
  const scanPhysical = (raw, firstLine, firstCol, tabAdjust) => {
54
- REFERENCE_2.lastIndex = 0;
55
105
  const out = [];
56
106
  let scanned = 0;
57
107
  let line = firstLine;
58
108
  let col = firstCol;
59
109
  let lineIndex = 0;
60
- for (const m of raw.matchAll(REFERENCE_2)) {
61
- const idx = m.index ?? 0;
110
+ for (const m of scanDecoded(raw)) {
111
+ const idx = m.index;
62
112
  while (scanned < idx) {
63
113
  const cp = raw.codePointAt(scanned);
64
114
  if (cp === 10) {
@@ -1,11 +1,11 @@
1
- /** Lima References 2.0 resolver. References 1.0 remains isolated in references.ts. */
2
- import { canonicalString, codepointLength, countNodes, ingestPartialValue, PARTIAL_COUNT_LIMIT, PARTIAL_NAME_LENGTH_LIMIT, PARTIAL_NODE_LIMIT, RESULT_NODE_LIMIT, SCALAR_LENGTH_LIMIT, } from './value.js';
3
- import { NESTING_DEPTH_LIMIT, parseCore, parseCoreWithPositions, toPlainValue, } from './core.js';
1
+ /** Lima References 2.1 resolver. References 1.0 remains isolated in references.ts. */
2
+ import { canonicalString, codepointLength, countNodes, ingestPartialValue, PARTIAL_COUNT_LIMIT, PARTIAL_NAME_LENGTH_LIMIT, PARTIAL_NODE_LIMIT, RESOLUTION_COPY_LIMIT, RESULT_NODE_LIMIT, SCALAR_LENGTH_LIMIT, } from './value.js';
3
+ import { isValidUnquotedKey } from './key-grammar.js';
4
+ import { validateDocument } from './document.js';
5
+ import { NESTING_DEPTH_LIMIT, parseCoreValidated, parseCoreWithPositions, toPlainValue, } from './core.js';
4
6
  import { hasActiveReferences2 } from './scalars.js';
5
7
  import { LimaError } from './errors.js';
6
8
  import { collectAllParticipants, deepCopyPositioned, earliestParticipant, emptyMapping, finalizePositioned, partialToPositioned, } from './positioned-tree.js';
7
- const PARTIAL_NAME = '[a-zA-Z0-9_][a-zA-Z0-9_:/-]*';
8
- const PARTIAL_NAME_RE = new RegExp(`^${PARTIAL_NAME}$`);
9
9
  const MAX_EDGES = 3;
10
10
  // Looking up the root path is itself the first reference edge; recursion into
11
11
  // that root therefore gets the public resolver's remaining two-edge budget.
@@ -13,13 +13,44 @@ const TARGET_EDGE_BUDGET = MAX_EDGES - 1;
13
13
  const referenceResourceStatuses = new WeakMap();
14
14
  /** Copies a pure-reference target and stamps the new insertion without
15
15
  * discarding provenance already attached to the copied root (R-112). */
16
- const copyWithInsertion = (target, insertedAt) => {
16
+ const copyWithInsertion = (target, insertedAt, ctx) => {
17
+ const earliest = ctx.earliestInsertion;
18
+ ctx.earliestInsertion = earliest === null ? insertedAt : earliestParticipant([earliest, insertedAt]);
19
+ if (!ctx.overflowed) {
20
+ ctx.copied += countPositioned(target);
21
+ ctx.overflowed = ctx.copied > RESOLUTION_COPY_LIMIT;
22
+ }
23
+ // the result is lost by now: resolution only goes on to see the earliest insertion
24
+ if (ctx.overflowed)
25
+ return { kind: 'null', line: 0 };
17
26
  const copy = deepCopyPositioned(target);
18
27
  const priorInsertions = copy.insertedAt === undefined
19
28
  ? copy.priorInsertions
20
29
  : [...(copy.priorInsertions ?? []), copy.insertedAt];
21
30
  return { ...copy, insertedAt, priorInsertions };
22
31
  };
32
+ const countPositioned = (v) => {
33
+ let count = 1;
34
+ if (v.kind === 'array')
35
+ for (const item of v.items)
36
+ count += countPositioned(item);
37
+ if (v.kind === 'mapping')
38
+ for (const child of v.entries.values())
39
+ count += countPositioned(child);
40
+ return count;
41
+ };
42
+ const newContext = (cache) => ({
43
+ diagnostics: [], copied: 0, overflowed: false, earliestInsertion: null, ...(cache ? { cache } : {}),
44
+ });
45
+ /** The error of a document whose references would copy past RESOLUTION_COPY_LIMIT: that of an oversized result. */
46
+ const overflowError = (ctx) => {
47
+ const winner = ctx.earliestInsertion;
48
+ return new LimaError({
49
+ code: 'RESOURCE_LIMIT', line: winner?.line ?? 1, token: winner?.token,
50
+ ...(winner?.offset !== undefined ? { column: winner.offset + 1 } : {}),
51
+ message: `Lima: result exceeds maximum size of ${RESULT_NODE_LIMIT} total nodes at line ${winner?.line ?? 1}`,
52
+ });
53
+ };
23
54
  const addDiagnostic = (ctx, diagnostic, offset = 0) => {
24
55
  ctx.diagnostics.push({ ...diagnostic, offset });
25
56
  };
@@ -58,10 +89,10 @@ export const resolveDocumentReferenceTarget = (parsed, path) => {
58
89
  return { status: resourceStatus };
59
90
  if (resourceStatus === 'invalid')
60
91
  return { status: 'unresolved' };
61
- const ctx = { diagnostics: [], cache: new WeakMap() };
92
+ const ctx = newContext(new WeakMap());
62
93
  const stack = new Set([target.root]);
63
94
  const resolved = resolveNode(target.root, document, new Map(), ctx, TARGET_EDGE_BUDGET, stack);
64
- if (!resolved.complete || ctx.diagnostics.length > 0)
95
+ if (!resolved.complete || ctx.overflowed || ctx.diagnostics.length > 0)
65
96
  return { status: 'unresolved' };
66
97
  const selected = lookupPath(resolved.value, target.tail);
67
98
  return selected === undefined
@@ -116,9 +147,9 @@ const documentReferenceResourceStatus = (parsed) => {
116
147
  const cached = referenceResourceStatuses.get(document);
117
148
  if (cached !== undefined)
118
149
  return cached;
119
- const ctx = { diagnostics: [], cache: new WeakMap() };
150
+ const ctx = newContext(new WeakMap());
120
151
  const resolved = resolveDocument(document, new Map(), ctx);
121
- let valid = !ctx.diagnostics.some((diagnostic) => diagnostic.code === 'RESOURCE_LIMIT');
152
+ let valid = !ctx.overflowed && !ctx.diagnostics.some((diagnostic) => diagnostic.code === 'RESOURCE_LIMIT');
122
153
  if (valid) {
123
154
  try {
124
155
  assertResolvedDocumentResourceLimits(resolved);
@@ -220,7 +251,7 @@ const resolveNodeUncached = (node, document, partials, ctx, remainingEdges, stac
220
251
  // `partialToPositioned` never annotates partial targets: partials are
221
252
  // inert and have no source token before this document insertion.
222
253
  return {
223
- value: copyWithInsertion(target, { line: pure.line, offset: pure.offset, token: pure.token }),
254
+ value: copyWithInsertion(target, { line: pure.line, offset: pure.offset, token: pure.token }, ctx),
224
255
  complete: true,
225
256
  };
226
257
  }
@@ -235,7 +266,7 @@ const resolveNodeUncached = (node, document, partials, ctx, remainingEdges, stac
235
266
  return {
236
267
  // `selected` may itself be the root inserted by an earlier reference;
237
268
  // both it and this outer copy participate in final-structure errors.
238
- value: copyWithInsertion(selected, { line: pure.line, offset: pure.offset, token: pure.token }),
269
+ value: copyWithInsertion(selected, { line: pure.line, offset: pure.offset, token: pure.token }, ctx),
239
270
  complete: true,
240
271
  };
241
272
  }
@@ -280,6 +311,8 @@ const resolveNodeUncached = (node, document, partials, ctx, remainingEdges, stac
280
311
  code: 'RESOURCE_LIMIT', line: first.line, token: first.token,
281
312
  message: `Lima: scalar exceeds maximum length of ${SCALAR_LENGTH_LIMIT} code points at line ${first.line}`,
282
313
  }, first.offset);
314
+ // the document has failed; a value that holds this one still exceeds the limit, and none grows further
315
+ output = output.slice(0, 2 * (SCALAR_LENGTH_LIMIT + 1));
283
316
  }
284
317
  return { value: { ...node, value: output, references2: unresolvedTokens }, complete };
285
318
  };
@@ -317,7 +350,7 @@ const validatePartials = (raw) => {
317
350
  throw new LimaError({ code: 'INVALID_PARTIAL', message: `Lima: too many partials (max ${PARTIAL_COUNT_LIMIT})` });
318
351
  }
319
352
  for (const name of names) {
320
- if (!PARTIAL_NAME_RE.test(name)) {
353
+ if (!isValidUnquotedKey(name, true)) {
321
354
  throw new LimaError({ code: 'INVALID_PARTIAL', partial: name, message: `Lima: invalid partial name "${name}"` });
322
355
  }
323
356
  if (codepointLength(name) > PARTIAL_NAME_LENGTH_LIMIT) {
@@ -356,6 +389,7 @@ const scanUnresolved = (node, ctx) => {
356
389
  scanUnresolved(child, ctx);
357
390
  };
358
391
  const parseInternal = (frontMatter, options, useResolveCache) => {
392
+ validateDocument(frontMatter);
359
393
  if (options?.mode !== undefined && options.mode !== 'core' && options.mode !== 'references') {
360
394
  throw new TypeError(`Lima: invalid parse mode "${String(options.mode)}"`);
361
395
  }
@@ -365,15 +399,17 @@ const parseInternal = (frontMatter, options, useResolveCache) => {
365
399
  }
366
400
  // Core ignores the additional `mode` property. Passing the same object
367
401
  // avoids allocating a projected options object on this hot dispatch path.
368
- return parseCore(frontMatter, options);
402
+ return parseCoreValidated(frontMatter, options);
369
403
  }
370
404
  const partials = validatePartials(options?.partials ?? {});
371
405
  if (!frontMatter.includes('${') && !frontMatter.includes('$(')) {
372
- return parseCore(frontMatter, options);
406
+ return parseCoreValidated(frontMatter, options);
373
407
  }
374
408
  const document = parseCoreWithPositions(frontMatter, { strict: options?.strict ?? false, onWarning: options?.onWarning });
375
- const ctx = { diagnostics: [], ...(useResolveCache ? { cache: new WeakMap() } : {}) };
409
+ const ctx = newContext(useResolveCache ? new WeakMap() : undefined);
376
410
  const resolved = resolveDocument(document, partials, ctx);
411
+ if (ctx.overflowed)
412
+ throw overflowError(ctx);
377
413
  if (options?.strict)
378
414
  for (const value of resolved.values())
379
415
  scanUnresolved(value, ctx);
package/dist/scalars.js CHANGED
@@ -187,7 +187,7 @@ const parseDateUTC = (str, strict = false, line = 0) => {
187
187
  const NUMBER_RE = /^-?(?:(?:0|[1-9][0-9]*)(?:\.[0-9]+)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/;
188
188
  const DATE_PRE_RE = /\d[\d\-:.\/a-zA-Z]{4,}/;
189
189
  const isFloatForm = (str) => str.includes('.') || str.includes('e') || str.includes('E');
190
- const isZeroLiteral = (str) => /^0+(\.0+)?$/.test(str.replace(/^-/, '').split(/[eE]/)[0]);
190
+ const isZeroLiteral = (str) => /^(?:0+(?:\.0+)?|\.0+)$/.test(str.replace(/^-/, '').split(/[eE]/)[0]);
191
191
  export const NO_SPAN_VALUE = Symbol('NO_SPAN_VALUE');
192
192
  /**
193
193
  * Parses allocation-free scalar forms whose complete grammar can be proven
@@ -354,8 +354,9 @@ export const closingQuoteIndex = (s, singleQuoteEscape = true) => {
354
354
  * Kept byte-for-byte identical to `scanner.ts`'s `isKeyStartChar` /
355
355
  * `isKeyContinueChar`, which enforce the same grammar at the top level.
356
356
  */
357
- const isUnquotedKeyStart = (c) => (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 95;
358
- const isUnquotedKeyContinue = (c) => isUnquotedKeyStart(c) || c === 58 || c === 45;
357
+ import { isValidUnquotedKey } from './key-grammar.js';
358
+ const isAsciiUnquotedKeyStart = (c) => (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 95;
359
+ const isAsciiUnquotedKeyContinue = (c) => isAsciiUnquotedKeyStart(c) || c === 58 || c === 45 || c === 42;
359
360
  /**
360
361
  * Whether `raw` (a key candidate as written, before quote stripping) is a
361
362
  * usable Lima key:
@@ -375,13 +376,17 @@ export const isValidKey = (raw) => {
375
376
  const f = raw.charCodeAt(0);
376
377
  if (f === 34 || f === 39)
377
378
  return closingQuoteIndex(raw, false) === raw.length - 1;
378
- if (!isUnquotedKeyStart(f))
379
- return false;
380
- for (let i = 1; i < raw.length; i++) {
381
- if (!isUnquotedKeyContinue(raw.charCodeAt(i)))
379
+ if (f <= 0x7f) {
380
+ if (!isAsciiUnquotedKeyStart(f))
382
381
  return false;
382
+ for (let i = 1; i < raw.length; i++) {
383
+ const c = raw.charCodeAt(i);
384
+ if (!isAsciiUnquotedKeyContinue(c))
385
+ return c > 0x7f && isValidUnquotedKey(raw);
386
+ }
387
+ return true;
383
388
  }
384
- return true;
389
+ return isValidUnquotedKey(raw);
385
390
  };
386
391
  const ANY_ESCAPE_RE = /\\(u[0-9a-fA-F]{0,4}|U[0-9a-fA-F]{0,8}|x[0-9a-fA-F]{0,2}|.)/gs;
387
392
  const SINGLE_CHAR_ESCAPES = '"\\/bfnrt'; // deliberately excludes '0' — Core Appendix A: \0 is unknown, not a null shorthand.
package/dist/scanner.js CHANGED
@@ -50,8 +50,9 @@
50
50
  * U+2028 / U+2029 included, is consumed as an escape pair here and
51
51
  * resolved at decode time.
52
52
  */
53
- const isKeyStartChar = (c) => (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 95; // a-z A-Z 0-9 _
54
- const isKeyContinueChar = (c) => isKeyStartChar(c) || c === 58 || c === 45; // + : -
53
+ import { isKeyCharacterCodePoint, isKeyInitialCodePoint } from './key-grammar.js';
54
+ const isAsciiKeyStart = (c) => (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 95;
55
+ const isAsciiKeyContinue = (c) => isAsciiKeyStart(c) || c === 58 || c === 45 || c === 42;
55
56
  /** Positive = block end, negative = inline end, zero = no separator. */
56
57
  const matchSeparator = (s, pos) => {
57
58
  let i = pos;
@@ -125,11 +126,30 @@ const matchAt = (s, pos, line, out) => {
125
126
  keyKind = 2;
126
127
  }
127
128
  else {
128
- if (!isKeyStartChar(c))
129
+ if (c <= 0x7f && !isAsciiKeyStart(c))
129
130
  return false;
130
131
  let runEnd = pos + 1;
131
- while (runEnd < s.length && isKeyContinueChar(s.charCodeAt(runEnd)))
132
+ if (c > 0x7f) {
133
+ const first = s.codePointAt(pos);
134
+ if (!isKeyInitialCodePoint(first))
135
+ return false;
136
+ runEnd = pos + (first > 0xffff ? 2 : 1);
137
+ }
138
+ // Preserve the old tiny ASCII loop. Unicode decoding is entered only
139
+ // when this key actually reaches a non-ASCII code unit.
140
+ while (runEnd < s.length && isAsciiKeyContinue(s.charCodeAt(runEnd)))
132
141
  runEnd++;
142
+ while (runEnd < s.length) {
143
+ let cp = s.charCodeAt(runEnd);
144
+ if (cp <= 0x7f)
145
+ break;
146
+ cp = s.codePointAt(runEnd);
147
+ if (!isKeyCharacterCodePoint(cp))
148
+ break;
149
+ runEnd += cp > 0xffff ? 2 : 1;
150
+ while (runEnd < s.length && isAsciiKeyContinue(s.charCodeAt(runEnd)))
151
+ runEnd++;
152
+ }
133
153
  for (let k = runEnd - 1; k >= pos + 1; k--) {
134
154
  if (s.charCodeAt(k) !== 58)
135
155
  continue;
package/dist/structure.js CHANGED
@@ -15,7 +15,9 @@
15
15
  * these lines, as Core 1.0 did in both modes.
16
16
  */
17
17
  import { isTrimWhitespace } from './chars.js';
18
- import { LimaError } from './errors.js';
18
+ import { LimaError, printableLine } from './errors.js';
19
+ import { isValidUnquotedKey } from './key-grammar.js';
20
+ import { KEY_GRAMMAR_HINT, specificKeyHint } from './key-hints.js';
19
21
  /**
20
22
  * Checks the lines of `frontMatter` from `start` (a line start) to `end` that follow a key owned as `owner`; `line`
21
23
  * is the 1-based line at `start`; `valueStart` to `valueEnd` is the inline value of that key, read only for the hint a
@@ -57,7 +59,7 @@ export function checkRangeLines(frontMatter, start, end, line, owner, valueStart
57
59
  const text = frontMatter.slice(pos, stop);
58
60
  throw new LimaError({
59
61
  code: 'UNRECOGNIZED_LINE', line: current,
60
- message: `Lima: unrecognised line at line ${current}: "${text}"${hint(text)}`,
62
+ message: `Lima: unrecognised line at line ${current}: "${printableLine(text)}"${hint(text)}`,
61
63
  });
62
64
  }
63
65
  if (owner === 'mapping' && base === -1)
@@ -86,16 +88,22 @@ export const isBlockScalarMarker = (frontMatter, rawStart, lineEnd) => {
86
88
  };
87
89
  /** What a reader likely meant by an unrecognised line, as a hint after the message; none for anything else. */
88
90
  const hint = (text) => {
91
+ const specific = specificKeyHint(text);
92
+ if (specific !== undefined)
93
+ return specific;
89
94
  if (text === '---' || text === '...')
90
95
  return ' (a YAML document marker; Lima has one document)';
91
96
  if (isItem(text))
92
97
  return ' (a sequence item belongs to a key with no value of its own)';
93
98
  if (text.startsWith('"') || text.startsWith("'"))
94
99
  return ' (a quoted key closes on its own line)';
100
+ const separator = text.indexOf(': ');
101
+ if (separator >= 0 && !isValidUnquotedKey(text.slice(0, separator)))
102
+ return KEY_GRAMMAR_HINT;
95
103
  // `author Odile`, `key:value`: key characters, but no ": " after them
96
- if (!text.includes(':') || /^[a-zA-Z0-9_][a-zA-Z0-9_:-]*$/.test(text.split(' ')[0]))
104
+ if (!text.includes(':') || isValidUnquotedKey(text.split(' ')[0]))
97
105
  return ' (a key needs ": " after it)';
98
- return ' (an unquoted key has letters, digits, "_", "-" and ":" only; quote any other)';
106
+ return KEY_GRAMMAR_HINT;
99
107
  };
100
108
  /** The hint a YAML block scalar marker in place of a value earns; none for any other value. */
101
109
  const yamlHint = (value) => {
@@ -0,0 +1 @@
1
+ export declare const UNICODE_KEY_RANGES: Uint32Array<ArrayBuffer>;
@@ -0,0 +1,245 @@
1
+ // Generated from UnicodeData.txt 18.0.0; DO NOT EDIT.
2
+ // SHA-256: 0736451de439ae7baf1425136617da495e09ee5afbe6e394374db7009ea08950
3
+ // Regenerate: bun scripts/generate-unicode-key-tables.ts /path/to/UnicodeData.txt
4
+ export const UNICODE_KEY_RANGES = new Uint32Array([
5
+ 0xAA, 0xAA, 0x1, 0xB2, 0xB3, 0x4, 0xB5, 0xB5, 0x1, 0xB9, 0xB9, 0x4, 0xBA, 0xBA, 0x1, 0xBC, 0xBE, 0x4, 0xC0,
6
+ 0xD6, 0x1, 0xD8, 0xF6, 0x1, 0xF8, 0x2C1, 0x1, 0x2C6, 0x2D1, 0x1, 0x2E0, 0x2E4, 0x1, 0x2EC, 0x2EC, 0x1,
7
+ 0x2EE, 0x2EE, 0x1, 0x300, 0x36F, 0x2, 0x370, 0x374, 0x1, 0x376, 0x377, 0x1, 0x37A, 0x37D, 0x1, 0x37F, 0x37F,
8
+ 0x1, 0x386, 0x386, 0x1, 0x388, 0x38A, 0x1, 0x38C, 0x38C, 0x1, 0x38E, 0x3A1, 0x1, 0x3A3, 0x3F5, 0x1, 0x3F7,
9
+ 0x481, 0x1, 0x483, 0x489, 0x2, 0x48A, 0x52F, 0x1, 0x531, 0x556, 0x1, 0x558, 0x559, 0x1, 0x560, 0x588, 0x1,
10
+ 0x58B, 0x58C, 0x1, 0x591, 0x5BD, 0x2, 0x5BF, 0x5BF, 0x2, 0x5C1, 0x5C2, 0x2, 0x5C4, 0x5C5, 0x2, 0x5C7, 0x5C9,
11
+ 0x2, 0x5D0, 0x5EA, 0x1, 0x5EF, 0x5F2, 0x1, 0x610, 0x61A, 0x2, 0x620, 0x64A, 0x1, 0x64B, 0x65F, 0x2, 0x660,
12
+ 0x669, 0x4, 0x66E, 0x66F, 0x1, 0x670, 0x670, 0x2, 0x671, 0x6D3, 0x1, 0x6D5, 0x6D5, 0x1, 0x6D6, 0x6DC, 0x2,
13
+ 0x6DF, 0x6E4, 0x2, 0x6E5, 0x6E6, 0x1, 0x6E7, 0x6E8, 0x2, 0x6EA, 0x6ED, 0x2, 0x6EE, 0x6EF, 0x1, 0x6F0, 0x6F9,
14
+ 0x4, 0x6FA, 0x6FC, 0x1, 0x6FF, 0x6FF, 0x1, 0x710, 0x710, 0x1, 0x711, 0x711, 0x2, 0x712, 0x72F, 0x1, 0x730,
15
+ 0x74A, 0x2, 0x74D, 0x7A5, 0x1, 0x7A6, 0x7B0, 0x2, 0x7B1, 0x7B1, 0x1, 0x7C0, 0x7C9, 0x4, 0x7CA, 0x7EA, 0x1,
16
+ 0x7EB, 0x7F3, 0x2, 0x7F4, 0x7F5, 0x1, 0x7FA, 0x7FA, 0x1, 0x7FD, 0x7FD, 0x2, 0x800, 0x815, 0x1, 0x816, 0x819,
17
+ 0x2, 0x81A, 0x81A, 0x1, 0x81B, 0x823, 0x2, 0x824, 0x824, 0x1, 0x825, 0x827, 0x2, 0x828, 0x828, 0x1, 0x829,
18
+ 0x82D, 0x2, 0x840, 0x858, 0x1, 0x859, 0x85B, 0x2, 0x860, 0x86A, 0x1, 0x870, 0x887, 0x1, 0x889, 0x88F, 0x1,
19
+ 0x897, 0x89F, 0x2, 0x8A0, 0x8C9, 0x1, 0x8CA, 0x8E1, 0x2, 0x8E3, 0x903, 0x2, 0x904, 0x939, 0x1, 0x93A, 0x93C,
20
+ 0x2, 0x93D, 0x93D, 0x1, 0x93E, 0x94F, 0x2, 0x950, 0x950, 0x1, 0x951, 0x957, 0x2, 0x958, 0x961, 0x1, 0x962,
21
+ 0x963, 0x2, 0x966, 0x96F, 0x4, 0x971, 0x980, 0x1, 0x981, 0x983, 0x2, 0x985, 0x98C, 0x1, 0x98F, 0x990, 0x1,
22
+ 0x993, 0x9A8, 0x1, 0x9AA, 0x9B0, 0x1, 0x9B2, 0x9B2, 0x1, 0x9B6, 0x9B9, 0x1, 0x9BC, 0x9BC, 0x2, 0x9BD, 0x9BD,
23
+ 0x1, 0x9BE, 0x9C4, 0x2, 0x9C7, 0x9C8, 0x2, 0x9CB, 0x9CD, 0x2, 0x9CE, 0x9CE, 0x1, 0x9D7, 0x9D7, 0x2, 0x9DC,
24
+ 0x9DD, 0x1, 0x9DF, 0x9E1, 0x1, 0x9E2, 0x9E3, 0x2, 0x9E6, 0x9EF, 0x4, 0x9F0, 0x9F1, 0x1, 0x9F4, 0x9F9, 0x4,
25
+ 0x9FC, 0x9FC, 0x1, 0x9FE, 0x9FE, 0x2, 0xA01, 0xA03, 0x2, 0xA05, 0xA0A, 0x1, 0xA0F, 0xA10, 0x1, 0xA13, 0xA28,
26
+ 0x1, 0xA2A, 0xA30, 0x1, 0xA32, 0xA33, 0x1, 0xA35, 0xA36, 0x1, 0xA38, 0xA39, 0x1, 0xA3C, 0xA3C, 0x2, 0xA3E,
27
+ 0xA42, 0x2, 0xA47, 0xA48, 0x2, 0xA4B, 0xA4D, 0x2, 0xA51, 0xA51, 0x2, 0xA59, 0xA5C, 0x1, 0xA5E, 0xA5E, 0x1,
28
+ 0xA66, 0xA6F, 0x4, 0xA70, 0xA71, 0x2, 0xA72, 0xA74, 0x1, 0xA75, 0xA75, 0x2, 0xA81, 0xA83, 0x2, 0xA85, 0xA8D,
29
+ 0x1, 0xA8F, 0xA91, 0x1, 0xA93, 0xAA8, 0x1, 0xAAA, 0xAB0, 0x1, 0xAB2, 0xAB3, 0x1, 0xAB5, 0xAB9, 0x1, 0xABC,
30
+ 0xABC, 0x2, 0xABD, 0xABD, 0x1, 0xABE, 0xAC5, 0x2, 0xAC7, 0xAC9, 0x2, 0xACB, 0xACD, 0x2, 0xAD0, 0xAD0, 0x1,
31
+ 0xAE0, 0xAE1, 0x1, 0xAE2, 0xAE3, 0x2, 0xAE6, 0xAEF, 0x4, 0xAF9, 0xAF9, 0x1, 0xAFA, 0xAFF, 0x2, 0xB01, 0xB03,
32
+ 0x2, 0xB05, 0xB0C, 0x1, 0xB0F, 0xB10, 0x1, 0xB13, 0xB28, 0x1, 0xB2A, 0xB30, 0x1, 0xB32, 0xB33, 0x1, 0xB35,
33
+ 0xB39, 0x1, 0xB3C, 0xB3C, 0x2, 0xB3D, 0xB3D, 0x1, 0xB3E, 0xB44, 0x2, 0xB47, 0xB48, 0x2, 0xB4B, 0xB4D, 0x2,
34
+ 0xB53, 0xB57, 0x2, 0xB5C, 0xB5D, 0x1, 0xB5F, 0xB61, 0x1, 0xB62, 0xB63, 0x2, 0xB66, 0xB6F, 0x4, 0xB71, 0xB71,
35
+ 0x1, 0xB72, 0xB77, 0x4, 0xB82, 0xB82, 0x2, 0xB83, 0xB83, 0x1, 0xB85, 0xB8A, 0x1, 0xB8E, 0xB90, 0x1, 0xB92,
36
+ 0xB95, 0x1, 0xB99, 0xB9A, 0x1, 0xB9C, 0xB9C, 0x1, 0xB9E, 0xB9F, 0x1, 0xBA3, 0xBA4, 0x1, 0xBA8, 0xBAA, 0x1,
37
+ 0xBAE, 0xBB9, 0x1, 0xBBE, 0xBC2, 0x2, 0xBC6, 0xBC8, 0x2, 0xBCA, 0xBCD, 0x2, 0xBD0, 0xBD0, 0x1, 0xBD7, 0xBD7,
38
+ 0x2, 0xBE6, 0xBF2, 0x4, 0xC00, 0xC04, 0x2, 0xC05, 0xC0C, 0x1, 0xC0E, 0xC10, 0x1, 0xC12, 0xC28, 0x1, 0xC2A,
39
+ 0xC39, 0x1, 0xC3C, 0xC3C, 0x2, 0xC3D, 0xC3D, 0x1, 0xC3E, 0xC44, 0x2, 0xC46, 0xC48, 0x2, 0xC4A, 0xC4D, 0x2,
40
+ 0xC55, 0xC56, 0x2, 0xC58, 0xC5A, 0x1, 0xC5C, 0xC5D, 0x1, 0xC60, 0xC61, 0x1, 0xC62, 0xC63, 0x2, 0xC66, 0xC6F,
41
+ 0x4, 0xC78, 0xC7E, 0x4, 0xC80, 0xC80, 0x1, 0xC81, 0xC83, 0x2, 0xC85, 0xC8C, 0x1, 0xC8E, 0xC90, 0x1, 0xC92,
42
+ 0xCA8, 0x1, 0xCAA, 0xCB3, 0x1, 0xCB5, 0xCB9, 0x1, 0xCBC, 0xCBC, 0x2, 0xCBD, 0xCBD, 0x1, 0xCBE, 0xCC4, 0x2,
43
+ 0xCC6, 0xCC8, 0x2, 0xCCA, 0xCCD, 0x2, 0xCD5, 0xCD6, 0x2, 0xCDC, 0xCDE, 0x1, 0xCE0, 0xCE1, 0x1, 0xCE2, 0xCE3,
44
+ 0x2, 0xCE6, 0xCEF, 0x4, 0xCF1, 0xCF2, 0x1, 0xCF3, 0xCF3, 0x2, 0xD00, 0xD03, 0x2, 0xD04, 0xD0C, 0x1, 0xD0E,
45
+ 0xD10, 0x1, 0xD12, 0xD3A, 0x1, 0xD3B, 0xD3C, 0x2, 0xD3D, 0xD3D, 0x1, 0xD3E, 0xD44, 0x2, 0xD46, 0xD48, 0x2,
46
+ 0xD4A, 0xD4D, 0x2, 0xD4E, 0xD4E, 0x1, 0xD54, 0xD56, 0x1, 0xD57, 0xD57, 0x2, 0xD58, 0xD5E, 0x4, 0xD5F, 0xD61,
47
+ 0x1, 0xD62, 0xD63, 0x2, 0xD66, 0xD78, 0x4, 0xD7A, 0xD7F, 0x1, 0xD81, 0xD83, 0x2, 0xD85, 0xD96, 0x1, 0xD9A,
48
+ 0xDB1, 0x1, 0xDB3, 0xDBB, 0x1, 0xDBD, 0xDBD, 0x1, 0xDC0, 0xDC6, 0x1, 0xDCA, 0xDCA, 0x2, 0xDCF, 0xDD4, 0x2,
49
+ 0xDD6, 0xDD6, 0x2, 0xDD8, 0xDDF, 0x2, 0xDE6, 0xDEF, 0x4, 0xDF2, 0xDF3, 0x2, 0xE01, 0xE30, 0x1, 0xE31, 0xE31,
50
+ 0x2, 0xE32, 0xE33, 0x1, 0xE34, 0xE3A, 0x2, 0xE40, 0xE46, 0x1, 0xE47, 0xE4E, 0x2, 0xE50, 0xE59, 0x4, 0xE81,
51
+ 0xE82, 0x1, 0xE84, 0xE84, 0x1, 0xE86, 0xE8A, 0x1, 0xE8C, 0xEA3, 0x1, 0xEA5, 0xEA5, 0x1, 0xEA7, 0xEB0, 0x1,
52
+ 0xEB1, 0xEB1, 0x2, 0xEB2, 0xEB3, 0x1, 0xEB4, 0xEBC, 0x2, 0xEBD, 0xEBD, 0x1, 0xEC0, 0xEC4, 0x1, 0xEC6, 0xEC6,
53
+ 0x1, 0xEC8, 0xECE, 0x2, 0xED0, 0xED9, 0x4, 0xEDC, 0xEDF, 0x1, 0xF00, 0xF00, 0x1, 0xF18, 0xF19, 0x2, 0xF20,
54
+ 0xF33, 0x4, 0xF35, 0xF35, 0x2, 0xF37, 0xF37, 0x2, 0xF39, 0xF39, 0x2, 0xF3E, 0xF3F, 0x2, 0xF40, 0xF47, 0x1,
55
+ 0xF49, 0xF6C, 0x1, 0xF71, 0xF84, 0x2, 0xF86, 0xF87, 0x2, 0xF88, 0xF8C, 0x1, 0xF8D, 0xF97, 0x2, 0xF99, 0xFBC,
56
+ 0x2, 0xFC6, 0xFC6, 0x2, 0x1000, 0x102A, 0x1, 0x102B, 0x103E, 0x2, 0x103F, 0x103F, 0x1, 0x1040, 0x1049, 0x4,
57
+ 0x1050, 0x1055, 0x1, 0x1056, 0x1059, 0x2, 0x105A, 0x105D, 0x1, 0x105E, 0x1060, 0x2, 0x1061, 0x1061, 0x1,
58
+ 0x1062, 0x1064, 0x2, 0x1065, 0x1066, 0x1, 0x1067, 0x106D, 0x2, 0x106E, 0x1070, 0x1, 0x1071, 0x1074, 0x2,
59
+ 0x1075, 0x1081, 0x1, 0x1082, 0x108D, 0x2, 0x108E, 0x108E, 0x1, 0x108F, 0x108F, 0x2, 0x1090, 0x1099, 0x4,
60
+ 0x109A, 0x109D, 0x2, 0x10A0, 0x10C5, 0x1, 0x10C7, 0x10C7, 0x1, 0x10CD, 0x10CD, 0x1, 0x10D0, 0x10FA, 0x1,
61
+ 0x10FC, 0x1248, 0x1, 0x124A, 0x124D, 0x1, 0x1250, 0x1256, 0x1, 0x1258, 0x1258, 0x1, 0x125A, 0x125D, 0x1,
62
+ 0x1260, 0x1288, 0x1, 0x128A, 0x128D, 0x1, 0x1290, 0x12B0, 0x1, 0x12B2, 0x12B5, 0x1, 0x12B8, 0x12BE, 0x1,
63
+ 0x12C0, 0x12C0, 0x1, 0x12C2, 0x12C5, 0x1, 0x12C8, 0x12D6, 0x1, 0x12D8, 0x1310, 0x1, 0x1312, 0x1315, 0x1,
64
+ 0x1318, 0x135A, 0x1, 0x135D, 0x135F, 0x2, 0x1369, 0x137C, 0x4, 0x1380, 0x138F, 0x1, 0x13A0, 0x13F5, 0x1,
65
+ 0x13F8, 0x13FD, 0x1, 0x1401, 0x166C, 0x1, 0x166F, 0x167F, 0x1, 0x1681, 0x169A, 0x1, 0x16A0, 0x16EA, 0x1,
66
+ 0x16EE, 0x16F0, 0x4, 0x16F1, 0x16F8, 0x1, 0x1700, 0x1711, 0x1, 0x1712, 0x1715, 0x2, 0x171F, 0x1731, 0x1,
67
+ 0x1732, 0x1734, 0x2, 0x1740, 0x1751, 0x1, 0x1752, 0x1753, 0x2, 0x1760, 0x176C, 0x1, 0x176E, 0x1770, 0x1,
68
+ 0x1772, 0x1773, 0x2, 0x1780, 0x17B3, 0x1, 0x17B4, 0x17D3, 0x2, 0x17D7, 0x17D7, 0x1, 0x17DC, 0x17DC, 0x1,
69
+ 0x17DD, 0x17DD, 0x2, 0x17E0, 0x17E9, 0x4, 0x17F0, 0x17F9, 0x4, 0x180B, 0x180D, 0x2, 0x180F, 0x180F, 0x2,
70
+ 0x1810, 0x1819, 0x4, 0x1820, 0x1878, 0x1, 0x1880, 0x1884, 0x1, 0x1885, 0x1886, 0x2, 0x1887, 0x18A8, 0x1,
71
+ 0x18A9, 0x18A9, 0x2, 0x18AA, 0x18AA, 0x1, 0x18B0, 0x18F5, 0x1, 0x1900, 0x191E, 0x1, 0x1920, 0x192B, 0x2,
72
+ 0x1930, 0x193B, 0x2, 0x1946, 0x194F, 0x4, 0x1950, 0x196D, 0x1, 0x1970, 0x1974, 0x1, 0x1980, 0x19AB, 0x1,
73
+ 0x19B0, 0x19C9, 0x1, 0x19D0, 0x19DA, 0x4, 0x1A00, 0x1A16, 0x1, 0x1A17, 0x1A1B, 0x2, 0x1A20, 0x1A54, 0x1,
74
+ 0x1A55, 0x1A5E, 0x2, 0x1A60, 0x1A7C, 0x2, 0x1A7F, 0x1A7F, 0x2, 0x1A80, 0x1A89, 0x4, 0x1A90, 0x1A99, 0x4,
75
+ 0x1AA7, 0x1AA7, 0x1, 0x1AB0, 0x1AF0, 0x2, 0x1B00, 0x1B04, 0x2, 0x1B05, 0x1B33, 0x1, 0x1B34, 0x1B44, 0x2,
76
+ 0x1B45, 0x1B4C, 0x1, 0x1B50, 0x1B59, 0x4, 0x1B6B, 0x1B73, 0x2, 0x1B80, 0x1B82, 0x2, 0x1B83, 0x1BA0, 0x1,
77
+ 0x1BA1, 0x1BAD, 0x2, 0x1BAE, 0x1BAF, 0x1, 0x1BB0, 0x1BB9, 0x4, 0x1BBA, 0x1BE5, 0x1, 0x1BE6, 0x1BF3, 0x2,
78
+ 0x1C00, 0x1C23, 0x1, 0x1C24, 0x1C37, 0x2, 0x1C40, 0x1C49, 0x4, 0x1C4D, 0x1C4F, 0x1, 0x1C50, 0x1C59, 0x4,
79
+ 0x1C5A, 0x1C7D, 0x1, 0x1C80, 0x1C8A, 0x1, 0x1C90, 0x1CBA, 0x1, 0x1CBD, 0x1CBF, 0x1, 0x1CD0, 0x1CD2, 0x2,
80
+ 0x1CD4, 0x1CE8, 0x2, 0x1CE9, 0x1CEC, 0x1, 0x1CED, 0x1CED, 0x2, 0x1CEE, 0x1CF3, 0x1, 0x1CF4, 0x1CF4, 0x2,
81
+ 0x1CF5, 0x1CF6, 0x1, 0x1CF7, 0x1CF9, 0x2, 0x1CFA, 0x1CFA, 0x1, 0x1D00, 0x1DBF, 0x1, 0x1DC0, 0x1DFF, 0x2,
82
+ 0x1E00, 0x1F15, 0x1, 0x1F18, 0x1F1D, 0x1, 0x1F20, 0x1F45, 0x1, 0x1F48, 0x1F4D, 0x1, 0x1F50, 0x1F57, 0x1,
83
+ 0x1F59, 0x1F59, 0x1, 0x1F5B, 0x1F5B, 0x1, 0x1F5D, 0x1F5D, 0x1, 0x1F5F, 0x1F7D, 0x1, 0x1F80, 0x1FB4, 0x1,
84
+ 0x1FB6, 0x1FBC, 0x1, 0x1FBE, 0x1FBE, 0x1, 0x1FC2, 0x1FC4, 0x1, 0x1FC6, 0x1FCC, 0x1, 0x1FD0, 0x1FD3, 0x1,
85
+ 0x1FD6, 0x1FDB, 0x1, 0x1FE0, 0x1FEC, 0x1, 0x1FF2, 0x1FF4, 0x1, 0x1FF6, 0x1FFC, 0x1, 0x2070, 0x2070, 0x4,
86
+ 0x2071, 0x2071, 0x1, 0x2074, 0x2079, 0x4, 0x207F, 0x207F, 0x1, 0x2080, 0x2089, 0x4, 0x208F, 0x209F, 0x1,
87
+ 0x20D0, 0x20F0, 0x2, 0x2102, 0x2102, 0x1, 0x2107, 0x2107, 0x1, 0x210A, 0x2113, 0x1, 0x2115, 0x2115, 0x1,
88
+ 0x2119, 0x211D, 0x1, 0x2124, 0x2124, 0x1, 0x2126, 0x2126, 0x1, 0x2128, 0x2128, 0x1, 0x212A, 0x212D, 0x1,
89
+ 0x212F, 0x2139, 0x1, 0x213C, 0x213F, 0x1, 0x2145, 0x2149, 0x1, 0x214E, 0x214E, 0x1, 0x2150, 0x2182, 0x4,
90
+ 0x2183, 0x2184, 0x1, 0x2185, 0x2189, 0x4, 0x2460, 0x249B, 0x4, 0x24EA, 0x24FF, 0x4, 0x2776, 0x2793, 0x4,
91
+ 0x2C00, 0x2CE4, 0x1, 0x2CEB, 0x2CEE, 0x1, 0x2CEF, 0x2CF1, 0x2, 0x2CF2, 0x2CF3, 0x1, 0x2CFD, 0x2CFD, 0x4,
92
+ 0x2D00, 0x2D25, 0x1, 0x2D27, 0x2D27, 0x1, 0x2D2D, 0x2D2D, 0x1, 0x2D30, 0x2D67, 0x1, 0x2D6F, 0x2D6F, 0x1,
93
+ 0x2D7F, 0x2D7F, 0x2, 0x2D80, 0x2D96, 0x1, 0x2DA0, 0x2DA6, 0x1, 0x2DA8, 0x2DAE, 0x1, 0x2DB0, 0x2DB6, 0x1,
94
+ 0x2DB8, 0x2DBE, 0x1, 0x2DC0, 0x2DC6, 0x1, 0x2DC8, 0x2DCE, 0x1, 0x2DD0, 0x2DD6, 0x1, 0x2DD8, 0x2DDE, 0x1,
95
+ 0x2DE0, 0x2DFF, 0x2, 0x2E2F, 0x2E2F, 0x1, 0x3005, 0x3006, 0x1, 0x3007, 0x3007, 0x4, 0x3021, 0x3029, 0x4,
96
+ 0x302A, 0x302F, 0x2, 0x3031, 0x3035, 0x1, 0x3038, 0x303A, 0x4, 0x303B, 0x303C, 0x1, 0x3041, 0x3096, 0x1,
97
+ 0x3099, 0x309A, 0x2, 0x309D, 0x309F, 0x1, 0x30A1, 0x30FA, 0x1, 0x30FC, 0x30FF, 0x1, 0x3105, 0x312F, 0x1,
98
+ 0x3131, 0x318E, 0x1, 0x3192, 0x3195, 0x4, 0x31A0, 0x31BF, 0x1, 0x31F0, 0x31FF, 0x1, 0x3220, 0x3229, 0x4,
99
+ 0x3248, 0x324F, 0x4, 0x3251, 0x325F, 0x4, 0x3280, 0x3289, 0x4, 0x32B1, 0x32BF, 0x4, 0x3400, 0x4DBF, 0x1,
100
+ 0x4E00, 0xA48C, 0x1, 0xA4D0, 0xA4FD, 0x1, 0xA500, 0xA60C, 0x1, 0xA610, 0xA61F, 0x1, 0xA620, 0xA629, 0x4,
101
+ 0xA62A, 0xA62B, 0x1, 0xA640, 0xA66E, 0x1, 0xA66F, 0xA672, 0x2, 0xA674, 0xA67D, 0x2, 0xA67F, 0xA69D, 0x1,
102
+ 0xA69E, 0xA69F, 0x2, 0xA6A0, 0xA6E5, 0x1, 0xA6E6, 0xA6EF, 0x4, 0xA6F0, 0xA6F1, 0x2, 0xA717, 0xA71F, 0x1,
103
+ 0xA722, 0xA788, 0x1, 0xA78B, 0xA7DD, 0x1, 0xA7E2, 0xA7E2, 0x1, 0xA7F1, 0xA801, 0x1, 0xA802, 0xA802, 0x2,
104
+ 0xA803, 0xA805, 0x1, 0xA806, 0xA806, 0x2, 0xA807, 0xA80A, 0x1, 0xA80B, 0xA80B, 0x2, 0xA80C, 0xA822, 0x1,
105
+ 0xA823, 0xA827, 0x2, 0xA82C, 0xA82C, 0x2, 0xA830, 0xA835, 0x4, 0xA840, 0xA873, 0x1, 0xA880, 0xA881, 0x2,
106
+ 0xA882, 0xA8B3, 0x1, 0xA8B4, 0xA8C5, 0x2, 0xA8D0, 0xA8D9, 0x4, 0xA8E0, 0xA8F1, 0x2, 0xA8F2, 0xA8F7, 0x1,
107
+ 0xA8FB, 0xA8FB, 0x1, 0xA8FD, 0xA8FE, 0x1, 0xA8FF, 0xA8FF, 0x2, 0xA900, 0xA909, 0x4, 0xA90A, 0xA925, 0x1,
108
+ 0xA926, 0xA92D, 0x2, 0xA930, 0xA946, 0x1, 0xA947, 0xA953, 0x2, 0xA960, 0xA97C, 0x1, 0xA980, 0xA983, 0x2,
109
+ 0xA984, 0xA9B2, 0x1, 0xA9B3, 0xA9C0, 0x2, 0xA9CF, 0xA9CF, 0x1, 0xA9D0, 0xA9D9, 0x4, 0xA9E0, 0xA9E4, 0x1,
110
+ 0xA9E5, 0xA9E5, 0x2, 0xA9E6, 0xA9EF, 0x1, 0xA9F0, 0xA9F9, 0x4, 0xA9FA, 0xA9FE, 0x1, 0xAA00, 0xAA28, 0x1,
111
+ 0xAA29, 0xAA36, 0x2, 0xAA40, 0xAA42, 0x1, 0xAA43, 0xAA43, 0x2, 0xAA44, 0xAA4B, 0x1, 0xAA4C, 0xAA4D, 0x2,
112
+ 0xAA50, 0xAA59, 0x4, 0xAA60, 0xAA76, 0x1, 0xAA7A, 0xAA7A, 0x1, 0xAA7B, 0xAA7D, 0x2, 0xAA7E, 0xAAAF, 0x1,
113
+ 0xAAB0, 0xAAB0, 0x2, 0xAAB1, 0xAAB1, 0x1, 0xAAB2, 0xAAB4, 0x2, 0xAAB5, 0xAAB6, 0x1, 0xAAB7, 0xAAB8, 0x2,
114
+ 0xAAB9, 0xAABD, 0x1, 0xAABE, 0xAABF, 0x2, 0xAAC0, 0xAAC0, 0x1, 0xAAC1, 0xAAC1, 0x2, 0xAAC2, 0xAAC2, 0x1,
115
+ 0xAADB, 0xAADD, 0x1, 0xAAE0, 0xAAEA, 0x1, 0xAAEB, 0xAAEF, 0x2, 0xAAF2, 0xAAF4, 0x1, 0xAAF5, 0xAAF6, 0x2,
116
+ 0xAB01, 0xAB06, 0x1, 0xAB09, 0xAB0E, 0x1, 0xAB11, 0xAB16, 0x1, 0xAB20, 0xAB26, 0x1, 0xAB28, 0xAB2E, 0x1,
117
+ 0xAB30, 0xAB5A, 0x1, 0xAB5C, 0xAB69, 0x1, 0xAB6C, 0xAB6D, 0x1, 0xAB70, 0xABE2, 0x1, 0xABE3, 0xABEA, 0x2,
118
+ 0xABEC, 0xABED, 0x2, 0xABF0, 0xABF9, 0x4, 0xAC00, 0xD7A3, 0x1, 0xD7B0, 0xD7C6, 0x1, 0xD7CB, 0xD7FB, 0x1,
119
+ 0xF900, 0xFA6D, 0x1, 0xFA70, 0xFAD9, 0x1, 0xFB00, 0xFB06, 0x1, 0xFB13, 0xFB17, 0x1, 0xFB1D, 0xFB1D, 0x1,
120
+ 0xFB1E, 0xFB1E, 0x2, 0xFB1F, 0xFB28, 0x1, 0xFB2A, 0xFB36, 0x1, 0xFB38, 0xFB3C, 0x1, 0xFB3E, 0xFB3E, 0x1,
121
+ 0xFB40, 0xFB41, 0x1, 0xFB43, 0xFB44, 0x1, 0xFB46, 0xFBB1, 0x1, 0xFBD3, 0xFD3D, 0x1, 0xFD50, 0xFD8F, 0x1,
122
+ 0xFD92, 0xFDC7, 0x1, 0xFDF0, 0xFDFB, 0x1, 0xFE00, 0xFE0F, 0x2, 0xFE20, 0xFE2F, 0x2, 0xFE70, 0xFE74, 0x1,
123
+ 0xFE76, 0xFEFC, 0x1, 0xFF10, 0xFF19, 0x4, 0xFF21, 0xFF3A, 0x1, 0xFF41, 0xFF5A, 0x1, 0xFF66, 0xFFBE, 0x1,
124
+ 0xFFC2, 0xFFC7, 0x1, 0xFFCA, 0xFFCF, 0x1, 0xFFD2, 0xFFD7, 0x1, 0xFFDA, 0xFFDC, 0x1, 0x10000, 0x1000B, 0x1,
125
+ 0x1000D, 0x10026, 0x1, 0x10028, 0x1003A, 0x1, 0x1003C, 0x1003D, 0x1, 0x1003F, 0x1004D, 0x1, 0x10050,
126
+ 0x1005D, 0x1, 0x10080, 0x100FA, 0x1, 0x10107, 0x10133, 0x4, 0x10140, 0x10178, 0x4, 0x1018A, 0x1018B, 0x4,
127
+ 0x101FD, 0x101FD, 0x2, 0x10280, 0x1029C, 0x1, 0x102A0, 0x102D0, 0x1, 0x102E0, 0x102E0, 0x2, 0x102E1,
128
+ 0x102FB, 0x4, 0x10300, 0x1031F, 0x1, 0x10320, 0x10323, 0x4, 0x1032D, 0x10340, 0x1, 0x10341, 0x10341, 0x4,
129
+ 0x10342, 0x10349, 0x1, 0x1034A, 0x1034A, 0x4, 0x10350, 0x10375, 0x1, 0x10376, 0x1037A, 0x2, 0x10380,
130
+ 0x1039D, 0x1, 0x103A0, 0x103C3, 0x1, 0x103C8, 0x103CF, 0x1, 0x103D1, 0x103D5, 0x4, 0x10400, 0x1049D, 0x1,
131
+ 0x104A0, 0x104A9, 0x4, 0x104B0, 0x104D3, 0x1, 0x104D8, 0x104FB, 0x1, 0x10500, 0x10527, 0x1, 0x10530,
132
+ 0x10563, 0x1, 0x10570, 0x1057A, 0x1, 0x1057C, 0x1058A, 0x1, 0x1058C, 0x10592, 0x1, 0x10594, 0x10595, 0x1,
133
+ 0x10597, 0x105A1, 0x1, 0x105A3, 0x105B1, 0x1, 0x105B3, 0x105B9, 0x1, 0x105BB, 0x105BC, 0x1, 0x105C0,
134
+ 0x105F3, 0x1, 0x10600, 0x10736, 0x1, 0x10740, 0x10755, 0x1, 0x10760, 0x10767, 0x1, 0x10780, 0x10785, 0x1,
135
+ 0x10787, 0x107B0, 0x1, 0x107B2, 0x107BF, 0x1, 0x10800, 0x10805, 0x1, 0x10808, 0x10808, 0x1, 0x1080A,
136
+ 0x10835, 0x1, 0x10837, 0x10838, 0x1, 0x1083C, 0x1083C, 0x1, 0x1083F, 0x10855, 0x1, 0x10858, 0x1085F, 0x4,
137
+ 0x10860, 0x10876, 0x1, 0x10879, 0x1087F, 0x4, 0x10880, 0x1089E, 0x1, 0x108A7, 0x108AF, 0x4, 0x108E0,
138
+ 0x108F2, 0x1, 0x108F4, 0x108F5, 0x1, 0x108FB, 0x108FF, 0x4, 0x10900, 0x10915, 0x1, 0x10916, 0x1091B, 0x4,
139
+ 0x10920, 0x10939, 0x1, 0x10940, 0x10959, 0x1, 0x10980, 0x109B7, 0x1, 0x109BC, 0x109BD, 0x4, 0x109BE,
140
+ 0x109BF, 0x1, 0x109C0, 0x109CF, 0x4, 0x109D2, 0x109FF, 0x4, 0x10A00, 0x10A00, 0x1, 0x10A01, 0x10A03, 0x2,
141
+ 0x10A05, 0x10A06, 0x2, 0x10A0C, 0x10A0F, 0x2, 0x10A10, 0x10A13, 0x1, 0x10A15, 0x10A17, 0x1, 0x10A19,
142
+ 0x10A35, 0x1, 0x10A38, 0x10A3A, 0x2, 0x10A3F, 0x10A3F, 0x2, 0x10A40, 0x10A48, 0x4, 0x10A60, 0x10A7C, 0x1,
143
+ 0x10A7D, 0x10A7E, 0x4, 0x10A80, 0x10A9C, 0x1, 0x10A9D, 0x10A9F, 0x4, 0x10AC0, 0x10AC7, 0x1, 0x10AC9,
144
+ 0x10AE4, 0x1, 0x10AE5, 0x10AE6, 0x2, 0x10AEB, 0x10AEF, 0x4, 0x10B00, 0x10B35, 0x1, 0x10B40, 0x10B55, 0x1,
145
+ 0x10B58, 0x10B5F, 0x4, 0x10B60, 0x10B72, 0x1, 0x10B78, 0x10B7F, 0x4, 0x10B80, 0x10B91, 0x1, 0x10BA9,
146
+ 0x10BAF, 0x4, 0x10C00, 0x10C48, 0x1, 0x10C80, 0x10CB2, 0x1, 0x10CC0, 0x10CF2, 0x1, 0x10CFA, 0x10CFF, 0x4,
147
+ 0x10D00, 0x10D23, 0x1, 0x10D24, 0x10D27, 0x2, 0x10D30, 0x10D39, 0x4, 0x10D40, 0x10D49, 0x4, 0x10D4A,
148
+ 0x10D65, 0x1, 0x10D69, 0x10D6D, 0x2, 0x10D6F, 0x10D85, 0x1, 0x10E60, 0x10E7E, 0x4, 0x10E80, 0x10EA9, 0x1,
149
+ 0x10EAB, 0x10EAC, 0x2, 0x10EB0, 0x10EB1, 0x1, 0x10EC2, 0x10EC7, 0x1, 0x10ECB, 0x10ECF, 0x2, 0x10ED9,
150
+ 0x10EEE, 0x1, 0x10EF0, 0x10EFF, 0x2, 0x10F00, 0x10F1C, 0x1, 0x10F1D, 0x10F26, 0x4, 0x10F27, 0x10F27, 0x1,
151
+ 0x10F30, 0x10F45, 0x1, 0x10F46, 0x10F50, 0x2, 0x10F51, 0x10F54, 0x4, 0x10F70, 0x10F81, 0x1, 0x10F82,
152
+ 0x10F85, 0x2, 0x10FB0, 0x10FC4, 0x1, 0x10FC5, 0x10FCB, 0x4, 0x10FE0, 0x10FF6, 0x1, 0x11000, 0x11002, 0x2,
153
+ 0x11003, 0x11037, 0x1, 0x11038, 0x11046, 0x2, 0x11052, 0x1106F, 0x4, 0x11070, 0x11070, 0x2, 0x11071,
154
+ 0x11072, 0x1, 0x11073, 0x11074, 0x2, 0x11075, 0x11075, 0x1, 0x1107F, 0x11082, 0x2, 0x11083, 0x110AF, 0x1,
155
+ 0x110B0, 0x110BA, 0x2, 0x110C2, 0x110C2, 0x2, 0x110D0, 0x110E8, 0x1, 0x110F0, 0x110F9, 0x4, 0x11100,
156
+ 0x11102, 0x2, 0x11103, 0x11126, 0x1, 0x11127, 0x11134, 0x2, 0x11136, 0x1113F, 0x4, 0x11144, 0x11144, 0x1,
157
+ 0x11145, 0x11146, 0x2, 0x11147, 0x11147, 0x1, 0x11150, 0x11172, 0x1, 0x11173, 0x11173, 0x2, 0x11176,
158
+ 0x11176, 0x1, 0x11180, 0x11182, 0x2, 0x11183, 0x111B2, 0x1, 0x111B3, 0x111C0, 0x2, 0x111C1, 0x111C4, 0x1,
159
+ 0x111C9, 0x111CC, 0x2, 0x111CE, 0x111CF, 0x2, 0x111D0, 0x111D9, 0x4, 0x111DA, 0x111DA, 0x1, 0x111DC,
160
+ 0x111DC, 0x1, 0x111E1, 0x111F4, 0x4, 0x11200, 0x11211, 0x1, 0x11213, 0x1122B, 0x1, 0x1122C, 0x11237, 0x2,
161
+ 0x1123E, 0x1123E, 0x2, 0x1123F, 0x11240, 0x1, 0x11241, 0x11241, 0x2, 0x11280, 0x11286, 0x1, 0x11288,
162
+ 0x11288, 0x1, 0x1128A, 0x1128D, 0x1, 0x1128F, 0x1129D, 0x1, 0x1129F, 0x112A8, 0x1, 0x112B0, 0x112DE, 0x1,
163
+ 0x112DF, 0x112EA, 0x2, 0x112F0, 0x112F9, 0x4, 0x11300, 0x11303, 0x2, 0x11305, 0x1130C, 0x1, 0x1130F,
164
+ 0x11310, 0x1, 0x11313, 0x11328, 0x1, 0x1132A, 0x11330, 0x1, 0x11332, 0x11333, 0x1, 0x11335, 0x11339, 0x1,
165
+ 0x1133B, 0x1133C, 0x2, 0x1133D, 0x1133D, 0x1, 0x1133E, 0x11344, 0x2, 0x11347, 0x11348, 0x2, 0x1134B,
166
+ 0x1134D, 0x2, 0x11350, 0x11350, 0x1, 0x11357, 0x11357, 0x2, 0x1135D, 0x11361, 0x1, 0x11362, 0x11363, 0x2,
167
+ 0x11366, 0x1136C, 0x2, 0x11370, 0x11374, 0x2, 0x11380, 0x11389, 0x1, 0x1138B, 0x1138B, 0x1, 0x1138E,
168
+ 0x1138E, 0x1, 0x11390, 0x113B5, 0x1, 0x113B7, 0x113B7, 0x1, 0x113B8, 0x113C0, 0x2, 0x113C2, 0x113C2, 0x2,
169
+ 0x113C5, 0x113C5, 0x2, 0x113C7, 0x113CA, 0x2, 0x113CC, 0x113D0, 0x2, 0x113D1, 0x113D1, 0x1, 0x113D2,
170
+ 0x113D2, 0x2, 0x113D3, 0x113D3, 0x1, 0x113E1, 0x113E2, 0x2, 0x11400, 0x11434, 0x1, 0x11435, 0x11446, 0x2,
171
+ 0x11447, 0x1144A, 0x1, 0x11450, 0x11459, 0x4, 0x1145E, 0x1145E, 0x2, 0x1145F, 0x11461, 0x1, 0x11480,
172
+ 0x114AF, 0x1, 0x114B0, 0x114C3, 0x2, 0x114C4, 0x114C5, 0x1, 0x114C7, 0x114C7, 0x1, 0x114D0, 0x114D9, 0x4,
173
+ 0x11580, 0x115AE, 0x1, 0x115AF, 0x115B5, 0x2, 0x115B8, 0x115C0, 0x2, 0x115D8, 0x115DB, 0x1, 0x115DC,
174
+ 0x115DD, 0x2, 0x11600, 0x1162F, 0x1, 0x11630, 0x11640, 0x2, 0x11644, 0x11644, 0x1, 0x11650, 0x11659, 0x4,
175
+ 0x11680, 0x116AA, 0x1, 0x116AB, 0x116B7, 0x2, 0x116B8, 0x116B8, 0x1, 0x116C0, 0x116C9, 0x4, 0x116D0,
176
+ 0x116E3, 0x4, 0x11700, 0x1171A, 0x1, 0x1171D, 0x1172B, 0x2, 0x11730, 0x1173B, 0x4, 0x11740, 0x11746, 0x1,
177
+ 0x11800, 0x1182B, 0x1, 0x1182C, 0x1183A, 0x2, 0x118A0, 0x118DF, 0x1, 0x118E0, 0x118F2, 0x4, 0x118FF,
178
+ 0x11906, 0x1, 0x11909, 0x11909, 0x1, 0x1190C, 0x11913, 0x1, 0x11915, 0x11916, 0x1, 0x11918, 0x1192F, 0x1,
179
+ 0x11930, 0x11935, 0x2, 0x11937, 0x11938, 0x2, 0x1193B, 0x1193E, 0x2, 0x1193F, 0x1193F, 0x1, 0x11940,
180
+ 0x11940, 0x2, 0x11941, 0x11941, 0x1, 0x11942, 0x11943, 0x2, 0x11950, 0x11959, 0x4, 0x119A0, 0x119A7, 0x1,
181
+ 0x119AA, 0x119D0, 0x1, 0x119D1, 0x119D7, 0x2, 0x119DA, 0x119E0, 0x2, 0x119E1, 0x119E1, 0x1, 0x119E3,
182
+ 0x119E3, 0x1, 0x119E4, 0x119E4, 0x2, 0x11A00, 0x11A00, 0x1, 0x11A01, 0x11A0A, 0x2, 0x11A0B, 0x11A32, 0x1,
183
+ 0x11A33, 0x11A39, 0x2, 0x11A3A, 0x11A3A, 0x1, 0x11A3B, 0x11A3E, 0x2, 0x11A47, 0x11A47, 0x2, 0x11A50,
184
+ 0x11A50, 0x1, 0x11A51, 0x11A5B, 0x2, 0x11A5C, 0x11A89, 0x1, 0x11A8A, 0x11A99, 0x2, 0x11A9D, 0x11A9D, 0x1,
185
+ 0x11AB0, 0x11AF8, 0x1, 0x11B0A, 0x11B0A, 0x1, 0x11B60, 0x11B67, 0x2, 0x11BC0, 0x11BE0, 0x1, 0x11BF0,
186
+ 0x11BF9, 0x4, 0x11C00, 0x11C08, 0x1, 0x11C0A, 0x11C2E, 0x1, 0x11C2F, 0x11C36, 0x2, 0x11C38, 0x11C3F, 0x2,
187
+ 0x11C40, 0x11C40, 0x1, 0x11C50, 0x11C6C, 0x4, 0x11C72, 0x11C8F, 0x1, 0x11C92, 0x11CA7, 0x2, 0x11CA9,
188
+ 0x11CB6, 0x2, 0x11D00, 0x11D06, 0x1, 0x11D08, 0x11D09, 0x1, 0x11D0B, 0x11D30, 0x1, 0x11D31, 0x11D36, 0x2,
189
+ 0x11D3A, 0x11D3A, 0x2, 0x11D3C, 0x11D3D, 0x2, 0x11D3F, 0x11D45, 0x2, 0x11D46, 0x11D46, 0x1, 0x11D47,
190
+ 0x11D47, 0x2, 0x11D50, 0x11D59, 0x4, 0x11D60, 0x11D65, 0x1, 0x11D67, 0x11D68, 0x1, 0x11D6A, 0x11D89, 0x1,
191
+ 0x11D8A, 0x11D8E, 0x2, 0x11D90, 0x11D91, 0x2, 0x11D93, 0x11D97, 0x2, 0x11D98, 0x11D98, 0x1, 0x11DA0,
192
+ 0x11DA9, 0x4, 0x11DB0, 0x11DDB, 0x1, 0x11DE0, 0x11DE9, 0x4, 0x11DF0, 0x11DF0, 0x2, 0x11DF1, 0x11DF1, 0x1,
193
+ 0x11EE0, 0x11EF2, 0x1, 0x11EF3, 0x11EF6, 0x2, 0x11F00, 0x11F01, 0x2, 0x11F02, 0x11F02, 0x1, 0x11F03,
194
+ 0x11F03, 0x2, 0x11F04, 0x11F10, 0x1, 0x11F12, 0x11F33, 0x1, 0x11F34, 0x11F3A, 0x2, 0x11F3E, 0x11F42, 0x2,
195
+ 0x11F50, 0x11F59, 0x4, 0x11F5A, 0x11F5A, 0x2, 0x11FB0, 0x11FB0, 0x1, 0x11FC0, 0x11FD4, 0x4, 0x12000,
196
+ 0x12399, 0x1, 0x12400, 0x1246F, 0x4, 0x12475, 0x1247F, 0x4, 0x12480, 0x12543, 0x1, 0x12550, 0x12686, 0x4,
197
+ 0x12F90, 0x12FF0, 0x1, 0x13000, 0x1342F, 0x1, 0x13440, 0x13440, 0x2, 0x13441, 0x13446, 0x1, 0x13447,
198
+ 0x13455, 0x2, 0x13460, 0x143FA, 0x1, 0x14400, 0x14646, 0x1, 0x16100, 0x1611D, 0x1, 0x1611E, 0x1612F, 0x2,
199
+ 0x16130, 0x16139, 0x4, 0x16800, 0x16A38, 0x1, 0x16A40, 0x16A5E, 0x1, 0x16A60, 0x16A69, 0x4, 0x16A70,
200
+ 0x16ABE, 0x1, 0x16AC0, 0x16AC9, 0x4, 0x16AD0, 0x16AED, 0x1, 0x16AF0, 0x16AF4, 0x2, 0x16B00, 0x16B2F, 0x1,
201
+ 0x16B30, 0x16B36, 0x2, 0x16B40, 0x16B43, 0x1, 0x16B50, 0x16B59, 0x4, 0x16B5B, 0x16B61, 0x4, 0x16B63,
202
+ 0x16B77, 0x1, 0x16B7D, 0x16B8F, 0x1, 0x16D40, 0x16D6C, 0x1, 0x16D70, 0x16D79, 0x4, 0x16E40, 0x16E7F, 0x1,
203
+ 0x16E80, 0x16E96, 0x4, 0x16EA0, 0x16EB8, 0x1, 0x16EBB, 0x16ED3, 0x1, 0x16F00, 0x16F4A, 0x1, 0x16F4F,
204
+ 0x16F4F, 0x2, 0x16F50, 0x16F50, 0x1, 0x16F51, 0x16F87, 0x2, 0x16F8F, 0x16F92, 0x2, 0x16F93, 0x16F9F, 0x1,
205
+ 0x16FE0, 0x16FE1, 0x1, 0x16FE3, 0x16FE3, 0x1, 0x16FE4, 0x16FE4, 0x2, 0x16FF0, 0x16FF1, 0x2, 0x16FF2,
206
+ 0x16FF3, 0x1, 0x16FF4, 0x16FF6, 0x4, 0x17000, 0x18CDA, 0x1, 0x18CFF, 0x18D20, 0x1, 0x18D80, 0x18DF2, 0x1,
207
+ 0x18E00, 0x19191, 0x1, 0x191A0, 0x191D2, 0x1, 0x1AFF0, 0x1AFF3, 0x1, 0x1AFF5, 0x1AFFB, 0x1, 0x1AFFD,
208
+ 0x1AFFE, 0x1, 0x1B000, 0x1B128, 0x1, 0x1B132, 0x1B132, 0x1, 0x1B150, 0x1B152, 0x1, 0x1B155, 0x1B155, 0x1,
209
+ 0x1B164, 0x1B168, 0x1, 0x1B170, 0x1B2FB, 0x1, 0x1BC00, 0x1BC6A, 0x1, 0x1BC70, 0x1BC7C, 0x1, 0x1BC80,
210
+ 0x1BC88, 0x1, 0x1BC90, 0x1BC99, 0x1, 0x1BC9D, 0x1BC9E, 0x2, 0x1CCF0, 0x1CCF9, 0x4, 0x1CF00, 0x1CF2D, 0x2,
211
+ 0x1CF30, 0x1CF46, 0x2, 0x1D127, 0x1D128, 0x2, 0x1D165, 0x1D169, 0x2, 0x1D16D, 0x1D172, 0x2, 0x1D17B,
212
+ 0x1D182, 0x2, 0x1D185, 0x1D18B, 0x2, 0x1D1AA, 0x1D1AD, 0x2, 0x1D242, 0x1D244, 0x2, 0x1D250, 0x1D252, 0x2,
213
+ 0x1D25B, 0x1D25C, 0x2, 0x1D25F, 0x1D25F, 0x2, 0x1D280, 0x1D281, 0x2, 0x1D2C0, 0x1D2D3, 0x4, 0x1D2E0,
214
+ 0x1D2F3, 0x4, 0x1D360, 0x1D378, 0x4, 0x1D400, 0x1D454, 0x1, 0x1D456, 0x1D49C, 0x1, 0x1D49E, 0x1D49F, 0x1,
215
+ 0x1D4A2, 0x1D4A2, 0x1, 0x1D4A5, 0x1D4A6, 0x1, 0x1D4A9, 0x1D4AC, 0x1, 0x1D4AE, 0x1D4B9, 0x1, 0x1D4BB,
216
+ 0x1D4BB, 0x1, 0x1D4BD, 0x1D4C3, 0x1, 0x1D4C5, 0x1D505, 0x1, 0x1D507, 0x1D50A, 0x1, 0x1D50D, 0x1D514, 0x1,
217
+ 0x1D516, 0x1D51C, 0x1, 0x1D51E, 0x1D539, 0x1, 0x1D53B, 0x1D53E, 0x1, 0x1D540, 0x1D544, 0x1, 0x1D546,
218
+ 0x1D546, 0x1, 0x1D54A, 0x1D550, 0x1, 0x1D552, 0x1D6A6, 0x1, 0x1D6A8, 0x1D6C0, 0x1, 0x1D6C2, 0x1D6DA, 0x1,
219
+ 0x1D6DC, 0x1D6FA, 0x1, 0x1D6FC, 0x1D714, 0x1, 0x1D716, 0x1D734, 0x1, 0x1D736, 0x1D74E, 0x1, 0x1D750,
220
+ 0x1D76E, 0x1, 0x1D770, 0x1D788, 0x1, 0x1D78A, 0x1D7A8, 0x1, 0x1D7AA, 0x1D7C2, 0x1, 0x1D7C4, 0x1D7CB, 0x1,
221
+ 0x1D7CE, 0x1D7FF, 0x4, 0x1DA00, 0x1DA36, 0x2, 0x1DA3B, 0x1DA6C, 0x2, 0x1DA75, 0x1DA75, 0x2, 0x1DA84,
222
+ 0x1DA84, 0x2, 0x1DA9B, 0x1DA9F, 0x2, 0x1DAA1, 0x1DAAF, 0x2, 0x1DF00, 0x1DF81, 0x1, 0x1DF90, 0x1DF96, 0x1,
223
+ 0x1DFCD, 0x1DFFF, 0x1, 0x1E000, 0x1E006, 0x2, 0x1E008, 0x1E018, 0x2, 0x1E01B, 0x1E021, 0x2, 0x1E023,
224
+ 0x1E024, 0x2, 0x1E026, 0x1E02A, 0x2, 0x1E030, 0x1E06D, 0x1, 0x1E08F, 0x1E08F, 0x2, 0x1E100, 0x1E12C, 0x1,
225
+ 0x1E130, 0x1E136, 0x2, 0x1E137, 0x1E13D, 0x1, 0x1E140, 0x1E149, 0x4, 0x1E14E, 0x1E14E, 0x1, 0x1E290,
226
+ 0x1E2AD, 0x1, 0x1E2AE, 0x1E2AE, 0x2, 0x1E2C0, 0x1E2EB, 0x1, 0x1E2EC, 0x1E2EF, 0x2, 0x1E2F0, 0x1E2F9, 0x4,
227
+ 0x1E4D0, 0x1E4EB, 0x1, 0x1E4EC, 0x1E4EF, 0x2, 0x1E4F0, 0x1E4F9, 0x4, 0x1E5D0, 0x1E5ED, 0x1, 0x1E5EE,
228
+ 0x1E5EF, 0x2, 0x1E5F0, 0x1E5F0, 0x1, 0x1E5F1, 0x1E5FA, 0x4, 0x1E6C0, 0x1E6DE, 0x1, 0x1E6E0, 0x1E6E2, 0x1,
229
+ 0x1E6E3, 0x1E6E3, 0x2, 0x1E6E4, 0x1E6E5, 0x1, 0x1E6E6, 0x1E6E6, 0x2, 0x1E6E7, 0x1E6ED, 0x1, 0x1E6EE,
230
+ 0x1E6EF, 0x2, 0x1E6F0, 0x1E6F4, 0x1, 0x1E6F5, 0x1E6F5, 0x2, 0x1E6FE, 0x1E6FF, 0x1, 0x1E7E0, 0x1E7E6, 0x1,
231
+ 0x1E7E8, 0x1E7EB, 0x1, 0x1E7ED, 0x1E7EE, 0x1, 0x1E7F0, 0x1E7FE, 0x1, 0x1E800, 0x1E8C4, 0x1, 0x1E8C7,
232
+ 0x1E8CF, 0x4, 0x1E8D0, 0x1E8D6, 0x2, 0x1E900, 0x1E943, 0x1, 0x1E944, 0x1E94A, 0x2, 0x1E94B, 0x1E94B, 0x1,
233
+ 0x1E950, 0x1E959, 0x4, 0x1EC71, 0x1ECAB, 0x4, 0x1ECAD, 0x1ECAF, 0x4, 0x1ECB1, 0x1ECB4, 0x4, 0x1ED01,
234
+ 0x1ED2D, 0x4, 0x1ED2F, 0x1ED3D, 0x4, 0x1EE00, 0x1EE03, 0x1, 0x1EE05, 0x1EE1F, 0x1, 0x1EE21, 0x1EE22, 0x1,
235
+ 0x1EE24, 0x1EE24, 0x1, 0x1EE27, 0x1EE27, 0x1, 0x1EE29, 0x1EE32, 0x1, 0x1EE34, 0x1EE37, 0x1, 0x1EE39,
236
+ 0x1EE39, 0x1, 0x1EE3B, 0x1EE3B, 0x1, 0x1EE42, 0x1EE42, 0x1, 0x1EE47, 0x1EE47, 0x1, 0x1EE49, 0x1EE49, 0x1,
237
+ 0x1EE4B, 0x1EE4B, 0x1, 0x1EE4D, 0x1EE4F, 0x1, 0x1EE51, 0x1EE52, 0x1, 0x1EE54, 0x1EE54, 0x1, 0x1EE57,
238
+ 0x1EE57, 0x1, 0x1EE59, 0x1EE59, 0x1, 0x1EE5B, 0x1EE5B, 0x1, 0x1EE5D, 0x1EE5D, 0x1, 0x1EE5F, 0x1EE5F, 0x1,
239
+ 0x1EE61, 0x1EE62, 0x1, 0x1EE64, 0x1EE64, 0x1, 0x1EE67, 0x1EE6A, 0x1, 0x1EE6C, 0x1EE72, 0x1, 0x1EE74,
240
+ 0x1EE77, 0x1, 0x1EE79, 0x1EE7C, 0x1, 0x1EE7E, 0x1EE7E, 0x1, 0x1EE80, 0x1EE89, 0x1, 0x1EE8B, 0x1EE9B, 0x1,
241
+ 0x1EEA1, 0x1EEA3, 0x1, 0x1EEA5, 0x1EEA9, 0x1, 0x1EEAB, 0x1EEBB, 0x1, 0x1F100, 0x1F10C, 0x4, 0x1FBF0,
242
+ 0x1FBF9, 0x4, 0x20000, 0x2A6DF, 0x1, 0x2A700, 0x2B81E, 0x1, 0x2B820, 0x2CEAD, 0x1, 0x2CEB0, 0x2EBE0, 0x1,
243
+ 0x2EBF0, 0x2EE5D, 0x1, 0x2F800, 0x2FA1D, 0x1, 0x30000, 0x3134A, 0x1, 0x31350, 0x33479, 0x1, 0x3D000,
244
+ 0x3FC3F, 0x1, 0xE0100, 0xE01EF, 0x2,
245
+ ]);
package/dist/value.d.ts CHANGED
@@ -60,6 +60,12 @@ export declare const PARTIAL_COUNT_LIMIT = 128;
60
60
  export declare const PARTIAL_NAME_LENGTH_LIMIT = 128;
61
61
  export declare const PARTIAL_NODE_LIMIT = 4096;
62
62
  export declare const RESULT_NODE_LIMIT = 65536;
63
+ /**
64
+ * Nodes a resolution may copy (References §4.1: limits are validated during expansion). Each value is resolved
65
+ * for at most four edge budgets, so a document within RESULT_NODE_LIMIT stays far below this. Past it the result
66
+ * cannot fit, and copying on would only fill the memory: a few KB of references can reach millions of nodes.
67
+ */
68
+ export declare const RESOLUTION_COPY_LIMIT: number;
63
69
  export declare const SCALAR_LENGTH_LIMIT = 16384;
64
70
  /**
65
71
  * Counts Unicode code points (what every length-limit check in this
package/dist/value.js CHANGED
@@ -63,6 +63,12 @@ export const PARTIAL_COUNT_LIMIT = 128;
63
63
  export const PARTIAL_NAME_LENGTH_LIMIT = 128;
64
64
  export const PARTIAL_NODE_LIMIT = 4096;
65
65
  export const RESULT_NODE_LIMIT = 65536;
66
+ /**
67
+ * Nodes a resolution may copy (References §4.1: limits are validated during expansion). Each value is resolved
68
+ * for at most four edge budgets, so a document within RESULT_NODE_LIMIT stays far below this. Past it the result
69
+ * cannot fit, and copying on would only fill the memory: a few KB of references can reach millions of nodes.
70
+ */
71
+ export const RESOLUTION_COPY_LIMIT = 16 * RESULT_NODE_LIMIT;
66
72
  export const SCALAR_LENGTH_LIMIT = 16384;
67
73
  /**
68
74
  * Counts Unicode code points (what every length-limit check in this
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limaformat/lima",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Lima frontmatter parser — LIMA Is Metadata Annotation",
5
5
  "keywords": ["frontmatter", "parser", "yaml", "markdown", "metadata"],
6
6
  "homepage": "https://limaformat.dev",
@@ -20,7 +20,7 @@
20
20
  }
21
21
  },
22
22
  "files": ["dist", "README.md", "LICENSE", "CHANGELOG.md"],
23
- "engines": { "node": ">=18" },
23
+ "engines": { "node": ">=22" },
24
24
  "scripts": {
25
25
  "build": "tsc -p tsconfig.build.json",
26
26
  "prepack": "bun run build",