soml-lang 0.0.2 → 0.0.3
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/distribution/edit.d.ts +56 -0
- package/distribution/edit.js +635 -0
- package/distribution/error.d.ts +19 -2
- package/distribution/error.js +20 -3
- package/distribution/format.d.ts +48 -4
- package/distribution/format.js +209 -49
- package/distribution/index.d.ts +6 -3
- package/distribution/index.js +7 -2
- package/distribution/parse.d.ts +68 -5
- package/distribution/parse.js +593 -177
- package/distribution/shared.d.ts +58 -4
- package/distribution/shared.js +93 -11
- package/distribution/stringify.d.ts +88 -8
- package/distribution/stringify.js +173 -59
- package/distribution/tree.d.ts +115 -4
- package/distribution/tree.js +221 -86
- package/package.json +4 -3
- package/readme.md +254 -47
package/distribution/shared.d.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
export declare const TAB = 9;
|
|
2
|
+
export declare const LF = 10;
|
|
3
|
+
export declare const SPACE = 32;
|
|
4
|
+
export declare const DOUBLE_QUOTE = 34;
|
|
5
|
+
export declare const HASH = 35;
|
|
6
|
+
export declare const SINGLE_QUOTE = 39;
|
|
7
|
+
export declare const ASTERISK = 42;
|
|
8
|
+
export declare const COMMA = 44;
|
|
9
|
+
export declare const DASH = 45;
|
|
10
|
+
export declare const DOT = 46;
|
|
11
|
+
export declare const SLASH = 47;
|
|
12
|
+
export declare const COLON = 58;
|
|
13
|
+
export declare const OPEN_BRACKET = 91;
|
|
14
|
+
export declare const BACKSLASH = 92;
|
|
15
|
+
export declare const CLOSE_BRACKET = 93;
|
|
16
|
+
export declare const OPEN_BRACE = 123;
|
|
17
|
+
export declare const CLOSE_BRACE = 125;
|
|
1
18
|
export declare const MAX_DEPTH = 100;
|
|
2
19
|
export declare const INT64_MIN: bigint;
|
|
3
20
|
export declare const INT64_MAX: bigint;
|
|
@@ -13,17 +30,38 @@ export declare function trimTrailingZeros(digits: string): string;
|
|
|
13
30
|
A duration as a `Temporal.Duration` in hours and smaller units, which hold any int64 count of nanoseconds exactly.
|
|
14
31
|
*/
|
|
15
32
|
export declare function createDuration(nanoseconds: bigint): Temporal.Duration;
|
|
16
|
-
|
|
33
|
+
/**
|
|
34
|
+
The `integers` option of `parse()`, `stringify()`, and `edit()`, checked, or its default when it is left out.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getIntegersOption(options: unknown): 'bigint' | 'number';
|
|
17
37
|
/**
|
|
18
38
|
Whether a UTF-16 code unit can be part of a bare key. `NaN`, which `charCodeAt()` returns past the end of a string, cannot.
|
|
19
39
|
*/
|
|
20
40
|
export declare function isBareKeyCharacter(code: number): boolean;
|
|
21
41
|
/**
|
|
22
|
-
Whether a key can be written without quotes: one or more ASCII letters, digits, `_`, or
|
|
42
|
+
Whether a key can be written without quotes, as a bare key: one or more ASCII letters, digits, `_`, or `-`, in any order, so `404` and `-x` are bare keys too. `stringify()` writes such a key bare and quotes every other key.
|
|
43
|
+
|
|
44
|
+
@param key - The decoded key.
|
|
45
|
+
@returns Whether `key` can be a bare key.
|
|
46
|
+
|
|
47
|
+
@example
|
|
48
|
+
```
|
|
49
|
+
import {isBareKey} from 'soml-lang';
|
|
50
|
+
|
|
51
|
+
isBareKey('content-type');
|
|
52
|
+
//=> true
|
|
53
|
+
|
|
54
|
+
isBareKey('a.b');
|
|
55
|
+
//=> false
|
|
56
|
+
```
|
|
23
57
|
*/
|
|
24
58
|
export declare function isBareKey(key: string): boolean;
|
|
25
59
|
/**
|
|
26
|
-
|
|
60
|
+
A key as an error message shows it: bare when it can be, and otherwise quoted, and cut short when it is long.
|
|
61
|
+
*/
|
|
62
|
+
export declare function describeKey(key: string): string;
|
|
63
|
+
/**
|
|
64
|
+
The end of the number, instant, or duration token that starts at `start`, which is a digit, `-`, or the `i` of `infinity`.
|
|
27
65
|
*/
|
|
28
66
|
export declare function findNumberEnd(source: string, start: number): number;
|
|
29
67
|
/**
|
|
@@ -38,11 +76,27 @@ export declare function findBlockStringEnd(source: string, offset: number, quote
|
|
|
38
76
|
delimiterStart: number;
|
|
39
77
|
} | undefined;
|
|
40
78
|
/**
|
|
79
|
+
Whether a UTF-16 code unit is a space or a tab, the whitespace within a line.
|
|
80
|
+
*/
|
|
81
|
+
export declare function isSpace(code: number): boolean;
|
|
82
|
+
/**
|
|
83
|
+
The index after the spaces and tabs from `index` on.
|
|
84
|
+
*/
|
|
85
|
+
export declare function skipSpaces(text: string, index: number): number;
|
|
86
|
+
/**
|
|
87
|
+
The index after the last character before `index` that is not a space or a tab.
|
|
88
|
+
*/
|
|
89
|
+
export declare function skipSpacesBack(text: string, index: number): number;
|
|
90
|
+
/**
|
|
91
|
+
Whether a line in a block string is blank: empty, or only spaces and tabs. A blank line becomes an empty line in the value.
|
|
92
|
+
*/
|
|
93
|
+
export declare function isBlankLine(line: string): boolean;
|
|
94
|
+
/**
|
|
41
95
|
Shorten text quoted in an error message, so a huge token does not make a huge message. The cut never splits a surrogate pair.
|
|
42
96
|
*/
|
|
43
97
|
export declare function abbreviate(text: string, maximumLength?: number): string;
|
|
44
98
|
export declare function formatCodePoint(codePoint: number): string;
|
|
45
99
|
/**
|
|
46
|
-
Describe a character for an error message, such as
|
|
100
|
+
Describe a character for an error message, such as `“$”` or `U+00A0 (NO-BREAK SPACE)`.
|
|
47
101
|
*/
|
|
48
102
|
export declare function describeCharacter(codePoint: number): string;
|
package/distribution/shared.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
/*
|
|
2
|
+
UTF-16 code units of the characters that the lexers look for.
|
|
3
|
+
*/
|
|
4
|
+
export const TAB = 0x09;
|
|
5
|
+
export const LF = 0x0A;
|
|
6
|
+
export const SPACE = 0x20;
|
|
7
|
+
export const DOUBLE_QUOTE = 0x22;
|
|
8
|
+
export const HASH = 0x23;
|
|
9
|
+
export const SINGLE_QUOTE = 0x27;
|
|
10
|
+
export const ASTERISK = 0x2A;
|
|
11
|
+
export const COMMA = 0x2C;
|
|
12
|
+
export const DASH = 0x2D;
|
|
13
|
+
export const DOT = 0x2E;
|
|
14
|
+
export const SLASH = 0x2F;
|
|
15
|
+
export const COLON = 0x3A;
|
|
16
|
+
export const OPEN_BRACKET = 0x5B;
|
|
17
|
+
export const BACKSLASH = 0x5C;
|
|
18
|
+
export const CLOSE_BRACKET = 0x5D;
|
|
19
|
+
export const OPEN_BRACE = 0x7B;
|
|
20
|
+
export const CLOSE_BRACE = 0x7D;
|
|
21
|
+
/*
|
|
2
22
|
The deepest nesting either direction accepts. A recursive-descent parser would otherwise end in an engine stack overflow.
|
|
3
23
|
*/
|
|
4
24
|
export const MAX_DEPTH = 100;
|
|
@@ -10,7 +30,7 @@ The instant range is checked in UTC, so that every instant has a canonical form
|
|
|
10
30
|
export const MIN_INSTANT = -62135596800000000000n; // 0001-01-01T00:00:00Z
|
|
11
31
|
export const MAX_INSTANT = 253402300799999999999n; // 9999-12-31T23:59:59.999999999Z
|
|
12
32
|
/*
|
|
13
|
-
`Temporal` is built into Node.js 26 and later. Before that, only instants and durations need it, so that everything else works without a polyfill
|
|
33
|
+
`Temporal` is built into Node.js 26 and later. Before that, only the values of instants and durations need it, so that everything else works without a polyfill, including `format()` and `parseTree()`. It is read at import, so a polyfill must be loaded before this package.
|
|
14
34
|
*/
|
|
15
35
|
const temporal = typeof Temporal === 'undefined' ? undefined : Temporal;
|
|
16
36
|
export function requireTemporal() {
|
|
@@ -54,10 +74,21 @@ export function createDuration(nanoseconds) {
|
|
|
54
74
|
const [hours, minutes, seconds, milliseconds, microseconds, nanosecondsPart] = parts;
|
|
55
75
|
return new (requireTemporal().Duration)(0, 0, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanosecondsPart);
|
|
56
76
|
}
|
|
57
|
-
|
|
77
|
+
/**
|
|
78
|
+
The `integers` option of `parse()`, `stringify()`, and `edit()`, checked, or its default when it is left out.
|
|
79
|
+
*/
|
|
80
|
+
export function getIntegersOption(options) {
|
|
81
|
+
if (options === undefined) {
|
|
82
|
+
return 'bigint';
|
|
83
|
+
}
|
|
84
|
+
if (typeof options !== 'object' || options === null) {
|
|
85
|
+
throw new TypeError(`The options must be an object, got ${options === null ? 'null' : typeof options}`);
|
|
86
|
+
}
|
|
87
|
+
const { integers = 'bigint' } = options;
|
|
58
88
|
if (integers !== 'bigint' && integers !== 'number') {
|
|
59
89
|
throw new TypeError(`The \`integers\` option must be 'bigint' or 'number', got ${typeof integers === 'string' ? `'${abbreviate(integers)}'` : typeof integers}`);
|
|
60
90
|
}
|
|
91
|
+
return integers;
|
|
61
92
|
}
|
|
62
93
|
/*
|
|
63
94
|
Names for the characters that are invisible or easy to mistake, so an error can say what it found.
|
|
@@ -122,7 +153,21 @@ export function isBareKeyCharacter(code) {
|
|
|
122
153
|
return code < 128 && bareKeyCharacters[code] === 1;
|
|
123
154
|
}
|
|
124
155
|
/**
|
|
125
|
-
Whether a key can be written without quotes: one or more ASCII letters, digits, `_`, or
|
|
156
|
+
Whether a key can be written without quotes, as a bare key: one or more ASCII letters, digits, `_`, or `-`, in any order, so `404` and `-x` are bare keys too. `stringify()` writes such a key bare and quotes every other key.
|
|
157
|
+
|
|
158
|
+
@param key - The decoded key.
|
|
159
|
+
@returns Whether `key` can be a bare key.
|
|
160
|
+
|
|
161
|
+
@example
|
|
162
|
+
```
|
|
163
|
+
import {isBareKey} from 'soml-lang';
|
|
164
|
+
|
|
165
|
+
isBareKey('content-type');
|
|
166
|
+
//=> true
|
|
167
|
+
|
|
168
|
+
isBareKey('a.b');
|
|
169
|
+
//=> false
|
|
170
|
+
```
|
|
126
171
|
*/
|
|
127
172
|
export function isBareKey(key) {
|
|
128
173
|
if (key === '') {
|
|
@@ -136,7 +181,13 @@ export function isBareKey(key) {
|
|
|
136
181
|
return true;
|
|
137
182
|
}
|
|
138
183
|
/**
|
|
139
|
-
|
|
184
|
+
A key as an error message shows it: bare when it can be, and otherwise quoted, and cut short when it is long.
|
|
185
|
+
*/
|
|
186
|
+
export function describeKey(key) {
|
|
187
|
+
return isBareKey(key) ? abbreviate(key) : JSON.stringify(abbreviate(key));
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
The end of the number, instant, or duration token that starts at `start`, which is a digit, `-`, or the `i` of `infinity`.
|
|
140
191
|
*/
|
|
141
192
|
export function findNumberEnd(source, start) {
|
|
142
193
|
let end = start + 1;
|
|
@@ -160,10 +211,7 @@ Find the closing delimiter of a block string: the first line from `offset` on th
|
|
|
160
211
|
*/
|
|
161
212
|
export function findBlockStringEnd(source, offset, quote, length) {
|
|
162
213
|
for (let lineStart = offset; lineStart < source.length; lineStart = findLineEnd(source, lineStart) + 1) {
|
|
163
|
-
|
|
164
|
-
while (source.charCodeAt(delimiterStart) === 0x20 || source.charCodeAt(delimiterStart) === 0x09) {
|
|
165
|
-
delimiterStart++;
|
|
166
|
-
}
|
|
214
|
+
const delimiterStart = skipSpaces(source, lineStart);
|
|
167
215
|
let runLength = 0;
|
|
168
216
|
while (source.charCodeAt(delimiterStart + runLength) === quote) {
|
|
169
217
|
runLength++;
|
|
@@ -172,9 +220,43 @@ export function findBlockStringEnd(source, offset, quote, length) {
|
|
|
172
220
|
return { lineStart, delimiterStart };
|
|
173
221
|
}
|
|
174
222
|
}
|
|
223
|
+
// Past the last line, either because the source ended with a line break or because the last line was content.
|
|
175
224
|
return undefined;
|
|
176
225
|
}
|
|
177
226
|
/**
|
|
227
|
+
Whether a UTF-16 code unit is a space or a tab, the whitespace within a line.
|
|
228
|
+
*/
|
|
229
|
+
export function isSpace(code) {
|
|
230
|
+
return code === SPACE || code === TAB;
|
|
231
|
+
}
|
|
232
|
+
/*
|
|
233
|
+
Whitespace within a line is scanned with loops rather than regular expressions such as `/[\t ]*:/`, because a regular expression that backtracks over a run of a few million spaces runs out of stack.
|
|
234
|
+
*/
|
|
235
|
+
/**
|
|
236
|
+
The index after the spaces and tabs from `index` on.
|
|
237
|
+
*/
|
|
238
|
+
export function skipSpaces(text, index) {
|
|
239
|
+
while (isSpace(text.charCodeAt(index))) {
|
|
240
|
+
index++;
|
|
241
|
+
}
|
|
242
|
+
return index;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
The index after the last character before `index` that is not a space or a tab.
|
|
246
|
+
*/
|
|
247
|
+
export function skipSpacesBack(text, index) {
|
|
248
|
+
while (index > 0 && isSpace(text.charCodeAt(index - 1))) {
|
|
249
|
+
index--;
|
|
250
|
+
}
|
|
251
|
+
return index;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
Whether a line in a block string is blank: empty, or only spaces and tabs. A blank line becomes an empty line in the value.
|
|
255
|
+
*/
|
|
256
|
+
export function isBlankLine(line) {
|
|
257
|
+
return skipSpaces(line, 0) === line.length;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
178
260
|
Shorten text quoted in an error message, so a huge token does not make a huge message. The cut never splits a surrogate pair.
|
|
179
261
|
*/
|
|
180
262
|
export function abbreviate(text, maximumLength = 40) {
|
|
@@ -189,7 +271,7 @@ export function formatCodePoint(codePoint) {
|
|
|
189
271
|
return `U+${codePoint.toString(16).toUpperCase().padStart(4, '0')}`;
|
|
190
272
|
}
|
|
191
273
|
/**
|
|
192
|
-
Describe a character for an error message, such as
|
|
274
|
+
Describe a character for an error message, such as `“$”` or `U+00A0 (NO-BREAK SPACE)`.
|
|
193
275
|
*/
|
|
194
276
|
export function describeCharacter(codePoint) {
|
|
195
277
|
const name = CHARACTER_NAMES.get(codePoint);
|
|
@@ -198,6 +280,6 @@ export function describeCharacter(codePoint) {
|
|
|
198
280
|
return `${formatCodePoint(codePoint)} (${name}${isWhitespace ? '; only space, tab, and line feed are whitespace' : ''})`;
|
|
199
281
|
}
|
|
200
282
|
const character = String.fromCodePoint(codePoint);
|
|
201
|
-
// Control, format, private-use, unassigned, surrogate, and
|
|
202
|
-
return codePoint !== 0x20 && /^[\p{Other}\p{Separator}]$/v.test(character) ? formatCodePoint(codePoint) :
|
|
283
|
+
// Control, format, private-use, unassigned, surrogate, separator, and default-ignorable characters are invisible or ambiguous, so they are shown by code point.
|
|
284
|
+
return codePoint !== 0x20 && /^[\p{Default_Ignorable_Code_Point}\p{Other}\p{Separator}]$/v.test(character) ? formatCodePoint(codePoint) : `“${character}”`;
|
|
203
285
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Options for `stringify()`.
|
|
3
|
+
*/
|
|
1
4
|
export type StringifyOptions = {
|
|
2
5
|
/**
|
|
3
|
-
How an int is represented in
|
|
6
|
+
How an int is represented in `value`.
|
|
4
7
|
|
|
5
8
|
- `'bigint'`: A `bigint` is written as an int, and a `number` is always written as a float, so `8080` becomes `8080.0`.
|
|
6
9
|
- `'number'`: A `number` that is a safe integer is written as an int, and any other `number` as a float. A `bigint` is still written as an int.
|
|
@@ -8,21 +11,42 @@ export type StringifyOptions = {
|
|
|
8
11
|
@default 'bigint'
|
|
9
12
|
*/
|
|
10
13
|
readonly integers?: 'bigint' | 'number';
|
|
14
|
+
/**
|
|
15
|
+
Write exact canonical form, with the members of every object sorted by key, for hashing, signing, or comparing.
|
|
16
|
+
|
|
17
|
+
By default, members keep the order of `value`, which reads better in a file for people, and every other rule of canonical form is followed. JavaScript puts integer-like keys, such as `404` or `10`, before every other key, in numeric order, so their order in `value` cannot be kept.
|
|
18
|
+
|
|
19
|
+
@default false
|
|
20
|
+
|
|
21
|
+
@example
|
|
22
|
+
```
|
|
23
|
+
import {stringify} from 'soml-lang';
|
|
24
|
+
|
|
25
|
+
stringify({name: 'api', description: 'The edge service'});
|
|
26
|
+
//=> "name: 'api'\ndescription: 'The edge service'\n"
|
|
27
|
+
|
|
28
|
+
stringify({name: 'api', description: 'The edge service'}, {canonical: true});
|
|
29
|
+
//=> "description: 'The edge service'\nname: 'api'\n"
|
|
30
|
+
```
|
|
31
|
+
*/
|
|
32
|
+
readonly canonical?: boolean;
|
|
11
33
|
};
|
|
12
34
|
/**
|
|
13
|
-
Serialize an object or an array to
|
|
35
|
+
Serialize an object or an array to SOML. Nesting is written with braces and tabs, and the output ends with one line feed. Comments, dotted keys, and block strings are never written.
|
|
14
36
|
|
|
15
|
-
|
|
37
|
+
Members keep the order of `value`, which reads better in a file for people, and every other rule of canonical form is followed. With the `canonical: true` option, members are sorted by key, and the output is canonical form: two equal values produce the same bytes, so it can be hashed, signed, or compared.
|
|
38
|
+
|
|
39
|
+
JavaScript puts integer-like keys, such as `404` or `10`, before every other key, in numeric order, so their order in `value` cannot be kept.
|
|
16
40
|
|
|
17
41
|
A `bigint` is written as an int and a `number` as a float, so `{port: 8080}` becomes `port: 8080.0`. Use `8080n`, or the `integers: 'number'` option.
|
|
18
42
|
|
|
19
|
-
|
|
43
|
+
Besides the types that `parse()` returns, a `Date` is accepted and written as an instant, a `Temporal.Duration` is accepted when it has no years, months, weeks, or days, because those are not a fixed length, and a member whose value is `undefined` is left out, as `JSON.stringify` does.
|
|
20
44
|
|
|
21
45
|
@param value - A plain object or an array.
|
|
22
|
-
@param options - How to
|
|
23
|
-
@returns The
|
|
24
|
-
@throws {TypeError}
|
|
25
|
-
@throws {RangeError}
|
|
46
|
+
@param options - How an int is represented in `value`, and whether to sort members.
|
|
47
|
+
@returns The document, ending with one line feed.
|
|
48
|
+
@throws {TypeError} For a value that cannot be represented: `NaN`, a function, a symbol value, an object that is neither a plain object nor an array (such as a class instance or a `Map`), `undefined` in an array, a circular reference, a non-collection at the top level, an invalid `Date`, a `Temporal.Duration` with years, months, weeks, or days, an object that only claims to be a `Date`, a `Temporal.Instant`, or a `Temporal.Duration`, and a string or key with a lone surrogate or a carriage return. Also when `options` is not an object, its `integers` is not `'bigint'` or `'number'`, or its `canonical` is not a boolean.
|
|
49
|
+
@throws {RangeError} For an int outside the 64-bit range, an instant outside the years 0001 to 9999, a duration outside the 64-bit range of nanoseconds, and nesting deeper than 100 levels.
|
|
26
50
|
|
|
27
51
|
@example
|
|
28
52
|
```
|
|
@@ -30,6 +54,62 @@ import {stringify} from 'soml-lang';
|
|
|
30
54
|
|
|
31
55
|
stringify({name: 'api-gateway', replicas: 3n, timeout: 30});
|
|
32
56
|
//=> "name: 'api-gateway'\nreplicas: 3\ntimeout: 30.0\n"
|
|
57
|
+
|
|
58
|
+
stringify({port: 8080}, {integers: 'number'});
|
|
59
|
+
//=> 'port: 8080\n'
|
|
60
|
+
|
|
61
|
+
stringify({name: 'api', description: 'The edge service'}, {canonical: true});
|
|
62
|
+
//=> "description: 'The edge service'\nname: 'api'\n"
|
|
33
63
|
```
|
|
34
64
|
*/
|
|
35
65
|
export declare function stringify(value: object, options?: StringifyOptions): string;
|
|
66
|
+
/**
|
|
67
|
+
Serialize one value as it is written in a document: a scalar on one line, and an object or an array in braces or brackets over several lines, with each level indented by one more tab. There is no line feed at the end.
|
|
68
|
+
|
|
69
|
+
For showing a value, as in a message, or for writing it into a template. Use `stringify()` to write a whole document, and `edit()` to change a value in one.
|
|
70
|
+
|
|
71
|
+
It takes the same values and options as `stringify()`, and any of them at the top level, so `1.5` gives `'1.5'` and `'it\'s'` gives `"it's"`. Members keep their order, as in `stringify()`, unless the `canonical: true` option sorts them.
|
|
72
|
+
|
|
73
|
+
@param value - A value of any type that `stringify()` accepts in a document.
|
|
74
|
+
@param options - How an int is represented in `value`, and whether to sort members.
|
|
75
|
+
@returns The value as it is written in a document.
|
|
76
|
+
@throws {TypeError} For a value that cannot be represented, as for `stringify()`, and for `undefined`.
|
|
77
|
+
@throws {RangeError} For a value out of range, as for `stringify()`.
|
|
78
|
+
|
|
79
|
+
@example
|
|
80
|
+
```
|
|
81
|
+
import {stringifyValue} from 'soml-lang';
|
|
82
|
+
|
|
83
|
+
stringifyValue(0.1 + 0.2);
|
|
84
|
+
//=> '0.30000000000000004'
|
|
85
|
+
|
|
86
|
+
stringifyValue(8080n);
|
|
87
|
+
//=> '8080'
|
|
88
|
+
|
|
89
|
+
stringifyValue({b: 1n, a: [true]});
|
|
90
|
+
//=> '{\n\tb: 1\n\ta: [\n\t\ttrue\n\t]\n}'
|
|
91
|
+
|
|
92
|
+
stringifyValue({b: 1n, a: [true]}, {canonical: true});
|
|
93
|
+
//=> '{\n\ta: [\n\t\ttrue\n\t]\n\tb: 1\n}'
|
|
94
|
+
```
|
|
95
|
+
*/
|
|
96
|
+
export declare function stringifyValue(value: unknown, options?: StringifyOptions): string;
|
|
97
|
+
/**
|
|
98
|
+
Compare two keys in canonical order, which is by their Unicode scalar values, as `stringify()` sorts members with the `canonical: true` option. For a sort, such as in a lint rule that keeps the members of an object in canonical order.
|
|
99
|
+
|
|
100
|
+
The default `Array#sort()` compares UTF-16 code units, which puts U+E000 to U+FFFF after every character above U+FFFF, so it differs from canonical order for keys that hold such characters.
|
|
101
|
+
|
|
102
|
+
@param left - A key.
|
|
103
|
+
@param right - Another key.
|
|
104
|
+
@returns A negative number when `left` comes first, a positive number when `right` comes first, and `0` when they are equal.
|
|
105
|
+
|
|
106
|
+
@example
|
|
107
|
+
```
|
|
108
|
+
import {compareKeys} from 'soml-lang';
|
|
109
|
+
|
|
110
|
+
['b', 'a', '😀', 'ff'].toSorted(compareKeys);
|
|
111
|
+
//=> ['a', 'b', 'ff', '😀']
|
|
112
|
+
```
|
|
113
|
+
*/
|
|
114
|
+
export declare function compareKeys(left: string, right: string): number;
|
|
115
|
+
export declare function formatKey(key: string): string;
|