@atproto/lex-json 0.0.15 → 0.1.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/json.js CHANGED
@@ -1,3 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
3
2
  //# sourceMappingURL=json.js.map
@@ -1,4 +1,4 @@
1
- import { LexValue } from '@atproto/lex-data';
1
+ import { BlobRef, Cid, LexMap, LexValue } from '@atproto/lex-data';
2
2
  import { JsonValue } from './json.js';
3
3
  /**
4
4
  * Serialize a Lex value to a JSON string.
@@ -79,9 +79,9 @@ export type LexParseOptions = {
79
79
  */
80
80
  export declare function lexParse<T extends LexValue = LexValue>(input: string, options?: LexParseOptions): T;
81
81
  /**
82
- * Parses a `Uint8Array` containing JSON data into a Lex value.
82
+ * Parses a JSON string from a byte array into Lex values.
83
83
  */
84
- export declare function lexParseJsonBytes(jsonBytes: Uint8Array, options?: LexParseOptions): LexValue;
84
+ export declare function lexParseJsonBytes(bytes: Uint8Array, options?: LexParseOptions): LexValue;
85
85
  /**
86
86
  * Converts a parsed JSON representation of Lexicon value to a {@link LexValue}.
87
87
  *
@@ -140,4 +140,8 @@ export declare function jsonToLex(value: JsonValue, options?: LexParseOptions):
140
140
  * ```
141
141
  */
142
142
  export declare function lexToJson(value: LexValue): JsonValue;
143
+ /**
144
+ * @internal
145
+ */
146
+ export declare function parseSpecialJsonObject(input: LexMap, options: LexParseOptions): Cid | Uint8Array | BlobRef | undefined;
143
147
  //# sourceMappingURL=lex-json.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lex-json.d.ts","sourceRoot":"","sources":["../src/lex-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,QAAQ,EAGT,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAc,SAAS,EAAE,MAAM,WAAW,CAAA;AAGjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAKpD;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACpD,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAmC,GAC3C,CAAC,CAiBH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,EACrB,OAAO,CAAC,EAAE,eAAe,GACxB,QAAQ,CAWV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,eAAmC,GAC3C,QAAQ,CAsBV;AA+CD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAqBpD"}
