@atproto/lex-data 0.0.8 → 0.0.10
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 +16 -0
- package/LICENSE.txt +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/lex-error.d.ts +3 -2
- package/dist/lex-error.d.ts.map +1 -1
- package/dist/lex-error.js +3 -2
- package/dist/lex-error.js.map +1 -1
- package/dist/uint8array.d.ts +1 -0
- package/dist/uint8array.d.ts.map +1 -1
- package/dist/uint8array.js +12 -6
- package/dist/uint8array.js.map +1 -1
- package/dist/utf8.d.ts.map +1 -1
- package/dist/utf8.js +4 -8
- package/dist/utf8.js.map +1 -1
- package/package.json +2 -3
- package/src/cid-implementation.test.ts +0 -2
- package/src/cid.test.ts +139 -34
- package/src/index.ts +0 -1
- package/src/lex-error.ts +3 -3
- package/src/uint8array.test.ts +24 -5
- package/src/uint8array.ts +13 -6
- package/src/utf8-len.test.ts +19 -28
- package/src/utf8.ts +4 -8
- package/dist/language.d.ts +0 -18
- package/dist/language.d.ts.map +0 -1
- package/dist/language.js +0 -30
- package/dist/language.js.map +0 -1
- package/src/language.test.ts +0 -88
- package/src/language.ts +0 -39
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atproto/lex-data
|
|
2
2
|
|
|
3
|
+
## 0.0.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Avoid exposing empty string as `message` in error payloads
|
|
8
|
+
|
|
9
|
+
## 0.0.9
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#4562](https://github.com/bluesky-social/atproto/pull/4562) [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add `ifUint8Array` utility function
|
|
14
|
+
|
|
15
|
+
- [#4571](https://github.com/bluesky-social/atproto/pull/4571) [`99963d0`](https://github.com/bluesky-social/atproto/commit/99963d002a9e030e79aed5fba700e0a68f31e101) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Rename `isLanguageString` to `validateLanguage`
|
|
16
|
+
|
|
17
|
+
- [#4571](https://github.com/bluesky-social/atproto/pull/4571) [`99963d0`](https://github.com/bluesky-social/atproto/commit/99963d002a9e030e79aed5fba700e0a68f31e101) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve code coverage of tests
|
|
18
|
+
|
|
3
19
|
## 0.0.8
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/LICENSE.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Dual MIT/Apache-2.0 License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2022-
|
|
3
|
+
Copyright (c) 2022-2026 Bluesky Social PBC, and Contributors
|
|
4
4
|
|
|
5
5
|
Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
|
|
6
6
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
tslib_1.__exportStar(require("./blob.js"), exports);
|
|
5
5
|
tslib_1.__exportStar(require("./cid.js"), exports);
|
|
6
|
-
tslib_1.__exportStar(require("./language.js"), exports);
|
|
7
6
|
tslib_1.__exportStar(require("./lex-equals.js"), exports);
|
|
8
7
|
tslib_1.__exportStar(require("./lex-error.js"), exports);
|
|
9
8
|
tslib_1.__exportStar(require("./lex.js"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,oDAAyB;AACzB,mDAAwB;AACxB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,oDAAyB;AACzB,mDAAwB;AACxB,0DAA+B;AAC/B,yDAA8B;AAC9B,mDAAwB;AACxB,sDAA2B;AAC3B,0DAA+B;AAC/B,oDAAyB","sourcesContent":["export * from './blob.js'\nexport * from './cid.js'\nexport * from './lex-equals.js'\nexport * from './lex-error.js'\nexport * from './lex.js'\nexport * from './object.js'\nexport * from './uint8array.js'\nexport * from './utf8.js'\n"]}
|
package/dist/lex-error.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type LexErrorCode = string
|
|
1
|
+
export type LexErrorCode = string & NonNullable<unknown>;
|
|
2
2
|
export type LexErrorData<N extends LexErrorCode = LexErrorCode> = {
|
|
3
3
|
error: N;
|
|
4
4
|
message?: string;
|
|
@@ -6,7 +6,8 @@ export type LexErrorData<N extends LexErrorCode = LexErrorCode> = {
|
|
|
6
6
|
export declare class LexError<N extends LexErrorCode = LexErrorCode> extends Error {
|
|
7
7
|
readonly error: N;
|
|
8
8
|
name: string;
|
|
9
|
-
constructor(error: N, message?: string,
|
|
9
|
+
constructor(error: N, message?: string, // Defaults to empty string in Error constructor
|
|
10
|
+
options?: ErrorOptions);
|
|
10
11
|
toString(): string;
|
|
11
12
|
toJSON(): LexErrorData<N>;
|
|
12
13
|
/**
|
package/dist/lex-error.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lex-error.d.ts","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"lex-error.d.ts","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;AAExD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI;IAChE,KAAK,EAAE,CAAC,CAAA;IACR,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,qBAAa,QAAQ,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,CAAE,SAAQ,KAAK;IAItE,QAAQ,CAAC,KAAK,EAAE,CAAC;IAHnB,IAAI,SAAa;gBAGN,KAAK,EAAE,CAAC,EACjB,OAAO,CAAC,EAAE,MAAM,EAAE,gDAAgD;IAClE,OAAO,CAAC,EAAE,YAAY;IAKxB,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC;IAKzB;;OAEG;IACH,UAAU,IAAI,QAAQ;CAGvB"}
|
package/dist/lex-error.js
CHANGED
|
@@ -4,7 +4,8 @@ exports.LexError = void 0;
|
|
|
4
4
|
class LexError extends Error {
|
|
5
5
|
error;
|
|
6
6
|
name = 'LexError';
|
|
7
|
-
constructor(error, message,
|
|
7
|
+
constructor(error, message, // Defaults to empty string in Error constructor
|
|
8
|
+
options) {
|
|
8
9
|
super(message, options);
|
|
9
10
|
this.error = error;
|
|
10
11
|
}
|
|
@@ -13,7 +14,7 @@ class LexError extends Error {
|
|
|
13
14
|
}
|
|
14
15
|
toJSON() {
|
|
15
16
|
const { error, message } = this;
|
|
16
|
-
return { error, message: message
|
|
17
|
+
return { error, message: message || undefined };
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Translate into an HTTP response for downstream clients.
|
package/dist/lex-error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lex-error.js","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":";;;AAOA,MAAa,QAAgD,SAAQ,KAAK;IAI7D;IAHX,IAAI,GAAG,UAAU,CAAA;IAEjB,YACW,KAAQ,EACjB,OAAgB,
|
|
1
|
+
{"version":3,"file":"lex-error.js","sourceRoot":"","sources":["../src/lex-error.ts"],"names":[],"mappings":";;;AAOA,MAAa,QAAgD,SAAQ,KAAK;IAI7D;IAHX,IAAI,GAAG,UAAU,CAAA;IAEjB,YACW,KAAQ,EACjB,OAAgB,EAAE,gDAAgD;IAClE,OAAsB;QAEtB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAJd,UAAK,GAAL,KAAK,CAAG;IAKnB,CAAC;IAED,QAAQ;QACN,OAAO,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,CAAA;IACxD,CAAC;IAED,MAAM;QACJ,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;QAC/B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,CAAA;IACjD,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACtD,CAAC;CACF;AA1BD,4BA0BC","sourcesContent":["export type LexErrorCode = string & NonNullable<unknown>\n\nexport type LexErrorData<N extends LexErrorCode = LexErrorCode> = {\n error: N\n message?: string\n}\n\nexport class LexError<N extends LexErrorCode = LexErrorCode> extends Error {\n name = 'LexError'\n\n constructor(\n readonly error: N,\n message?: string, // Defaults to empty string in Error constructor\n options?: ErrorOptions,\n ) {\n super(message, options)\n }\n\n toString(): string {\n return `${this.name}: [${this.error}] ${this.message}`\n }\n\n toJSON(): LexErrorData<N> {\n const { error, message } = this\n return { error, message: message || undefined }\n }\n\n /**\n * Translate into an HTTP response for downstream clients.\n */\n toResponse(): Response {\n return Response.json(this.toJSON(), { status: 400 })\n }\n}\n"]}
|
package/dist/uint8array.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare const toBase64: (bytes: Uint8Array, alphabet?: Base64Alphabet) =>
|
|
|
14
14
|
* @throws If the input is not a valid base64 string
|
|
15
15
|
*/
|
|
16
16
|
export declare const fromBase64: (b64: string, alphabet?: Base64Alphabet) => Uint8Array;
|
|
17
|
+
export declare function ifUint8Array(input: unknown): Uint8Array | undefined;
|
|
17
18
|
/**
|
|
18
19
|
* Coerces various binary data representations into a Uint8Array.
|
|
19
20
|
*
|
package/dist/uint8array.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array.d.ts","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAavD,YAAY,EAAE,cAAc,EAAE,CAAA;AAO9B;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,CACrB,KAAK,EAAE,UAAU,EACjB,QAAQ,CAAC,EAAE,cAAc,KACtB,
|
|
1
|
+
{"version":3,"file":"uint8array.d.ts","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAavD,YAAY,EAAE,cAAc,EAAE,CAAA;AAO9B;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,CACrB,KAAK,EAAE,UAAU,EACjB,QAAQ,CAAC,EAAE,cAAc,KACtB,MAGa,CAAA;AAElB;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,CACvB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,cAAc,KACtB,UAGe,CAAA;AAUpB,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAMnE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAkBnE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAY/D;AAED,eAAO,MAAM,SAAS,8CACgD,CAAA"}
|
package/dist/uint8array.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ui8Concat = exports.fromBase64 = exports.toBase64 = void 0;
|
|
4
|
+
exports.ifUint8Array = ifUint8Array;
|
|
4
5
|
exports.asUint8Array = asUint8Array;
|
|
5
6
|
exports.ui8Equals = ui8Equals;
|
|
6
7
|
const uint8array_concat_js_1 = require("./uint8array-concat.js");
|
|
@@ -17,8 +18,8 @@ const uint8array_to_base64_js_1 = require("./uint8array-to-base64.js");
|
|
|
17
18
|
*/
|
|
18
19
|
exports.toBase64 =
|
|
19
20
|
/* v8 ignore next -- @preserve */ uint8array_to_base64_js_1.toBase64Native ??
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
uint8array_to_base64_js_1.toBase64Node ??
|
|
22
|
+
uint8array_to_base64_js_1.toBase64Ponyfill;
|
|
22
23
|
/**
|
|
23
24
|
* Decodes a base64 string into a Uint8Array. This function supports both padded
|
|
24
25
|
* and unpadded base64 strings.
|
|
@@ -28,13 +29,19 @@ exports.toBase64 =
|
|
|
28
29
|
*/
|
|
29
30
|
exports.fromBase64 =
|
|
30
31
|
/* v8 ignore next -- @preserve */ uint8array_from_base64_js_1.fromBase64Native ??
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
uint8array_from_base64_js_1.fromBase64Node ??
|
|
33
|
+
uint8array_from_base64_js_1.fromBase64Ponyfill;
|
|
33
34
|
/* v8 ignore next -- @preserve */
|
|
34
35
|
if (exports.toBase64 === uint8array_to_base64_js_1.toBase64Ponyfill || exports.fromBase64 === uint8array_from_base64_js_1.fromBase64Ponyfill) {
|
|
35
36
|
/*#__PURE__*/
|
|
36
37
|
console.warn('[@atproto/lex-data]: Uint8Array.fromBase64 / Uint8Array.prototype.toBase64 not available in this environment. Falling back to ponyfill implementation.');
|
|
37
38
|
}
|
|
39
|
+
function ifUint8Array(input) {
|
|
40
|
+
if (input instanceof Uint8Array) {
|
|
41
|
+
return input;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
38
45
|
/**
|
|
39
46
|
* Coerces various binary data representations into a Uint8Array.
|
|
40
47
|
*
|
|
@@ -64,6 +71,5 @@ function ui8Equals(a, b) {
|
|
|
64
71
|
return true;
|
|
65
72
|
}
|
|
66
73
|
exports.ui8Concat =
|
|
67
|
-
/* v8 ignore next -- @preserve */ uint8array_concat_js_1.ui8ConcatNode ??
|
|
68
|
-
/* v8 ignore next -- @preserve */ uint8array_concat_js_1.ui8ConcatPonyfill;
|
|
74
|
+
/* v8 ignore next -- @preserve */ uint8array_concat_js_1.ui8ConcatNode ?? uint8array_concat_js_1.ui8ConcatPonyfill;
|
|
69
75
|
//# sourceMappingURL=uint8array.js.map
|
package/dist/uint8array.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uint8array.js","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"uint8array.js","sourceRoot":"","sources":["../src/uint8array.ts"],"names":[],"mappings":";;;AAwDA,oCAMC;AAOD,oCAkBC;AAED,8BAYC;AApGD,iEAAyE;AACzE,2EAIoC;AACpC,uEAIkC;AAIlC,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,0CAA0C;AAE1C;;;;GAIG;AACU,QAAA,QAAQ;AAInB,iCAAiC,CAAC,wCAAc;IAChD,sCAAY;IACZ,0CAAgB,CAAA;AAElB;;;;;;GAMG;AACU,QAAA,UAAU;AAIrB,iCAAiC,CAAC,4CAAgB;IAClD,0CAAc;IACd,8CAAkB,CAAA;AAEpB,iCAAiC;AACjC,IAAI,gBAAQ,KAAK,0CAAgB,IAAI,kBAAU,KAAK,8CAAkB,EAAE,CAAC;IACvE,aAAa;IACb,OAAO,CAAC,IAAI,CACV,wJAAwJ,CACzJ,CAAA;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,UAAU,CACnB,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAChD,CAAA;IACH,CAAC;IAED,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACjC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAgB,SAAS,CAAC,CAAa,EAAE,CAAa;IACpD,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAEY,QAAA,SAAS;AACpB,iCAAiC,CAAC,oCAAa,IAAI,wCAAiB,CAAA","sourcesContent":["import { Base64Alphabet } from './uint8array-base64.js'\nimport { ui8ConcatNode, ui8ConcatPonyfill } from './uint8array-concat.js'\nimport {\n fromBase64Native,\n fromBase64Node,\n fromBase64Ponyfill,\n} from './uint8array-from-base64.js'\nimport {\n toBase64Native,\n toBase64Node,\n toBase64Ponyfill,\n} from './uint8array-to-base64.js'\n\nexport type { Base64Alphabet }\n\n// @TODO drop dependency on uint8arrays package once Uint8Array.fromBase64 /\n// Uint8Array.prototype.toBase64 is widely supported, and mark fromBase64 /\n// toBase64 as deprecated. We can also drop NodeJS specific implementations\n// once NodeJS <24 is no longer supported.\n\n/**\n * Encodes a Uint8Array into a base64 string.\n *\n * @returns The base64 encoded string\n */\nexport const toBase64: (\n bytes: Uint8Array,\n alphabet?: Base64Alphabet,\n) => string =\n /* v8 ignore next -- @preserve */ toBase64Native ??\n toBase64Node ??\n toBase64Ponyfill\n\n/**\n * Decodes a base64 string into a Uint8Array. This function supports both padded\n * and unpadded base64 strings.\n *\n * @returns The decoded {@link Uint8Array}\n * @throws If the input is not a valid base64 string\n */\nexport const fromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => Uint8Array =\n /* v8 ignore next -- @preserve */ fromBase64Native ??\n fromBase64Node ??\n fromBase64Ponyfill\n\n/* v8 ignore next -- @preserve */\nif (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Uint8Array.fromBase64 / Uint8Array.prototype.toBase64 not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\nexport function ifUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n return undefined\n}\n\n/**\n * Coerces various binary data representations into a Uint8Array.\n *\n * @return `undefined` if the input could not be coerced into a {@link Uint8Array}.\n */\nexport function asUint8Array(input: unknown): Uint8Array | undefined {\n if (input instanceof Uint8Array) {\n return input\n }\n\n if (ArrayBuffer.isView(input)) {\n return new Uint8Array(\n input.buffer,\n input.byteOffset,\n input.byteLength / Uint8Array.BYTES_PER_ELEMENT,\n )\n }\n\n if (input instanceof ArrayBuffer) {\n return new Uint8Array(input)\n }\n\n return undefined\n}\n\nexport function ui8Equals(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) {\n return false\n }\n\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] !== b[i]) {\n return false\n }\n }\n\n return true\n}\n\nexport const ui8Concat =\n /* v8 ignore next -- @preserve */ ui8ConcatNode ?? ui8ConcatPonyfill\n"]}
|
package/dist/utf8.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utf8.d.ts","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAShD,eAAO,MAAM,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"utf8.d.ts","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAShD,eAAO,MAAM,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MACiC,CAAA;AAU5E,eAAO,MAAM,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MACuB,CAAA;AAEjE,eAAO,MAAM,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,MACK,CAAA;AAE5E,eAAO,MAAM,cAAc,EAAE,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,cAAc,KACtB,MAC2E,CAAA"}
|
package/dist/utf8.js
CHANGED
|
@@ -6,20 +6,16 @@ const utf8_grapheme_len_js_1 = require("./utf8-grapheme-len.js");
|
|
|
6
6
|
const utf8_len_js_1 = require("./utf8-len.js");
|
|
7
7
|
const utf8_to_base64_js_1 = require("./utf8-to-base64.js");
|
|
8
8
|
exports.graphemeLen =
|
|
9
|
-
/* v8 ignore next -- @preserve */ utf8_grapheme_len_js_1.graphemeLenNative ??
|
|
10
|
-
/* v8 ignore next -- @preserve */ utf8_grapheme_len_js_1.graphemeLenPonyfill;
|
|
9
|
+
/* v8 ignore next -- @preserve */ utf8_grapheme_len_js_1.graphemeLenNative ?? utf8_grapheme_len_js_1.graphemeLenPonyfill;
|
|
11
10
|
/* v8 ignore next -- @preserve */
|
|
12
11
|
if (exports.graphemeLen === utf8_grapheme_len_js_1.graphemeLenPonyfill) {
|
|
13
12
|
/*#__PURE__*/
|
|
14
13
|
console.warn('[@atproto/lex-data]: Intl.Segmenter is not available in this environment. Falling back to ponyfill implementation.');
|
|
15
14
|
}
|
|
16
15
|
exports.utf8Len =
|
|
17
|
-
/* v8 ignore next -- @preserve */ utf8_len_js_1.utf8LenNode ??
|
|
18
|
-
/* v8 ignore next -- @preserve */ utf8_len_js_1.utf8LenCompute;
|
|
16
|
+
/* v8 ignore next -- @preserve */ utf8_len_js_1.utf8LenNode ?? utf8_len_js_1.utf8LenCompute;
|
|
19
17
|
exports.utf8ToBase64 =
|
|
20
|
-
/* v8 ignore next -- @preserve */ utf8_to_base64_js_1.utf8ToBase64Node ??
|
|
21
|
-
/* v8 ignore next -- @preserve */ utf8_to_base64_js_1.utf8ToBase64Ponyfill;
|
|
18
|
+
/* v8 ignore next -- @preserve */ utf8_to_base64_js_1.utf8ToBase64Node ?? utf8_to_base64_js_1.utf8ToBase64Ponyfill;
|
|
22
19
|
exports.utf8FromBase64 =
|
|
23
|
-
/* v8 ignore next -- @preserve */ utf8_from_base64_js_1.utf8FromBase64Node ??
|
|
24
|
-
/* v8 ignore next -- @preserve */ utf8_from_base64_js_1.utf8FromBase64Ponyfill;
|
|
20
|
+
/* v8 ignore next -- @preserve */ utf8_from_base64_js_1.utf8FromBase64Node ?? utf8_from_base64_js_1.utf8FromBase64Ponyfill;
|
|
25
21
|
//# sourceMappingURL=utf8.js.map
|
package/dist/utf8.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utf8.js","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":";;;AACA,+DAG8B;AAC9B,iEAA+E;AAC/E,+CAA2D;AAC3D,2DAA4E;AAE/D,QAAA,WAAW;AACtB,iCAAiC,CAAC,wCAAiB
|
|
1
|
+
{"version":3,"file":"utf8.js","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":";;;AACA,+DAG8B;AAC9B,iEAA+E;AAC/E,+CAA2D;AAC3D,2DAA4E;AAE/D,QAAA,WAAW;AACtB,iCAAiC,CAAC,wCAAiB,IAAI,0CAAmB,CAAA;AAE5E,iCAAiC;AACjC,IAAI,mBAAW,KAAK,0CAAmB,EAAE,CAAC;IACxC,aAAa;IACb,OAAO,CAAC,IAAI,CACV,oHAAoH,CACrH,CAAA;AACH,CAAC;AAEY,QAAA,OAAO;AAClB,iCAAiC,CAAC,yBAAW,IAAI,4BAAc,CAAA;AAEpD,QAAA,YAAY;AACvB,iCAAiC,CAAC,oCAAgB,IAAI,wCAAoB,CAAA;AAE/D,QAAA,cAAc;AAIzB,iCAAiC,CAAC,wCAAkB,IAAI,4CAAsB,CAAA","sourcesContent":["import { Base64Alphabet } from './uint8array.js'\nimport {\n utf8FromBase64Node,\n utf8FromBase64Ponyfill,\n} from './utf8-from-base64.js'\nimport { graphemeLenNative, graphemeLenPonyfill } from './utf8-grapheme-len.js'\nimport { utf8LenCompute, utf8LenNode } from './utf8-len.js'\nimport { utf8ToBase64Node, utf8ToBase64Ponyfill } from './utf8-to-base64.js'\n\nexport const graphemeLen: (str: string) => number =\n /* v8 ignore next -- @preserve */ graphemeLenNative ?? graphemeLenPonyfill\n\n/* v8 ignore next -- @preserve */\nif (graphemeLen === graphemeLenPonyfill) {\n /*#__PURE__*/\n console.warn(\n '[@atproto/lex-data]: Intl.Segmenter is not available in this environment. Falling back to ponyfill implementation.',\n )\n}\n\nexport const utf8Len: (string: string) => number =\n /* v8 ignore next -- @preserve */ utf8LenNode ?? utf8LenCompute\n\nexport const utf8ToBase64: (str: string, alphabet?: Base64Alphabet) => string =\n /* v8 ignore next -- @preserve */ utf8ToBase64Node ?? utf8ToBase64Ponyfill\n\nexport const utf8FromBase64: (\n b64: string,\n alphabet?: Base64Alphabet,\n) => string =\n /* v8 ignore next -- @preserve */ utf8FromBase64Node ?? utf8FromBase64Ponyfill\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lex-data",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Core utilities for AT Lexicons",
|
|
6
6
|
"keywords": [
|
|
@@ -38,8 +38,7 @@
|
|
|
38
38
|
"multiformats": "^9.9.0",
|
|
39
39
|
"tslib": "^2.8.1",
|
|
40
40
|
"uint8arrays": "3.0.0",
|
|
41
|
-
"unicode-segmenter": "^0.14.0"
|
|
42
|
-
"@atproto/syntax": "0.4.2"
|
|
41
|
+
"unicode-segmenter": "^0.14.0"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
44
|
"core-js": "^3",
|
package/src/cid.test.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint-disable import/no-deprecated */
|
|
2
|
-
|
|
3
1
|
import { CID } from 'multiformats/cid'
|
|
4
2
|
import { sha256, sha512 } from 'multiformats/hashes/sha2'
|
|
5
3
|
import { describe, expect, it } from 'vitest'
|
|
@@ -14,6 +12,7 @@ import {
|
|
|
14
12
|
decodeCid,
|
|
15
13
|
ensureValidCidString,
|
|
16
14
|
isCid,
|
|
15
|
+
isCidForBytes,
|
|
17
16
|
parseCid,
|
|
18
17
|
parseCidSafe,
|
|
19
18
|
} from './cid.js'
|
|
@@ -27,13 +26,13 @@ const cborCid = parseCid(cborCidStr, { flavor: 'cbor' })
|
|
|
27
26
|
const rawCidStr = 'bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4'
|
|
28
27
|
const rawCid = parseCid(rawCidStr, { flavor: 'raw' })
|
|
29
28
|
|
|
30
|
-
const
|
|
29
|
+
const rawCidLike: Cid = createCustomCid(
|
|
31
30
|
1,
|
|
32
31
|
RAW_MULTICODEC,
|
|
33
32
|
SHA256_MULTIHASH,
|
|
34
33
|
rawCid.multihash.digest,
|
|
35
34
|
)
|
|
36
|
-
const
|
|
35
|
+
const rawBytesCid = new BytesCid(rawCid.bytes)
|
|
37
36
|
|
|
38
37
|
describe(isCid, () => {
|
|
39
38
|
describe('non-strict mode', () => {
|
|
@@ -43,8 +42,8 @@ describe(isCid, () => {
|
|
|
43
42
|
})
|
|
44
43
|
|
|
45
44
|
it('returns true for custom compatible CID implementations', () => {
|
|
46
|
-
expect(isCid(
|
|
47
|
-
expect(isCid(
|
|
45
|
+
expect(isCid(rawCidLike)).toBe(true)
|
|
46
|
+
expect(isCid(rawBytesCid)).toBe(true)
|
|
48
47
|
})
|
|
49
48
|
|
|
50
49
|
it('returns true for CID v0 and v1', async () => {
|
|
@@ -118,50 +117,125 @@ describe(isCid, () => {
|
|
|
118
117
|
|
|
119
118
|
describe('alternative cid implementations', () => {
|
|
120
119
|
it('accepts compatible CID implementations', () => {
|
|
121
|
-
expect(isCid(
|
|
120
|
+
expect(isCid(rawCidLike)).toBe(true)
|
|
122
121
|
})
|
|
123
122
|
|
|
124
123
|
it('rejects non-matching version', () => {
|
|
125
|
-
expect(isCid({ ...
|
|
124
|
+
expect(isCid({ ...rawCidLike, version: 0 })).toBe(false)
|
|
126
125
|
})
|
|
127
126
|
|
|
128
127
|
it('rejects non-matching code', () => {
|
|
129
|
-
expect(isCid({ ...
|
|
128
|
+
expect(isCid({ ...rawCidLike, code: -1 })).toBe(false)
|
|
129
|
+
expect(isCid({ ...rawCidLike, code: 0 })).toBe(false)
|
|
130
|
+
expect(isCid({ ...rawCidLike, code: 256 })).toBe(false)
|
|
130
131
|
})
|
|
131
132
|
|
|
132
|
-
it('rejects
|
|
133
|
-
expect(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}),
|
|
138
|
-
).toBe(false)
|
|
139
|
-
})
|
|
133
|
+
it('rejects invalid bytes property', () => {
|
|
134
|
+
expect(isCid({ ...rawCidLike, bytes: undefined })).toBe(false)
|
|
135
|
+
expect(isCid({ ...rawCidLike, bytes: 12 })).toBe(false)
|
|
136
|
+
expect(isCid({ ...rawCidLike, bytes: {} })).toBe(false)
|
|
137
|
+
expect(isCid({ ...rawCidLike, bytes: [] })).toBe(false)
|
|
140
138
|
|
|
141
|
-
it('rejects non-matching multihash digest', () => {
|
|
142
|
-
const differentDigest = new Uint8Array(32)
|
|
143
|
-
differentDigest[0] = 1
|
|
144
139
|
expect(
|
|
145
140
|
isCid({
|
|
146
|
-
...
|
|
147
|
-
|
|
141
|
+
...rawCidLike,
|
|
142
|
+
bytes: rawCidLike.bytes.subarray(0, rawCidLike.bytes.length - 1),
|
|
148
143
|
}),
|
|
149
144
|
).toBe(false)
|
|
145
|
+
|
|
146
|
+
const bytes = new Uint8Array(rawCidLike.bytes.length)
|
|
147
|
+
|
|
148
|
+
bytes.set(rawCidLike.bytes)
|
|
149
|
+
expect(isCid({ ...rawCidLike, bytes })).toBe(true)
|
|
150
|
+
|
|
151
|
+
bytes[0] = bytes[0] ^ 0xff
|
|
152
|
+
expect(isCid({ ...rawCidLike, bytes })).toBe(false)
|
|
153
|
+
bytes.set(rawCidLike.bytes)
|
|
154
|
+
|
|
155
|
+
bytes[3] = bytes[3] ^ 0xff
|
|
156
|
+
expect(isCid({ ...rawCidLike, bytes })).toBe(false)
|
|
157
|
+
bytes.set(rawCidLike.bytes)
|
|
158
|
+
|
|
159
|
+
bytes[6] = bytes[6] ^ 0xff
|
|
160
|
+
expect(isCid({ ...rawCidLike, bytes })).toBe(false)
|
|
161
|
+
bytes.set(rawCidLike.bytes)
|
|
150
162
|
})
|
|
151
163
|
|
|
152
|
-
|
|
153
|
-
|
|
164
|
+
describe('multihash property', () => {
|
|
165
|
+
it('rejects non-matching object', () => {
|
|
166
|
+
expect(isCid({ ...rawCidLike, multihash: undefined })).toBe(false)
|
|
167
|
+
expect(isCid({ ...rawCidLike, multihash: 12 })).toBe(false)
|
|
168
|
+
expect(isCid({ ...rawCidLike, multihash: {} })).toBe(false)
|
|
169
|
+
expect(isCid({ ...rawCidLike, multihash: [] })).toBe(false)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('rejects non-matching code', () => {
|
|
173
|
+
expect(
|
|
174
|
+
isCid({
|
|
175
|
+
...rawCidLike,
|
|
176
|
+
multihash: { ...rawCidLike.multihash, code: -1 },
|
|
177
|
+
}),
|
|
178
|
+
).toBe(false)
|
|
179
|
+
expect(
|
|
180
|
+
isCid({
|
|
181
|
+
...rawCidLike,
|
|
182
|
+
multihash: { ...rawCidLike.multihash, code: 0 },
|
|
183
|
+
}),
|
|
184
|
+
).toBe(false)
|
|
185
|
+
expect(
|
|
186
|
+
isCid({
|
|
187
|
+
...rawCidLike,
|
|
188
|
+
multihash: { ...rawCidLike.multihash, code: 256 },
|
|
189
|
+
}),
|
|
190
|
+
).toBe(false)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('rejects non Uint8Array digest', () => {
|
|
194
|
+
expect(
|
|
195
|
+
isCid({
|
|
196
|
+
...rawCidLike,
|
|
197
|
+
multihash: { ...rawCidLike.multihash, digest: new Array(32) },
|
|
198
|
+
}),
|
|
199
|
+
).toBe(false)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('rejects non Uint8Array digest', () => {
|
|
203
|
+
expect(
|
|
204
|
+
isCid({
|
|
205
|
+
...rawCidLike,
|
|
206
|
+
multihash: { ...rawCidLike.multihash, digest: new Array(32) },
|
|
207
|
+
}),
|
|
208
|
+
).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('rejects non-matching digest', () => {
|
|
212
|
+
const differentDigest = new Uint8Array(32)
|
|
213
|
+
differentDigest[0] = 1
|
|
214
|
+
expect(
|
|
215
|
+
isCid({
|
|
216
|
+
...rawCidLike,
|
|
217
|
+
multihash: { ...rawCidLike.multihash, digest: differentDigest },
|
|
218
|
+
}),
|
|
219
|
+
).toBe(false)
|
|
220
|
+
})
|
|
154
221
|
})
|
|
155
222
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
isCid({
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
223
|
+
describe('equals() method', () => {
|
|
224
|
+
it('rejects objects without equals method', () => {
|
|
225
|
+
expect(isCid({ ...rawCidLike, equals: undefined })).toBe(false)
|
|
226
|
+
expect(isCid({ ...rawCidLike, equals: () => false })).toBe(false)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('rejects object with throwing equals method', () => {
|
|
230
|
+
expect(
|
|
231
|
+
isCid({
|
|
232
|
+
...rawCidLike,
|
|
233
|
+
equals: () => {
|
|
234
|
+
throw new Error('fail')
|
|
235
|
+
},
|
|
236
|
+
}),
|
|
237
|
+
).toBe(false)
|
|
238
|
+
})
|
|
165
239
|
})
|
|
166
240
|
})
|
|
167
241
|
})
|
|
@@ -186,6 +260,37 @@ describe(parseCid, () => {
|
|
|
186
260
|
})
|
|
187
261
|
})
|
|
188
262
|
|
|
263
|
+
describe(isCidForBytes, () => {
|
|
264
|
+
describe('raw', () => {
|
|
265
|
+
it('returns true for valid raw CID bytes', async () => {
|
|
266
|
+
for (const hasher of [sha256, sha512]) {
|
|
267
|
+
const data = new TextEncoder().encode('hello world')
|
|
268
|
+
const digest = await hasher.digest(data)
|
|
269
|
+
const cid = CID.createV1(RAW_MULTICODEC, digest)
|
|
270
|
+
expect(await isCidForBytes(cid, data)).toBe(true)
|
|
271
|
+
|
|
272
|
+
data[0] = data[0] ^ 0xff
|
|
273
|
+
expect(await isCidForBytes(cid, data)).toBe(false)
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
describe('cbor', () => {
|
|
279
|
+
it('returns true for valid cbor CID bytes', async () => {
|
|
280
|
+
for (const hasher of [sha256, sha512]) {
|
|
281
|
+
// @NOTE this is not valid CBOR, but sufficient for testing the hash
|
|
282
|
+
const data = new TextEncoder().encode('hello world')
|
|
283
|
+
const digest = await hasher.digest(data)
|
|
284
|
+
const cid = CID.createV1(DAG_CBOR_MULTICODEC, digest)
|
|
285
|
+
expect(await isCidForBytes(cid, data)).toBe(true)
|
|
286
|
+
|
|
287
|
+
data[0] = data[0] ^ 0xff
|
|
288
|
+
expect(await isCidForBytes(cid, data)).toBe(false)
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
|
|
189
294
|
describe(parseCidSafe, () => {
|
|
190
295
|
it('parses valid CIDs', () => {
|
|
191
296
|
expect(parseCidSafe(cborCidStr)?.toString()).toBe(cborCidStr)
|
|
@@ -230,7 +335,7 @@ describe(cidForRawHash, () => {
|
|
|
230
335
|
|
|
231
336
|
describe(asMultiformatsCID, () => {
|
|
232
337
|
it('converts compatible CID to multiformats CID', () => {
|
|
233
|
-
for (const cid of [cborCid, rawCid,
|
|
338
|
+
for (const cid of [cborCid, rawCid, rawCidLike, rawBytesCid]) {
|
|
234
339
|
expect(asMultiformatsCID(cid)).toBeInstanceOf(CID)
|
|
235
340
|
expect(asMultiformatsCID(cid)).toMatchObject({
|
|
236
341
|
version: cid.version,
|
package/src/index.ts
CHANGED
package/src/lex-error.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type LexErrorCode = string
|
|
1
|
+
export type LexErrorCode = string & NonNullable<unknown>
|
|
2
2
|
|
|
3
3
|
export type LexErrorData<N extends LexErrorCode = LexErrorCode> = {
|
|
4
4
|
error: N
|
|
@@ -10,7 +10,7 @@ export class LexError<N extends LexErrorCode = LexErrorCode> extends Error {
|
|
|
10
10
|
|
|
11
11
|
constructor(
|
|
12
12
|
readonly error: N,
|
|
13
|
-
message?: string,
|
|
13
|
+
message?: string, // Defaults to empty string in Error constructor
|
|
14
14
|
options?: ErrorOptions,
|
|
15
15
|
) {
|
|
16
16
|
super(message, options)
|
|
@@ -22,7 +22,7 @@ export class LexError<N extends LexErrorCode = LexErrorCode> extends Error {
|
|
|
22
22
|
|
|
23
23
|
toJSON(): LexErrorData<N> {
|
|
24
24
|
const { error, message } = this
|
|
25
|
-
return { error, message: message
|
|
25
|
+
return { error, message: message || undefined }
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
package/src/uint8array.test.ts
CHANGED
|
@@ -5,12 +5,13 @@ import { describe, expect, it } from 'vitest'
|
|
|
5
5
|
import {
|
|
6
6
|
asUint8Array,
|
|
7
7
|
fromBase64,
|
|
8
|
+
ifUint8Array,
|
|
8
9
|
toBase64,
|
|
9
10
|
ui8Concat,
|
|
10
11
|
ui8Equals,
|
|
11
12
|
} from './uint8array.js'
|
|
12
13
|
|
|
13
|
-
describe(
|
|
14
|
+
describe(toBase64, () => {
|
|
14
15
|
it('encodes empty Uint8Array', () => {
|
|
15
16
|
const encoded = toBase64(new Uint8Array(0))
|
|
16
17
|
expect(typeof encoded).toBe('string')
|
|
@@ -49,7 +50,7 @@ describe('toBase64', () => {
|
|
|
49
50
|
})
|
|
50
51
|
})
|
|
51
52
|
|
|
52
|
-
describe(
|
|
53
|
+
describe(fromBase64, () => {
|
|
53
54
|
it('decodes empty string', () => {
|
|
54
55
|
const decoded = fromBase64('')
|
|
55
56
|
expect(decoded).toBeInstanceOf(Uint8Array)
|
|
@@ -133,7 +134,7 @@ describe('roundtrip toBase64 <-> fromBase64', () => {
|
|
|
133
134
|
})
|
|
134
135
|
})
|
|
135
136
|
|
|
136
|
-
describe(
|
|
137
|
+
describe(asUint8Array, () => {
|
|
137
138
|
describe('Uint8Array input', () => {
|
|
138
139
|
it('returns same Uint8Array instance', () => {
|
|
139
140
|
const input = new Uint8Array([1, 2, 3])
|
|
@@ -294,7 +295,7 @@ describe('asUint8Array', () => {
|
|
|
294
295
|
})
|
|
295
296
|
})
|
|
296
297
|
|
|
297
|
-
describe(
|
|
298
|
+
describe(ui8Equals, () => {
|
|
298
299
|
describe('equal arrays', () => {
|
|
299
300
|
it('returns true for identical arrays', () => {
|
|
300
301
|
const a = new Uint8Array([1, 2, 3])
|
|
@@ -434,7 +435,25 @@ describe('ui8Equals', () => {
|
|
|
434
435
|
})
|
|
435
436
|
})
|
|
436
437
|
|
|
437
|
-
describe(
|
|
438
|
+
describe(ifUint8Array, () => {
|
|
439
|
+
it('returns the input if it is a Uint8Array', () => {
|
|
440
|
+
const input = new Uint8Array([1, 2, 3])
|
|
441
|
+
const result = ifUint8Array(input)
|
|
442
|
+
expect(result).toBe(input)
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
it('returns undefined for non-Uint8Array inputs', () => {
|
|
446
|
+
expect(ifUint8Array(null)).toBeUndefined()
|
|
447
|
+
expect(ifUint8Array(undefined)).toBeUndefined()
|
|
448
|
+
expect(ifUint8Array({})).toBeUndefined()
|
|
449
|
+
expect(ifUint8Array([])).toBeUndefined()
|
|
450
|
+
expect(ifUint8Array('string')).toBeUndefined()
|
|
451
|
+
expect(ifUint8Array(123)).toBeUndefined()
|
|
452
|
+
expect(ifUint8Array(true)).toBeUndefined()
|
|
453
|
+
})
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
describe(ui8Concat, () => {
|
|
438
457
|
it('concatenates empty array', () => {
|
|
439
458
|
const result = ui8Concat([])
|
|
440
459
|
expect(result).toBeInstanceOf(Uint8Array)
|
package/src/uint8array.ts
CHANGED
|
@@ -28,8 +28,8 @@ export const toBase64: (
|
|
|
28
28
|
alphabet?: Base64Alphabet,
|
|
29
29
|
) => string =
|
|
30
30
|
/* v8 ignore next -- @preserve */ toBase64Native ??
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
toBase64Node ??
|
|
32
|
+
toBase64Ponyfill
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Decodes a base64 string into a Uint8Array. This function supports both padded
|
|
@@ -43,8 +43,8 @@ export const fromBase64: (
|
|
|
43
43
|
alphabet?: Base64Alphabet,
|
|
44
44
|
) => Uint8Array =
|
|
45
45
|
/* v8 ignore next -- @preserve */ fromBase64Native ??
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
fromBase64Node ??
|
|
47
|
+
fromBase64Ponyfill
|
|
48
48
|
|
|
49
49
|
/* v8 ignore next -- @preserve */
|
|
50
50
|
if (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {
|
|
@@ -54,6 +54,14 @@ if (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {
|
|
|
54
54
|
)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export function ifUint8Array(input: unknown): Uint8Array | undefined {
|
|
58
|
+
if (input instanceof Uint8Array) {
|
|
59
|
+
return input
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return undefined
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
/**
|
|
58
66
|
* Coerces various binary data representations into a Uint8Array.
|
|
59
67
|
*
|
|
@@ -94,5 +102,4 @@ export function ui8Equals(a: Uint8Array, b: Uint8Array): boolean {
|
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
export const ui8Concat =
|
|
97
|
-
/* v8 ignore next -- @preserve */ ui8ConcatNode ??
|
|
98
|
-
/* v8 ignore next -- @preserve */ ui8ConcatPonyfill
|
|
105
|
+
/* v8 ignore next -- @preserve */ ui8ConcatNode ?? ui8ConcatPonyfill
|
package/src/utf8-len.test.ts
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import { utf8LenCompute, utf8LenNode } from './utf8-len.js'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
for (const utf8Len of [utf8LenNode!, utf8LenCompute!] as const) {
|
|
5
|
+
describe(utf8Len, () => {
|
|
6
|
+
it('computes utf8 string length', () => {
|
|
7
|
+
expect(utf8Len('a')).toBe(1)
|
|
8
|
+
expect(utf8Len('~')).toBe(1)
|
|
9
|
+
expect(utf8Len('ö')).toBe(2)
|
|
10
|
+
expect(utf8Len('ñ')).toBe(2)
|
|
11
|
+
expect(utf8Len('©')).toBe(2)
|
|
12
|
+
expect(utf8Len('⽘')).toBe(3)
|
|
13
|
+
expect(utf8Len('☎')).toBe(3)
|
|
14
|
+
expect(utf8Len('𓋓')).toBe(4)
|
|
15
|
+
expect(utf8Len('😀')).toBe(4)
|
|
16
|
+
expect(utf8Len('👨👩👧👧')).toBe(25)
|
|
17
|
+
// high surrogate with no low surrogate
|
|
18
|
+
expect(utf8Len('\uD83D')).toBe(3)
|
|
19
|
+
// low surrogate with no high surrogate
|
|
20
|
+
expect(utf8Len('\uDC00')).toBe(3)
|
|
21
|
+
})
|
|
16
22
|
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
describe(utf8LenCompute, () => {
|
|
20
|
-
it('computes utf8 string length', () => {
|
|
21
|
-
expect(utf8LenCompute('a')).toBe(1)
|
|
22
|
-
expect(utf8LenCompute('~')).toBe(1)
|
|
23
|
-
expect(utf8LenCompute('ö')).toBe(2)
|
|
24
|
-
expect(utf8LenCompute('ñ')).toBe(2)
|
|
25
|
-
expect(utf8LenCompute('©')).toBe(2)
|
|
26
|
-
expect(utf8LenCompute('⽘')).toBe(3)
|
|
27
|
-
expect(utf8LenCompute('☎')).toBe(3)
|
|
28
|
-
expect(utf8LenCompute('𓋓')).toBe(4)
|
|
29
|
-
expect(utf8LenCompute('😀')).toBe(4)
|
|
30
|
-
expect(utf8LenCompute('👨👩👧👧')).toBe(25)
|
|
31
|
-
})
|
|
32
|
-
})
|
|
23
|
+
}
|
package/src/utf8.ts
CHANGED
|
@@ -8,8 +8,7 @@ import { utf8LenCompute, utf8LenNode } from './utf8-len.js'
|
|
|
8
8
|
import { utf8ToBase64Node, utf8ToBase64Ponyfill } from './utf8-to-base64.js'
|
|
9
9
|
|
|
10
10
|
export const graphemeLen: (str: string) => number =
|
|
11
|
-
/* v8 ignore next -- @preserve */ graphemeLenNative ??
|
|
12
|
-
/* v8 ignore next -- @preserve */ graphemeLenPonyfill
|
|
11
|
+
/* v8 ignore next -- @preserve */ graphemeLenNative ?? graphemeLenPonyfill
|
|
13
12
|
|
|
14
13
|
/* v8 ignore next -- @preserve */
|
|
15
14
|
if (graphemeLen === graphemeLenPonyfill) {
|
|
@@ -20,16 +19,13 @@ if (graphemeLen === graphemeLenPonyfill) {
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
export const utf8Len: (string: string) => number =
|
|
23
|
-
/* v8 ignore next -- @preserve */ utf8LenNode ??
|
|
24
|
-
/* v8 ignore next -- @preserve */ utf8LenCompute
|
|
22
|
+
/* v8 ignore next -- @preserve */ utf8LenNode ?? utf8LenCompute
|
|
25
23
|
|
|
26
24
|
export const utf8ToBase64: (str: string, alphabet?: Base64Alphabet) => string =
|
|
27
|
-
/* v8 ignore next -- @preserve */ utf8ToBase64Node ??
|
|
28
|
-
/* v8 ignore next -- @preserve */ utf8ToBase64Ponyfill
|
|
25
|
+
/* v8 ignore next -- @preserve */ utf8ToBase64Node ?? utf8ToBase64Ponyfill
|
|
29
26
|
|
|
30
27
|
export const utf8FromBase64: (
|
|
31
28
|
b64: string,
|
|
32
29
|
alphabet?: Base64Alphabet,
|
|
33
30
|
) => string =
|
|
34
|
-
/* v8 ignore next -- @preserve */ utf8FromBase64Node ??
|
|
35
|
-
/* v8 ignore next -- @preserve */ utf8FromBase64Ponyfill
|
|
31
|
+
/* v8 ignore next -- @preserve */ utf8FromBase64Node ?? utf8FromBase64Ponyfill
|
package/dist/language.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export type LanguageTag = {
|
|
2
|
-
grandfathered?: string;
|
|
3
|
-
language?: string;
|
|
4
|
-
extlang?: string;
|
|
5
|
-
script?: string;
|
|
6
|
-
region?: string;
|
|
7
|
-
variant?: string;
|
|
8
|
-
extension?: string;
|
|
9
|
-
privateUse?: string;
|
|
10
|
-
};
|
|
11
|
-
export declare function parseLanguageString(input: string): LanguageTag | null;
|
|
12
|
-
/**
|
|
13
|
-
* Validates well-formed BCP 47 syntax
|
|
14
|
-
*
|
|
15
|
-
* @see {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.1}
|
|
16
|
-
*/
|
|
17
|
-
export declare function isLanguageString(input: string): boolean;
|
|
18
|
-
//# sourceMappingURL=language.d.ts.map
|
package/dist/language.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"language.d.ts","sourceRoot":"","sources":["../src/language.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAerE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvD"}
|
package/dist/language.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseLanguageString = parseLanguageString;
|
|
4
|
-
exports.isLanguageString = isLanguageString;
|
|
5
|
-
const BCP47_REGEXP = /^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?<privateUseA>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUseB>x(-[A-Za-z0-9]{1,8})+))$/;
|
|
6
|
-
function parseLanguageString(input) {
|
|
7
|
-
const parsed = input.match(BCP47_REGEXP);
|
|
8
|
-
if (!parsed?.groups)
|
|
9
|
-
return null;
|
|
10
|
-
const { groups } = parsed;
|
|
11
|
-
return {
|
|
12
|
-
grandfathered: groups.grandfathered,
|
|
13
|
-
language: groups.language,
|
|
14
|
-
extlang: groups.extlang,
|
|
15
|
-
script: groups.script,
|
|
16
|
-
region: groups.region,
|
|
17
|
-
variant: groups.variant,
|
|
18
|
-
extension: groups.extension,
|
|
19
|
-
privateUse: groups.privateUseA || groups.privateUseB,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Validates well-formed BCP 47 syntax
|
|
24
|
-
*
|
|
25
|
-
* @see {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.1}
|
|
26
|
-
*/
|
|
27
|
-
function isLanguageString(input) {
|
|
28
|
-
return BCP47_REGEXP.test(input);
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=language.js.map
|
package/dist/language.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"language.js","sourceRoot":"","sources":["../src/language.ts"],"names":[],"mappings":";;AAcA,kDAeC;AAOD,4CAEC;AAtCD,MAAM,YAAY,GAChB,mlBAAmlB,CAAA;AAarlB,SAAgB,mBAAmB,CAAC,KAAa;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IACxC,IAAI,CAAC,MAAM,EAAE,MAAM;QAAE,OAAO,IAAI,CAAA;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IACzB,OAAO;QACL,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW;KACrD,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,KAAa;IAC5C,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACjC,CAAC","sourcesContent":["const BCP47_REGEXP =\n /^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?<privateUseA>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUseB>x(-[A-Za-z0-9]{1,8})+))$/\n\nexport type LanguageTag = {\n grandfathered?: string\n language?: string\n extlang?: string\n script?: string\n region?: string\n variant?: string\n extension?: string\n privateUse?: string\n}\n\nexport function parseLanguageString(input: string): LanguageTag | null {\n const parsed = input.match(BCP47_REGEXP)\n if (!parsed?.groups) return null\n\n const { groups } = parsed\n return {\n grandfathered: groups.grandfathered,\n language: groups.language,\n extlang: groups.extlang,\n script: groups.script,\n region: groups.region,\n variant: groups.variant,\n extension: groups.extension,\n privateUse: groups.privateUseA || groups.privateUseB,\n }\n}\n\n/**\n * Validates well-formed BCP 47 syntax\n *\n * @see {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.1}\n */\nexport function isLanguageString(input: string): boolean {\n return BCP47_REGEXP.test(input)\n}\n"]}
|
package/src/language.test.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { isLanguageString, parseLanguageString } from './language'
|
|
3
|
-
|
|
4
|
-
describe('string', () => {
|
|
5
|
-
describe('languages', () => {
|
|
6
|
-
it('validates BCP 47', () => {
|
|
7
|
-
// valid
|
|
8
|
-
expect(isLanguageString('de')).toEqual(true)
|
|
9
|
-
expect(isLanguageString('de-CH')).toEqual(true)
|
|
10
|
-
expect(isLanguageString('de-DE-1901')).toEqual(true)
|
|
11
|
-
expect(isLanguageString('es-419')).toEqual(true)
|
|
12
|
-
expect(isLanguageString('sl-IT-nedis')).toEqual(true)
|
|
13
|
-
expect(isLanguageString('mn-Cyrl-MN')).toEqual(true)
|
|
14
|
-
expect(isLanguageString('x-fr-CH')).toEqual(true)
|
|
15
|
-
expect(
|
|
16
|
-
isLanguageString('en-GB-boont-r-extended-sequence-x-private'),
|
|
17
|
-
).toEqual(true)
|
|
18
|
-
expect(isLanguageString('sr-Cyrl')).toEqual(true)
|
|
19
|
-
expect(isLanguageString('hy-Latn-IT-arevela')).toEqual(true)
|
|
20
|
-
expect(isLanguageString('i-klingon')).toEqual(true)
|
|
21
|
-
// invalid
|
|
22
|
-
expect(isLanguageString('')).toEqual(false)
|
|
23
|
-
expect(isLanguageString('x')).toEqual(false)
|
|
24
|
-
expect(isLanguageString('de-CH-')).toEqual(false)
|
|
25
|
-
expect(isLanguageString('i-bad-grandfathered')).toEqual(false)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('parses BCP 47', () => {
|
|
29
|
-
// valid
|
|
30
|
-
expect(parseLanguageString('de')).toEqual({
|
|
31
|
-
language: 'de',
|
|
32
|
-
})
|
|
33
|
-
expect(parseLanguageString('de-CH')).toEqual({
|
|
34
|
-
language: 'de',
|
|
35
|
-
region: 'CH',
|
|
36
|
-
})
|
|
37
|
-
expect(parseLanguageString('de-DE-1901')).toEqual({
|
|
38
|
-
language: 'de',
|
|
39
|
-
region: 'DE',
|
|
40
|
-
variant: '1901',
|
|
41
|
-
})
|
|
42
|
-
expect(parseLanguageString('es-419')).toEqual({
|
|
43
|
-
language: 'es',
|
|
44
|
-
region: '419',
|
|
45
|
-
})
|
|
46
|
-
expect(parseLanguageString('sl-IT-nedis')).toEqual({
|
|
47
|
-
language: 'sl',
|
|
48
|
-
region: 'IT',
|
|
49
|
-
variant: 'nedis',
|
|
50
|
-
})
|
|
51
|
-
expect(parseLanguageString('mn-Cyrl-MN')).toEqual({
|
|
52
|
-
language: 'mn',
|
|
53
|
-
script: 'Cyrl',
|
|
54
|
-
region: 'MN',
|
|
55
|
-
})
|
|
56
|
-
expect(parseLanguageString('x-fr-CH')).toEqual({
|
|
57
|
-
privateUse: 'x-fr-CH',
|
|
58
|
-
})
|
|
59
|
-
expect(
|
|
60
|
-
parseLanguageString('en-GB-boont-r-extended-sequence-x-private'),
|
|
61
|
-
).toEqual({
|
|
62
|
-
language: 'en',
|
|
63
|
-
region: 'GB',
|
|
64
|
-
variant: 'boont',
|
|
65
|
-
extension: 'r-extended-sequence',
|
|
66
|
-
privateUse: 'x-private',
|
|
67
|
-
})
|
|
68
|
-
expect(parseLanguageString('sr-Cyrl')).toEqual({
|
|
69
|
-
language: 'sr',
|
|
70
|
-
script: 'Cyrl',
|
|
71
|
-
})
|
|
72
|
-
expect(parseLanguageString('hy-Latn-IT-arevela')).toEqual({
|
|
73
|
-
language: 'hy',
|
|
74
|
-
script: 'Latn',
|
|
75
|
-
region: 'IT',
|
|
76
|
-
variant: 'arevela',
|
|
77
|
-
})
|
|
78
|
-
expect(parseLanguageString('i-klingon')).toEqual({
|
|
79
|
-
grandfathered: 'i-klingon',
|
|
80
|
-
})
|
|
81
|
-
// invalid
|
|
82
|
-
expect(parseLanguageString('')).toEqual(null)
|
|
83
|
-
expect(parseLanguageString('x')).toEqual(null)
|
|
84
|
-
expect(parseLanguageString('de-CH-')).toEqual(null)
|
|
85
|
-
expect(parseLanguageString('i-bad-grandfathered')).toEqual(null)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
})
|
package/src/language.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const BCP47_REGEXP =
|
|
2
|
-
/^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?<privateUseA>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUseB>x(-[A-Za-z0-9]{1,8})+))$/
|
|
3
|
-
|
|
4
|
-
export type LanguageTag = {
|
|
5
|
-
grandfathered?: string
|
|
6
|
-
language?: string
|
|
7
|
-
extlang?: string
|
|
8
|
-
script?: string
|
|
9
|
-
region?: string
|
|
10
|
-
variant?: string
|
|
11
|
-
extension?: string
|
|
12
|
-
privateUse?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function parseLanguageString(input: string): LanguageTag | null {
|
|
16
|
-
const parsed = input.match(BCP47_REGEXP)
|
|
17
|
-
if (!parsed?.groups) return null
|
|
18
|
-
|
|
19
|
-
const { groups } = parsed
|
|
20
|
-
return {
|
|
21
|
-
grandfathered: groups.grandfathered,
|
|
22
|
-
language: groups.language,
|
|
23
|
-
extlang: groups.extlang,
|
|
24
|
-
script: groups.script,
|
|
25
|
-
region: groups.region,
|
|
26
|
-
variant: groups.variant,
|
|
27
|
-
extension: groups.extension,
|
|
28
|
-
privateUse: groups.privateUseA || groups.privateUseB,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Validates well-formed BCP 47 syntax
|
|
34
|
-
*
|
|
35
|
-
* @see {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.1}
|
|
36
|
-
*/
|
|
37
|
-
export function isLanguageString(input: string): boolean {
|
|
38
|
-
return BCP47_REGEXP.test(input)
|
|
39
|
-
}
|