1
+ {"version":3,"file":"lex-json.d.ts","sourceRoot":"","sources":["../src/lex-json.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,GAAG,EAEH,MAAM,EACN,QAAQ,EAGT,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAc,SAAS,EAAE,MAAM,WAAW,CAAA;AAGjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAKpD;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACpD,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAmC,GAC3C,CAAC,CAIH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE,eAAe,GACxB,QAAQ,CASV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,eAAmC,GAC3C,QAAQ,CAoBV;AA+CD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAqBpD;AAyCD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,GACvB,GAAG,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAiCxC"}
package/dist/lex-json.js CHANGED
@@ -1,14 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.lexStringify = lexStringify;
4
- exports.lexParse = lexParse;
5
- exports.lexParseJsonBytes = lexParseJsonBytes;
6
- exports.jsonToLex = jsonToLex;
7
- exports.lexToJson = lexToJson;
8
- const lex_data_1 = require("@atproto/lex-data");
9
- const blob_js_1 = require("./blob.js");
10
- const bytes_js_1 = require("./bytes.js");
11
- const link_js_1 = require("./link.js");
1
+ import { isCid, utf8FromBytes, } from '@atproto/lex-data';
2
+ import { parseTypedBlobRef } from './blob.js';
3
+ import { encodeLexBytes, parseLexBytes } from './bytes.js';
4
+ import { encodeLexLink, parseLexLink } from './link.js';
12
5
  /**
13
6
  * Serialize a Lex value to a JSON string.
14
7
  *
@@ -32,7 +25,7 @@ const link_js_1 = require("./link.js");
32
25
  * // json is '{"ref":{"$link":"bafyrei..."},"data":{"$bytes":"SGVsbG8="}}'
33
26
  * ```
34
27
  */
35
- function lexStringify(input) {
28
+ export function lexStringify(input) {
36
29
  // @NOTE Because of the way the "replacer" works in JSON.stringify, it's
37
30
  // simpler to convert Lex to JSON first rather than trying to do it
38
31
  // on-the-fly.
@@ -73,39 +66,23 @@ function lexStringify(input) {
73
66
  * const someBytes = lexParse<Uint8Array>('{"$bytes": "SGVsbG8sIHdvcmxkIQ=="}')
74
67
  * ```
75
68
  */
76
- function lexParse(input, options = { strict: false }) {
77
- return JSON.parse(input, function (key, value) {
78
- switch (typeof value) {
79
- case 'object':
80
- if (value === null)
81
- return null;
82
- if (Array.isArray(value))
83
- return value;
84
- return parseSpecialJsonObject(value, options) ?? value;
85
- case 'number':
86
- if (Number.isSafeInteger(value))
87
- return value;
88
- if (options.strict) {
89
- throw new TypeError(`Invalid non-integer number: ${value}`);
90
- }
91
- // fallthrough
92
- default:
93
- return value;
94
- }
95
- });
69
+ export function lexParse(input, options = { strict: false }) {
70
+ // @NOTE see ./lex-json.bench.ts for performance comparison of implementation
71
+ // that uses a reviver function in JSON.parse vs. the current implementation.
72
+ return jsonToLex(JSON.parse(input), options);
96
73
  }
97
74
  /**
98
- * Parses a `Uint8Array` containing JSON data into a Lex value.
75
+ * Parses a JSON string from a byte array into Lex values.
99
76
  */
100
- function lexParseJsonBytes(jsonBytes, options) {
101
- // @TODO optimize this to avoid intermediate string. This requires a custom
102
- // JSON parser that can operate on binary data, which is non-trivial, but
103
- // could be a future improvement if performance is a concern. See the link
104
- // below for an example of a JSON parser that operates on binary data in
105
- // @ipld/dag-json
106
- // https://github.com/ipld/js-dag-json/blob/57912da6e9d64a179f7d2384c3b6d7b07fbfb143/src/index.js#L161
107
- const jsonString = (0, lex_data_1.utf8FromBytes)(jsonBytes);
108
- return lexParse(jsonString, options);
77
+ export function lexParseJsonBytes(bytes, options) {
78
+ // @NOTE see ./json-bytes-decoder.bench.ts for performance comparison of
79
+ // implementation that uses a decoder class that operates directly on bytes
80
+ // vs. the current implementation that first decodes bytes to string and then
81
+ // parses JSON. For more common cases, it seems that the trivial
82
+ // implementation works better than the decoder based solution, while having a
83
+ // small overhead for slower cases (~2% difference). Because of this, we keep
84
+ // the trivial implementation:
85
+ return lexParse(utf8FromBytes(bytes), options);
109
86
  }
110
87
  /**
111
88
  * Converts a parsed JSON representation of Lexicon value to a {@link LexValue}.
@@ -136,7 +113,7 @@ function lexParseJsonBytes(jsonBytes, options) {
136
113
  * })
137
114
  * ```
138
115
  */
139
- function jsonToLex(value, options = { strict: false }) {
116
+ export function jsonToLex(value, options = { strict: false }) {
140
117
  switch (typeof value) {
141
118
  case 'object': {
142
119
  if (value === null)
@@ -149,10 +126,9 @@ function jsonToLex(value, options = { strict: false }) {
149
126
  case 'number':
150
127
  if (Number.isSafeInteger(value))
151
128
  return value;
152
- if (options.strict) {
153
- throw new TypeError(`Invalid non-integer number: ${value}`);
154
- }
155
- // fallthrough
129
+ if (options.strict === false)
130
+ return value;
131
+ throw new TypeError(`Invalid non-integer number: ${value}`);
156
132
  case 'boolean':
157
133
  case 'string':
158
134
  return value;
@@ -167,7 +143,7 @@ function jsonArrayToLex(input, options) {
167
143
  const inputItem = input[i];
168
144
  const item = jsonToLex(inputItem, options);
169
145
  if (item !== inputItem) {
170
- copy ?? (copy = Array.from(input));
146
+ copy ??= Array.from(input);
171
147
  copy[i] = item;
172
148
  }
173
149
  }
@@ -183,13 +159,13 @@ function jsonObjectToLexMap(input, options) {
183
159
  }
184
160
  // Ignore (strip) undefined values
185
161
  if (jsonValue === undefined) {
186
- copy ?? (copy = { ...input });
162
+ copy ??= { ...input };
187
163
  delete copy[key];
188
164
  continue;
189
165
  }
190
166
  const value = jsonToLex(jsonValue, options);
191
167
  if (value !== jsonValue) {
192
- copy ?? (copy = { ...input });
168
+ copy ??= { ...input };
193
169
  copy[key] = value;
194
170
  }
195
171
  }
@@ -222,7 +198,7 @@ function jsonObjectToLexMap(input, options) {
222
198
  * })
223
199
  * ```
224
200
  */
225
- function lexToJson(value) {
201
+ export function lexToJson(value) {
226
202
  switch (typeof value) {
227
203
  case 'object':
228
204
  if (value === null) {
@@ -231,11 +207,11 @@ function lexToJson(value) {
231
207
  else if (Array.isArray(value)) {
232
208
  return lexArrayToJson(value);
233
209
  }
234
- else if ((0, lex_data_1.isCid)(value)) {
235
- return (0, link_js_1.encodeLexLink)(value);
210
+ else if (isCid(value)) {
211
+ return encodeLexLink(value);
236
212
  }
237
213
  else if (ArrayBuffer.isView(value)) {
238
- return (0, bytes_js_1.encodeLexBytes)(value);
214
+ return encodeLexBytes(value);
239
215
  }
240
216
  else {
241
217
  return encodeLexMap(value);
@@ -255,7 +231,7 @@ function lexArrayToJson(input) {
255
231
  const inputItem = input[i];
256
232
  const item = lexToJson(inputItem);
257
233
  if (item !== inputItem) {
258
- copy ?? (copy = Array.from(input));
234
+ copy ??= Array.from(input);
259
235
  copy[i] = item;
260
236
  }
261
237
  }
@@ -271,29 +247,32 @@ function encodeLexMap(input) {
271
247
  }
272
248
  // Ignore (strip) undefined values
273
249
  if (lexValue === undefined) {
274
- copy ?? (copy = { ...input });
250
+ copy ??= { ...input };
275
251
  delete copy[key];
276
252
  continue;
277
253
  }
278
254
  const jsonValue = lexToJson(lexValue);
279
255
  if (jsonValue !== lexValue) {
280
- copy ?? (copy = { ...input });
256
+ copy ??= { ...input };
281
257
  copy[key] = jsonValue;
282
258
  }
283
259
  }
284
260
  return copy ?? input;
285
261
  }
286
- function parseSpecialJsonObject(input, options) {
262
+ /**
263
+ * @internal
264
+ */
265
+ export function parseSpecialJsonObject(input, options) {
287
266
  // Hot path: use hints to avoid parsing when possible
288
267
  if (input.$link !== undefined) {
289
- const cid = (0, link_js_1.parseLexLink)(input);
268
+ const cid = parseLexLink(input);
290
269
  if (cid)
291
270
  return cid;
292
271
  if (options.strict)
293
272
  throw new TypeError(`Invalid $link object`);
294
273
  }
295
274
  else if (input.$bytes !== undefined) {
296
- const bytes = (0, bytes_js_1.parseLexBytes)(input);
275
+ const bytes = parseLexBytes(input);
297
276
  if (bytes)
298
277
  return bytes;
299
278
  if (options.strict)
@@ -306,7 +285,7 @@ function parseSpecialJsonObject(input, options) {
306
285
  // the strict option is enabled.
307
286
  if (options.strict) {
308
287
  if (input.$type === 'blob') {
309
- const blob = (0, blob_js_1.parseTypedBlobRef)(input, options);
288
+ const blob = parseTypedBlobRef(input, options);
310
289
  if (blob)
311
290
  return blob;
312
291
  throw new TypeError(`Invalid blob object`);
@@ -1 +1 @@
1
- {"version":3,"file":"lex-json.js","sourceRoot":"","sources":["../src/lex-json.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BlobRef,\n Cid,\n LexArray,\n LexMap,\n LexValue,\n isCid,\n utf8FromBytes,\n} from '@atproto/lex-data'\nimport { parseTypedBlobRef } from './blob.js'\nimport { encodeLexBytes, parseLexBytes } from './bytes.js'\nimport { JsonObject, JsonValue } from './json.js'\nimport { encodeLexLink, parseLexLink } from './link.js'\n\n/**\n * Serialize a Lex value to a JSON string.\n *\n * This function serializes AT Protocol data model values to JSON, automatically\n * encoding special types:\n * - `Cid` instances are encoded as `{$link: string}`\n * - `Uint8Array` instances are encoded as `{$bytes: string}` (base64)\n *\n * @param input - The Lex value to stringify\n * @returns A JSON string representation of the value\n *\n * @example\n * ```typescript\n * import { lexStringify } from '@atproto/lex'\n *\n * // Stringify with CID and bytes encoding\n * const json = lexStringify({\n * ref: someCid,\n * data: new Uint8Array([72, 101, 108, 108, 111])\n * })\n * // json is '{\"ref\":{\"$link\":\"bafyrei...\"},\"data\":{\"$bytes\":\"SGVsbG8=\"}}'\n * ```\n */\nexport function lexStringify(input: LexValue): string {\n // @NOTE Because of the way the \"replacer\" works in JSON.stringify, it's\n // simpler to convert Lex to JSON first rather than trying to do it\n // on-the-fly.\n return JSON.stringify(lexToJson(input))\n}\n\n/**\n * Options for parsing JSON to Lex values.\n */\nexport type LexParseOptions = {\n /**\n * When enabled, forbids the presence of invalid Lex values such as:\n * - Non-integer numbers (only safe integers are valid in the Lex data model)\n * - Malformed `$link` objects\n * - Malformed `$bytes` objects\n * - Objects with invalid or empty `$type` properties\n * - Invalid {@link BlobRef} (`$type: 'blob'`) objects\n *\n * When disabled (default), invalid special objects are left as plain objects.\n *\n * @default false\n */\n strict?: boolean\n}\n\n/**\n * Parses a JSON string into Lex values.\n *\n * This function parses JSON and automatically decodes AT Protocol special types:\n * - `{$link: string}` objects are decoded to `Cid` instances\n * - `{$bytes: string}` objects are decoded to `Uint8Array` instances\n * - `{$type: 'blob'}` objects are validated\n *\n * @typeParam T - Type cast for the resulting Lex value. Use when you want to specify the expected structure of the parsed data.\n * @param input - The JSON string to parse\n * @param options - Parsing options (e.g., strict mode)\n * @returns The parsed Lex value\n * @throws {SyntaxError} If the input is not valid JSON\n * @throws {TypeError} If strict mode is enabled and invalid Lex values are found\n *\n * @example\n * ```typescript\n * import { lexParse } from '@atproto/lex'\n *\n * // Parse JSON with $link and $bytes decoding\n * const parsed = lexParse<{\n * ref: Cid\n * data: Uint8Array\n * }>(`{\n * \"ref\": { \"$link\": \"bafyrei...\" },\n * \"data\": { \"$bytes\": \"SGVsbG8sIHdvcmxkIQ==\" }\n * }`)\n *\n * // Parse a single CID\n * const someCid = lexParse<Cid>('{\"$link\": \"bafyrei...\"}')\n *\n * // Parse binary data\n * const someBytes = lexParse<Uint8Array>('{\"$bytes\": \"SGVsbG8sIHdvcmxkIQ==\"}')\n * ```\n */\nexport function lexParse<T extends LexValue = LexValue>(\n input: string,\n options: LexParseOptions = { strict: false },\n): T {\n return JSON.parse(input, function (key: string, value: JsonValue): LexValue {\n switch (typeof value) {\n case 'object':\n if (value === null) return null\n if (Array.isArray(value)) return value\n return parseSpecialJsonObject(value, options) ?? value\n case 'number':\n if (Number.isSafeInteger(value)) return value\n if (options.strict) {\n throw new TypeError(`Invalid non-integer number: ${value}`)\n }\n // fallthrough\n default:\n return value\n }\n })\n}\n\n/**\n * Parses a `Uint8Array` containing JSON data into a Lex value.\n */\nexport function lexParseJsonBytes(\n jsonBytes: Uint8Array,\n options?: LexParseOptions,\n): LexValue {\n // @TODO optimize this to avoid intermediate string. This requires a custom\n // JSON parser that can operate on binary data, which is non-trivial, but\n // could be a future improvement if performance is a concern. See the link\n // below for an example of a JSON parser that operates on binary data in\n // @ipld/dag-json\n\n // https://github.com/ipld/js-dag-json/blob/57912da6e9d64a179f7d2384c3b6d7b07fbfb143/src/index.js#L161\n\n const jsonString = utf8FromBytes(jsonBytes)\n return lexParse(jsonString, options)\n}\n\n/**\n * Converts a parsed JSON representation of Lexicon value to a {@link LexValue}.\n *\n * This function transforms already-parsed JSON objects into Lex values by\n * decoding AT Protocol special types:\n * - `{$link: string}` objects are converted to `Cid` instances\n * - `{$bytes: string}` objects are converted to `Uint8Array` instances\n *\n * Use this when you have a JavaScript object (e.g., from `JSON.parse()`) and\n * need to convert it to the Lex data model. For parsing JSON strings directly,\n * use {@link lexParse} instead.\n *\n * @param value - The JSON value to convert\n * @param options - Parsing options (e.g., strict mode)\n * @returns The converted Lex value\n * @throws {TypeError} If strict mode is enabled and invalid Lex values are found\n * @throws {TypeError} If the value contains unsupported types (e.g., undefined at top level)\n *\n * @example\n * ```typescript\n * import { jsonToLex } from '@atproto/lex'\n *\n * // Convert parsed JSON to Lex values\n * const lex = jsonToLex({\n * ref: { $link: 'bafyrei...' }, // Converted to Cid\n * data: { $bytes: 'SGVsbG8sIHdvcmxkIQ==' } // Converted to Uint8Array\n * })\n * ```\n */\nexport function jsonToLex(\n value: JsonValue,\n options: LexParseOptions = { strict: false },\n): LexValue {\n switch (typeof value) {\n case 'object': {\n if (value === null) return null\n if (Array.isArray(value)) return jsonArrayToLex(value, options)\n return (\n parseSpecialJsonObject(value, options) ??\n jsonObjectToLexMap(value, options)\n )\n }\n case 'number':\n if (Number.isSafeInteger(value)) return value\n if (options.strict) {\n throw new TypeError(`Invalid non-integer number: ${value}`)\n }\n // fallthrough\n case 'boolean':\n case 'string':\n return value\n default:\n throw new TypeError(`Invalid JSON value: ${typeof value}`)\n }\n}\n\nfunction jsonArrayToLex(\n input: JsonValue[],\n options: LexParseOptions,\n): LexValue[] {\n // Lazily copy value\n let copy: LexValue[] | undefined\n for (let i = 0; i < input.length; i++) {\n const inputItem = input[i]\n const item = jsonToLex(inputItem, options)\n if (item !== inputItem) {\n copy ??= Array.from(input)\n copy[i] = item\n }\n }\n return copy ?? input\n}\n\nfunction jsonObjectToLexMap(\n input: JsonObject,\n options: LexParseOptions,\n): LexMap {\n // Lazily copy value\n let copy: LexMap | undefined = undefined\n for (const [key, jsonValue] of Object.entries(input)) {\n // Prevent prototype pollution\n if (key === '__proto__') {\n throw new TypeError('Invalid key: __proto__')\n }\n\n // Ignore (strip) undefined values\n if (jsonValue === undefined) {\n copy ??= { ...input }\n delete copy[key]\n continue\n }\n\n const value = jsonToLex(jsonValue!, options)\n if (value !== jsonValue) {\n copy ??= { ...input }\n copy[key] = value\n }\n }\n return copy ?? input\n}\n\n/**\n * Converts a Lex value to a JSON-compatible value.\n *\n * This function transforms Lex data model values into plain JavaScript objects\n * suitable for JSON serialization:\n * - `Cid` instances are converted to `{$link: string}` objects\n * - `Uint8Array` instances are converted to `{$bytes: string}` objects (base64)\n *\n * Use this when you need to convert Lex values to plain objects (e.g., for\n * custom serialization or inspection). For direct JSON string output, use\n * {@link lexStringify} instead.\n *\n * @param value - The Lex value to convert\n * @returns The JSON-compatible value\n * @throws {TypeError} If the value contains unsupported types\n *\n * @example\n * ```typescript\n * import { lexToJson } from '@atproto/lex'\n *\n * // Convert Lex values to JSON-compatible objects\n * const obj = lexToJson({\n * ref: someCid, // Converted to { $link: string }\n * data: someBytes // Converted to { $bytes: string }\n * })\n * ```\n */\nexport function lexToJson(value: LexValue): JsonValue {\n switch (typeof value) {\n case 'object':\n if (value === null) {\n return value\n } else if (Array.isArray(value)) {\n return lexArrayToJson(value)\n } else if (isCid(value)) {\n return encodeLexLink(value)\n } else if (ArrayBuffer.isView(value)) {\n return encodeLexBytes(value)\n } else {\n return encodeLexMap(value)\n }\n case 'boolean':\n case 'string':\n case 'number':\n return value\n default:\n throw new TypeError(`Invalid Lex value: ${typeof value}`)\n }\n}\n\nfunction lexArrayToJson(input: LexArray): JsonValue[] {\n // Lazily copy value\n let copy: JsonValue[] | undefined\n for (let i = 0; i < input.length; i++) {\n const inputItem = input[i]\n const item = lexToJson(inputItem)\n if (item !== inputItem) {\n copy ??= Array.from(input) as JsonValue[]\n copy[i] = item\n }\n }\n return copy ?? (input as JsonValue[])\n}\n\nfunction encodeLexMap(input: LexMap): JsonObject {\n // Lazily copy value\n let copy: JsonObject | undefined = undefined\n for (const [key, lexValue] of Object.entries(input)) {\n // Prevent prototype pollution\n if (key === '__proto__') {\n throw new TypeError('Invalid key: __proto__')\n }\n\n // Ignore (strip) undefined values\n if (lexValue === undefined) {\n copy ??= { ...input } as JsonObject\n delete copy[key]\n continue\n }\n\n const jsonValue = lexToJson(lexValue!)\n if (jsonValue !== lexValue) {\n copy ??= { ...input } as JsonObject\n copy[key] = jsonValue\n }\n }\n return copy ?? (input as JsonObject)\n}\n\nfunction parseSpecialJsonObject(\n input: LexMap,\n options: LexParseOptions,\n): Cid | Uint8Array | BlobRef | undefined {\n // Hot path: use hints to avoid parsing when possible\n\n if (input.$link !== undefined) {\n const cid = parseLexLink(input)\n if (cid) return cid\n if (options.strict) throw new TypeError(`Invalid $link object`)\n } else if (input.$bytes !== undefined) {\n const bytes = parseLexBytes(input)\n if (bytes) return bytes\n if (options.strict) throw new TypeError(`Invalid $bytes object`)\n } else if (input.$type !== undefined) {\n // @NOTE Since blobs are \"just\" regular lex objects with a special shape,\n // and because an object that does not conform to the blob shape would still\n // result in undefined being returned, we only attempt to parse blobs when\n // the strict option is enabled.\n if (options.strict) {\n if (input.$type === 'blob') {\n const blob = parseTypedBlobRef(input, options)\n if (blob) return blob\n throw new TypeError(`Invalid blob object`)\n } else if (typeof input.$type !== 'string') {\n throw new TypeError(`Invalid $type property (${typeof input.$type})`)\n } else if (input.$type.length === 0) {\n throw new TypeError(`Empty $type property`)\n }\n }\n }\n\n // @NOTE We ignore legacy blob representation here. They can be handled at the\n // application level if needed.\n\n return undefined\n}\n"]}
1
+ {"version":3,"file":"lex-json.js","sourceRoot":"","sources":["../src/lex-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,EACL,aAAa,GACd,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAEvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,YAAY,CAAC,KAAe;IAC1C,wEAAwE;IACxE,mEAAmE;IACnE,cAAc;IACd,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;AACzC,CAAC;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAa,EACb,UAA2B,EAAE,MAAM,EAAE,KAAK,EAAE;IAE5C,6EAA6E;IAC7E,6EAA6E;IAC7E,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,CAAM,CAAA;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAiB,EACjB,OAAyB;IAEzB,wEAAwE;IACxE,2EAA2E;IAC3E,6EAA6E;IAC7E,gEAAgE;IAChE,8EAA8E;IAC9E,6EAA6E;IAC7E,8BAA8B;IAC9B,OAAO,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAA;AAChD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,SAAS,CACvB,KAAgB,EAChB,UAA2B,EAAE,MAAM,EAAE,KAAK,EAAE;IAE5C,QAAQ,OAAO,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAA;YAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;YAC/D,OAAO,CACL,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC;gBACtC,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,CACnC,CAAA;QACH,CAAC;QACD,KAAK,QAAQ;YACX,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;gBAAE,OAAO,KAAK,CAAA;YAC1C,MAAM,IAAI,SAAS,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAA;QAC7D,KAAK,SAAS,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,KAAK,CAAA;QACd;YACE,MAAM,IAAI,SAAS,CAAC,uBAAuB,OAAO,KAAK,EAAE,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CACrB,KAAkB,EAClB,OAAwB;IAExB,oBAAoB;IACpB,IAAI,IAA4B,CAAA;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAC1C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC1B,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,IAAI,KAAK,CAAA;AACtB,CAAC;AAED,SAAS,kBAAkB,CACzB,KAAiB,EACjB,OAAwB;IAExB,oBAAoB;IACpB,IAAI,IAAI,GAAuB,SAAS,CAAA;IACxC,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,8BAA8B;QAC9B,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAA;QAC/C,CAAC;QAED,kCAAkC;QAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,KAAK,EAAE,GAAG,KAAK,EAAE,CAAA;YACrB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;YAChB,SAAQ;QACV,CAAC;QAED,MAAM,KAAK,GAAG,SAAS,CAAC,SAAU,EAAE,OAAO,CAAC,CAAA;QAC5C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,KAAK,EAAE,GAAG,KAAK,EAAE,CAAA;YACrB,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,IAAI,KAAK,CAAA;AACtB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,SAAS,CAAC,KAAe;IACvC,QAAQ,OAAO,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,OAAO,KAAK,CAAA;YACd,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,OAAO,cAAc,CAAC,KAAK,CAAC,CAAA;YAC9B,CAAC;iBAAM,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,aAAa,CAAC,KAAK,CAAC,CAAA;YAC7B,CAAC;iBAAM,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,OAAO,cAAc,CAAC,KAAK,CAAC,CAAA;YAC9B,CAAC;iBAAM,CAAC;gBACN,OAAO,YAAY,CAAC,KAAK,CAAC,CAAA;YAC5B,CAAC;QACH,KAAK,SAAS,CAAC;QACf,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,KAAK,CAAA;QACd;YACE,MAAM,IAAI,SAAS,CAAC,sBAAsB,OAAO,KAAK,EAAE,CAAC,CAAA;IAC7D,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAe;IACrC,oBAAoB;IACpB,IAAI,IAA6B,CAAA;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1B,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,CAAA;QACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAgB,CAAA;YACzC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,IAAK,KAAqB,CAAA;AACvC,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,oBAAoB;IACpB,IAAI,IAAI,GAA2B,SAAS,CAAA;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,8BAA8B;QAC9B,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAA;QAC/C,CAAC;QAED,kCAAkC;QAClC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,KAAK,EAAE,GAAG,KAAK,EAAgB,CAAA;YACnC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;YAChB,SAAQ;QACV,CAAC;QAED,MAAM,SAAS,GAAG,SAAS,CAAC,QAAS,CAAC,CAAA;QACtC,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC3B,IAAI,KAAK,EAAE,GAAG,KAAK,EAAgB,CAAA;YACnC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;QACvB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,IAAK,KAAoB,CAAA;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAa,EACb,OAAwB;IAExB,qDAAqD;IAErD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;QAC/B,IAAI,GAAG;YAAE,OAAO,GAAG,CAAA;QACnB,IAAI,OAAO,CAAC,MAAM;YAAE,MAAM,IAAI,SAAS,CAAC,sBAAsB,CAAC,CAAA;IACjE,CAAC;SAAM,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QAClC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;QACvB,IAAI,OAAO,CAAC,MAAM;YAAE,MAAM,IAAI,SAAS,CAAC,uBAAuB,CAAC,CAAA;IAClE,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACrC,yEAAyE;QACzE,4EAA4E;QAC5E,0EAA0E;QAC1E,gCAAgC;QAChC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;gBAC3B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;gBAC9C,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAA;gBACrB,MAAM,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAAA;YAC5C,CAAC;iBAAM,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC3C,MAAM,IAAI,SAAS,CAAC,2BAA2B,OAAO,KAAK,CAAC,KAAK,GAAG,CAAC,CAAA;YACvE,CAAC;iBAAM,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpC,MAAM,IAAI,SAAS,CAAC,sBAAsB,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,+BAA+B;IAE/B,OAAO,SAAS,CAAA;AAClB,CAAC","sourcesContent":["import {\n BlobRef,\n Cid,\n LexArray,\n LexMap,\n LexValue,\n isCid,\n utf8FromBytes,\n} from '@atproto/lex-data'\nimport { parseTypedBlobRef } from './blob.js'\nimport { encodeLexBytes, parseLexBytes } from './bytes.js'\nimport { JsonObject, JsonValue } from './json.js'\nimport { encodeLexLink, parseLexLink } from './link.js'\n\n/**\n * Serialize a Lex value to a JSON string.\n *\n * This function serializes AT Protocol data model values to JSON, automatically\n * encoding special types:\n * - `Cid` instances are encoded as `{$link: string}`\n * - `Uint8Array` instances are encoded as `{$bytes: string}` (base64)\n *\n * @param input - The Lex value to stringify\n * @returns A JSON string representation of the value\n *\n * @example\n * ```typescript\n * import { lexStringify } from '@atproto/lex'\n *\n * // Stringify with CID and bytes encoding\n * const json = lexStringify({\n * ref: someCid,\n * data: new Uint8Array([72, 101, 108, 108, 111])\n * })\n * // json is '{\"ref\":{\"$link\":\"bafyrei...\"},\"data\":{\"$bytes\":\"SGVsbG8=\"}}'\n * ```\n */\nexport function lexStringify(input: LexValue): string {\n // @NOTE Because of the way the \"replacer\" works in JSON.stringify, it's\n // simpler to convert Lex to JSON first rather than trying to do it\n // on-the-fly.\n return JSON.stringify(lexToJson(input))\n}\n\n/**\n * Options for parsing JSON to Lex values.\n */\nexport type LexParseOptions = {\n /**\n * When enabled, forbids the presence of invalid Lex values such as:\n * - Non-integer numbers (only safe integers are valid in the Lex data model)\n * - Malformed `$link` objects\n * - Malformed `$bytes` objects\n * - Objects with invalid or empty `$type` properties\n * - Invalid {@link BlobRef} (`$type: 'blob'`) objects\n *\n * When disabled (default), invalid special objects are left as plain objects.\n *\n * @default false\n */\n strict?: boolean\n}\n\n/**\n * Parses a JSON string into Lex values.\n *\n * This function parses JSON and automatically decodes AT Protocol special types:\n * - `{$link: string}` objects are decoded to `Cid` instances\n * - `{$bytes: string}` objects are decoded to `Uint8Array` instances\n * - `{$type: 'blob'}` objects are validated\n *\n * @typeParam T - Type cast for the resulting Lex value. Use when you want to specify the expected structure of the parsed data.\n * @param input - The JSON string to parse\n * @param options - Parsing options (e.g., strict mode)\n * @returns The parsed Lex value\n * @throws {SyntaxError} If the input is not valid JSON\n * @throws {TypeError} If strict mode is enabled and invalid Lex values are found\n *\n * @example\n * ```typescript\n * import { lexParse } from '@atproto/lex'\n *\n * // Parse JSON with $link and $bytes decoding\n * const parsed = lexParse<{\n * ref: Cid\n * data: Uint8Array\n * }>(`{\n * \"ref\": { \"$link\": \"bafyrei...\" },\n * \"data\": { \"$bytes\": \"SGVsbG8sIHdvcmxkIQ==\" }\n * }`)\n *\n * // Parse a single CID\n * const someCid = lexParse<Cid>('{\"$link\": \"bafyrei...\"}')\n *\n * // Parse binary data\n * const someBytes = lexParse<Uint8Array>('{\"$bytes\": \"SGVsbG8sIHdvcmxkIQ==\"}')\n * ```\n */\nexport function lexParse<T extends LexValue = LexValue>(\n input: string,\n options: LexParseOptions = { strict: false },\n): T {\n // @NOTE see ./lex-json.bench.ts for performance comparison of implementation\n // that uses a reviver function in JSON.parse vs. the current implementation.\n return jsonToLex(JSON.parse(input), options) as T\n}\n\n/**\n * Parses a JSON string from a byte array into Lex values.\n */\nexport function lexParseJsonBytes(\n bytes: Uint8Array,\n options?: LexParseOptions,\n): LexValue {\n // @NOTE see ./json-bytes-decoder.bench.ts for performance comparison of\n // implementation that uses a decoder class that operates directly on bytes\n // vs. the current implementation that first decodes bytes to string and then\n // parses JSON. For more common cases, it seems that the trivial\n // implementation works better than the decoder based solution, while having a\n // small overhead for slower cases (~2% difference). Because of this, we keep\n // the trivial implementation:\n return lexParse(utf8FromBytes(bytes), options)\n}\n\n/**\n * Converts a parsed JSON representation of Lexicon value to a {@link LexValue}.\n *\n * This function transforms already-parsed JSON objects into Lex values by\n * decoding AT Protocol special types:\n * - `{$link: string}` objects are converted to `Cid` instances\n * - `{$bytes: string}` objects are converted to `Uint8Array` instances\n *\n * Use this when you have a JavaScript object (e.g., from `JSON.parse()`) and\n * need to convert it to the Lex data model. For parsing JSON strings directly,\n * use {@link lexParse} instead.\n *\n * @param value - The JSON value to convert\n * @param options - Parsing options (e.g., strict mode)\n * @returns The converted Lex value\n * @throws {TypeError} If strict mode is enabled and invalid Lex values are found\n * @throws {TypeError} If the value contains unsupported types (e.g., undefined at top level)\n *\n * @example\n * ```typescript\n * import { jsonToLex } from '@atproto/lex'\n *\n * // Convert parsed JSON to Lex values\n * const lex = jsonToLex({\n * ref: { $link: 'bafyrei...' }, // Converted to Cid\n * data: { $bytes: 'SGVsbG8sIHdvcmxkIQ==' } // Converted to Uint8Array\n * })\n * ```\n */\nexport function jsonToLex(\n value: JsonValue,\n options: LexParseOptions = { strict: false },\n): LexValue {\n switch (typeof value) {\n case 'object': {\n if (value === null) return null\n if (Array.isArray(value)) return jsonArrayToLex(value, options)\n return (\n parseSpecialJsonObject(value, options) ??\n jsonObjectToLexMap(value, options)\n )\n }\n case 'number':\n if (Number.isSafeInteger(value)) return value\n if (options.strict === false) return value\n throw new TypeError(`Invalid non-integer number: ${value}`)\n case 'boolean':\n case 'string':\n return value\n default:\n throw new TypeError(`Invalid JSON value: ${typeof value}`)\n }\n}\n\nfunction jsonArrayToLex(\n input: JsonValue[],\n options: LexParseOptions,\n): LexValue[] {\n // Lazily copy value\n let copy: LexValue[] | undefined\n for (let i = 0; i < input.length; i++) {\n const inputItem = input[i]\n const item = jsonToLex(inputItem, options)\n if (item !== inputItem) {\n copy ??= Array.from(input)\n copy[i] = item\n }\n }\n return copy ?? input\n}\n\nfunction jsonObjectToLexMap(\n input: JsonObject,\n options: LexParseOptions,\n): LexMap {\n // Lazily copy value\n let copy: LexMap | undefined = undefined\n for (const [key, jsonValue] of Object.entries(input)) {\n // Prevent prototype pollution\n if (key === '__proto__') {\n throw new TypeError('Invalid key: __proto__')\n }\n\n // Ignore (strip) undefined values\n if (jsonValue === undefined) {\n copy ??= { ...input }\n delete copy[key]\n continue\n }\n\n const value = jsonToLex(jsonValue!, options)\n if (value !== jsonValue) {\n copy ??= { ...input }\n copy[key] = value\n }\n }\n return copy ?? input\n}\n\n/**\n * Converts a Lex value to a JSON-compatible value.\n *\n * This function transforms Lex data model values into plain JavaScript objects\n * suitable for JSON serialization:\n * - `Cid` instances are converted to `{$link: string}` objects\n * - `Uint8Array` instances are converted to `{$bytes: string}` objects (base64)\n *\n * Use this when you need to convert Lex values to plain objects (e.g., for\n * custom serialization or inspection). For direct JSON string output, use\n * {@link lexStringify} instead.\n *\n * @param value - The Lex value to convert\n * @returns The JSON-compatible value\n * @throws {TypeError} If the value contains unsupported types\n *\n * @example\n * ```typescript\n * import { lexToJson } from '@atproto/lex'\n *\n * // Convert Lex values to JSON-compatible objects\n * const obj = lexToJson({\n * ref: someCid, // Converted to { $link: string }\n * data: someBytes // Converted to { $bytes: string }\n * })\n * ```\n */\nexport function lexToJson(value: LexValue): JsonValue {\n switch (typeof value) {\n case 'object':\n if (value === null) {\n return value\n } else if (Array.isArray(value)) {\n return lexArrayToJson(value)\n } else if (isCid(value)) {\n return encodeLexLink(value)\n } else if (ArrayBuffer.isView(value)) {\n return encodeLexBytes(value)\n } else {\n return encodeLexMap(value)\n }\n case 'boolean':\n case 'string':\n case 'number':\n return value\n default:\n throw new TypeError(`Invalid Lex value: ${typeof value}`)\n }\n}\n\nfunction lexArrayToJson(input: LexArray): JsonValue[] {\n // Lazily copy value\n let copy: JsonValue[] | undefined\n for (let i = 0; i < input.length; i++) {\n const inputItem = input[i]\n const item = lexToJson(inputItem)\n if (item !== inputItem) {\n copy ??= Array.from(input) as JsonValue[]\n copy[i] = item\n }\n }\n return copy ?? (input as JsonValue[])\n}\n\nfunction encodeLexMap(input: LexMap): JsonObject {\n // Lazily copy value\n let copy: JsonObject | undefined = undefined\n for (const [key, lexValue] of Object.entries(input)) {\n // Prevent prototype pollution\n if (key === '__proto__') {\n throw new TypeError('Invalid key: __proto__')\n }\n\n // Ignore (strip) undefined values\n if (lexValue === undefined) {\n copy ??= { ...input } as JsonObject\n delete copy[key]\n continue\n }\n\n const jsonValue = lexToJson(lexValue!)\n if (jsonValue !== lexValue) {\n copy ??= { ...input } as JsonObject\n copy[key] = jsonValue\n }\n }\n return copy ?? (input as JsonObject)\n}\n\n/**\n * @internal\n */\nexport function parseSpecialJsonObject(\n input: LexMap,\n options: LexParseOptions,\n): Cid | Uint8Array | BlobRef | undefined {\n // Hot path: use hints to avoid parsing when possible\n\n if (input.$link !== undefined) {\n const cid = parseLexLink(input)\n if (cid) return cid\n if (options.strict) throw new TypeError(`Invalid $link object`)\n } else if (input.$bytes !== undefined) {\n const bytes = parseLexBytes(input)\n if (bytes) return bytes\n if (options.strict) throw new TypeError(`Invalid $bytes object`)\n } else if (input.$type !== undefined) {\n // @NOTE Since blobs are \"just\" regular lex objects with a special shape,\n // and because an object that does not conform to the blob shape would still\n // result in undefined being returned, we only attempt to parse blobs when\n // the strict option is enabled.\n if (options.strict) {\n if (input.$type === 'blob') {\n const blob = parseTypedBlobRef(input, options)\n if (blob) return blob\n throw new TypeError(`Invalid blob object`)\n } else if (typeof input.$type !== 'string') {\n throw new TypeError(`Invalid $type property (${typeof input.$type})`)\n } else if (input.$type.length === 0) {\n throw new TypeError(`Empty $type property`)\n }\n }\n }\n\n // @NOTE We ignore legacy blob representation here. They can be handled at the\n // application level if needed.\n\n return undefined\n}\n"]}
package/dist/link.js CHANGED
@@ -1,9 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseLexLink = parseLexLink;
4
- exports.encodeLexLink = encodeLexLink;
5
- const lex_data_1 = require("@atproto/lex-data");
6
- function parseLexLink(input, options) {
1
+ import { parseCid, } from '@atproto/lex-data';
2
+ export function parseLexLink(input, options) {
7
3
  if (!input || !('$link' in input)) {
8
4
  return undefined;
9
5
  }
@@ -24,9 +20,9 @@ function parseLexLink(input, options) {
24
20
  return undefined;
25
21
  }
26
22
  try {
27
- return (0, lex_data_1.parseCid)($link, options);
23
+ return parseCid($link, options);
28
24
  }
29
- catch (cause) {
25
+ catch {
30
26
  return undefined;
31
27
  }
32
28
  }
@@ -47,7 +43,7 @@ function parseLexLink(input, options) {
47
43
  * // encoded is { $link: 'bafyreib2rxk3rybloqtqwbo' }
48
44
  * ```
49
45
  */
50
- function encodeLexLink(cid) {
46
+ export function encodeLexLink(cid) {
51
47
  return { $link: cid.toString() };
52
48
  }
53
49
  //# sourceMappingURL=link.js.map
package/dist/link.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":";;AA6CA,oCAkCC;AAmBD,sCAEC;AApGD,gDAK0B;AAwC1B,SAAgB,YAAY,CAC1B,KAA+B,EAC/B,OAAyB;IAEzB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpB,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;IAEvB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,yDAAyD;IACzD,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACxB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAA,mBAAQ,EAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,aAAa,CAAC,GAAQ;IACpC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAA;AAClC,CAAC","sourcesContent":["import {\n CheckCidOptions,\n Cid,\n InferCheckedCid,\n parseCid,\n} from '@atproto/lex-data'\nimport { JsonValue } from './json.js'\n\n/**\n * Parses a `{$link: string}` JSON object into a {@link Cid} instance.\n *\n * In the AT Protocol data model, CID references are represented in JSON as an\n * object with a single `$link` property containing a base32-encoded CID string,\n * prefixed with \"b\". This function decodes that representation into a `Cid`\n * object.\n *\n * @param input - An object potentially containing a `{$link: string}` property\n * @param options - Optional CID validation options\n * @returns The parsed {@link Cid} if the input is a valid `$link` object,\n * or `undefined` if the input is not a valid `$link` representation\n * @throws {TypeError} If `$link` is present but is not a valid CID string\n *\n * @example\n * ```typescript\n * // Parse a $link object to Cid\n * const cid = parseLexLink({ $link: 'bafyreib2rxk3rybloqtqwbo' })\n * // cid is a Cid instance\n *\n * // Returns undefined for non-$link objects\n * const result = parseLexLink({ foo: 'bar' })\n * // result is undefined\n *\n * // Returns undefined for objects with extra properties\n * const invalid = parseLexLink({ $link: 'bafyrei...', extra: true })\n * // invalid is undefined\n * ```\n */\nexport function parseLexLink<TOptions extends CheckCidOptions>(\n input: undefined | Record<string, unknown>,\n options: TOptions,\n): InferCheckedCid<TOptions> | undefined\nexport function parseLexLink(\n input?: Record<string, unknown>,\n options?: CheckCidOptions,\n): Cid | undefined\nexport function parseLexLink(\n input?: Record<string, unknown>,\n options?: CheckCidOptions,\n): Cid | undefined {\n if (!input || !('$link' in input)) {\n return undefined\n }\n\n for (const key in input) {\n if (key !== '$link') {\n return undefined\n }\n }\n\n const { $link } = input\n\n if (typeof $link !== 'string') {\n return undefined\n }\n\n if ($link.length === 0) {\n return undefined\n }\n\n // Arbitrary limit to prevent DoS via extremely long CIDs\n if ($link.length > 2048) {\n return undefined\n }\n\n try {\n return parseCid($link, options)\n } catch (cause) {\n return undefined\n }\n}\n\n/**\n * Encodes a {@link Cid} instance into a `{$link: string}` JSON representation.\n *\n * In the AT Protocol data model, CID references are represented in JSON as an\n * object with a single `$link` property containing a base32-encoded CID string,\n * prefixed with \"b\". This function performs that encoding.\n *\n * @param cid - The CID to encode\n * @returns An object with a `$link` property containing the string representation of the CID\n *\n * @example\n * ```typescript\n * const cid = CID.parse('bafyreib2rxk3rybloqtqwbo')\n * const encoded = encodeLexLink(cid)\n * // encoded is { $link: 'bafyreib2rxk3rybloqtqwbo' }\n * ```\n */\nexport function encodeLexLink(cid: Cid): JsonValue {\n return { $link: cid.toString() }\n}\n"]}
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,QAAQ,GACT,MAAM,mBAAmB,CAAA;AAwC1B,MAAM,UAAU,YAAY,CAC1B,KAA+B,EAC/B,OAAyB;IAEzB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpB,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;IAEvB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,yDAAyD;IACzD,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACxB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAA;AAClC,CAAC","sourcesContent":["import {\n CheckCidOptions,\n Cid,\n InferCheckedCid,\n parseCid,\n} from '@atproto/lex-data'\nimport { JsonValue } from './json.js'\n\n/**\n * Parses a `{$link: string}` JSON object into a {@link Cid} instance.\n *\n * In the AT Protocol data model, CID references are represented in JSON as an\n * object with a single `$link` property containing a base32-encoded CID string,\n * prefixed with \"b\". This function decodes that representation into a `Cid`\n * object.\n *\n * @param input - An object potentially containing a `{$link: string}` property\n * @param options - Optional CID validation options\n * @returns The parsed {@link Cid} if the input is a valid `$link` object,\n * or `undefined` if the input is not a valid `$link` representation\n * @throws {TypeError} If `$link` is present but is not a valid CID string\n *\n * @example\n * ```typescript\n * // Parse a $link object to Cid\n * const cid = parseLexLink({ $link: 'bafyreib2rxk3rybloqtqwbo' })\n * // cid is a Cid instance\n *\n * // Returns undefined for non-$link objects\n * const result = parseLexLink({ foo: 'bar' })\n * // result is undefined\n *\n * // Returns undefined for objects with extra properties\n * const invalid = parseLexLink({ $link: 'bafyrei...', extra: true })\n * // invalid is undefined\n * ```\n */\nexport function parseLexLink<TOptions extends CheckCidOptions>(\n input: undefined | Record<string, unknown>,\n options: TOptions,\n): InferCheckedCid<TOptions> | undefined\nexport function parseLexLink(\n input?: Record<string, unknown>,\n options?: CheckCidOptions,\n): Cid | undefined\nexport function parseLexLink(\n input?: Record<string, unknown>,\n options?: CheckCidOptions,\n): Cid | undefined {\n if (!input || !('$link' in input)) {\n return undefined\n }\n\n for (const key in input) {\n if (key !== '$link') {\n return undefined\n }\n }\n\n const { $link } = input\n\n if (typeof $link !== 'string') {\n return undefined\n }\n\n if ($link.length === 0) {\n return undefined\n }\n\n // Arbitrary limit to prevent DoS via extremely long CIDs\n if ($link.length > 2048) {\n return undefined\n }\n\n try {\n return parseCid($link, options)\n } catch {\n return undefined\n }\n}\n\n/**\n * Encodes a {@link Cid} instance into a `{$link: string}` JSON representation.\n *\n * In the AT Protocol data model, CID references are represented in JSON as an\n * object with a single `$link` property containing a base32-encoded CID string,\n * prefixed with \"b\". This function performs that encoding.\n *\n * @param cid - The CID to encode\n * @returns An object with a `$link` property containing the string representation of the CID\n *\n * @example\n * ```typescript\n * const cid = CID.parse('bafyreib2rxk3rybloqtqwbo')\n * const encoded = encodeLexLink(cid)\n * // encoded is { $link: 'bafyreib2rxk3rybloqtqwbo' }\n * ```\n */\nexport function encodeLexLink(cid: Cid): JsonValue {\n return { $link: cid.toString() }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@atproto/lex-json",
3
- "version": "0.0.15",
3
+ "version": "0.1.0-next.0",
4
+ "engines": {
5
+ "node": ">=22"
6
+ },
4
7
  "license": "MIT",
5
8
  "description": "Lexicon encoding utilities for AT Lexicon data in JSON format",
6
9
  "keywords": [
@@ -26,20 +29,16 @@
26
29
  "./CHANGELOG.md"
27
30
  ],
28
31
  "sideEffects": false,
29
- "type": "commonjs",
30
- "main": "./dist/index.js",
31
- "types": "./dist/index.d.ts",
32
+ "type": "module",
32
33
  "exports": {
33
34
  ".": {
34
35
  "types": "./dist/index.d.ts",
35
- "browser": "./dist/index.js",
36
- "import": "./dist/index.js",
37
36
  "default": "./dist/index.js"
38
37
  }
39
38
  },
40
39
  "dependencies": {
41
40
  "tslib": "^2.8.1",
42
- "@atproto/lex-data": "^0.0.15"
41
+ "@atproto/lex-data": "^0.1.0-next.0"
43
42
  },
44
43
  "devDependencies": {
45
44
  "vitest": "^4.0.16"