@atproto/lex-data 0.0.2 → 0.0.4

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/blob.d.ts +6 -0
  3. package/dist/blob.d.ts.map +1 -1
  4. package/dist/blob.js +4 -1
  5. package/dist/blob.js.map +1 -1
  6. package/dist/cid.d.ts +2 -3
  7. package/dist/cid.d.ts.map +1 -1
  8. package/dist/cid.js.map +1 -1
  9. package/dist/language.d.ts +2 -2
  10. package/dist/language.d.ts.map +1 -1
  11. package/dist/language.js +4 -4
  12. package/dist/language.js.map +1 -1
  13. package/dist/lex.d.ts.map +1 -1
  14. package/dist/lex.js +49 -48
  15. package/dist/lex.js.map +1 -1
  16. package/dist/object.d.ts +13 -1
  17. package/dist/object.d.ts.map +1 -1
  18. package/dist/object.js +15 -2
  19. package/dist/object.js.map +1 -1
  20. package/dist/uint8array-base64.d.ts +3 -0
  21. package/dist/uint8array-base64.d.ts.map +1 -0
  22. package/dist/uint8array-base64.js +3 -0
  23. package/dist/uint8array-base64.js.map +1 -0
  24. package/dist/uint8array-from-base64.d.ts +4 -3
  25. package/dist/uint8array-from-base64.d.ts.map +1 -1
  26. package/dist/uint8array-from-base64.js +9 -6
  27. package/dist/uint8array-from-base64.js.map +1 -1
  28. package/dist/uint8array-to-base64.d.ts +4 -3
  29. package/dist/uint8array-to-base64.d.ts.map +1 -1
  30. package/dist/uint8array-to-base64.js +7 -6
  31. package/dist/uint8array-to-base64.js.map +1 -1
  32. package/dist/uint8array.d.ts +6 -3
  33. package/dist/uint8array.d.ts.map +1 -1
  34. package/dist/uint8array.js +2 -1
  35. package/dist/uint8array.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/blob.ts +12 -1
  38. package/src/cid.ts +7 -7
  39. package/src/language.test.ts +33 -33
  40. package/src/language.ts +2 -2
  41. package/src/lex.test.ts +104 -1
  42. package/src/lex.ts +50 -43
  43. package/src/object.ts +16 -4
  44. package/src/uint8array-base64.ts +2 -0
  45. package/src/uint8array-from-base64.test.ts +33 -19
  46. package/src/uint8array-from-base64.ts +19 -6
  47. package/src/uint8array-to-base64.test.ts +170 -0
  48. package/src/uint8array-to-base64.ts +18 -8
  49. package/src/uint8array.ts +13 -5
  50. package/tsconfig.tests.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { fromString } from 'uint8arrays/from-string'
2
2
  import { NodeJSBuffer } from './lib/nodejs-buffer.js'
3
+ import { Base64Alphabet } from './uint8array-base64.js'
3
4
 
4
5
  const Buffer = NodeJSBuffer
5
6
 
@@ -21,14 +22,23 @@ declare global {
21
22
 
22
23
  export const fromBase64Native =
23
24
  typeof Uint8Array.fromBase64 === 'function'
24
- ? function fromBase64Native(b64: string): Uint8Array {
25
- return Uint8Array.fromBase64!(b64, { lastChunkHandling: 'loose' })
25
+ ? function fromBase64Native(
26
+ b64: string,
27
+ alphabet: Base64Alphabet = 'base64',
28
+ ): Uint8Array {
29
+ return Uint8Array.fromBase64!(b64, {
30
+ alphabet,
31
+ lastChunkHandling: 'loose',
32
+ })
26
33
  }
27
34
  : null
28
35
 
29
36
  export const fromBase64Node = Buffer
30
- ? function fromBase64Node(b64: string): Uint8Array {
31
- const bytes = Buffer.from(b64, 'base64')
37
+ ? function fromBase64Node(
38
+ b64: string,
39
+ alphabet: Base64Alphabet = 'base64',
40
+ ): Uint8Array {
41
+ const bytes = Buffer.from(b64, alphabet)
32
42
  verifyBase64ForBytes(b64, bytes)
33
43
  // Convert to Uint8Array because even though Buffer is a sub class of
34
44
  // Uint8Array, it serializes differently to Uint8Array (e.g. in JSON) and
@@ -37,8 +47,11 @@ export const fromBase64Node = Buffer
37
47
  }
38
48
  : null
39
49
 
40
- export function fromBase64Ponyfill(b64: string): Uint8Array {
41
- const bytes = fromString(b64, 'base64')
50
+ export function fromBase64Ponyfill(
51
+ b64: string,
52
+ alphabet: Base64Alphabet = 'base64',
53
+ ): Uint8Array {
54
+ const bytes = fromString(b64, b64.endsWith('=') ? `${alphabet}pad` : alphabet)
42
55
  verifyBase64ForBytes(b64, bytes)
43
56
  return bytes
44
57
  }
@@ -0,0 +1,170 @@
1
+ import 'core-js/modules/es.uint8-array.from-base64.js'
2
+ import 'core-js/modules/es.uint8-array.to-base64.js'
3
+ import assert from 'node:assert'
4
+ import {
5
+ toBase64Native,
6
+ toBase64Node,
7
+ toBase64Ponyfill,
8
+ } from './uint8array-to-base64.js'
9
+
10
+ for (const toBase64 of [
11
+ toBase64Native,
12
+ toBase64Node,
13
+ toBase64Ponyfill,
14
+ ] as const) {
15
+ // Tests should run in NodeJS where implementations are either available or
16
+ // polyfilled (see core-js imports above).
17
+ assert(toBase64 !== null, 'toBase64 implementation should not be null')
18
+
19
+ describe(toBase64.name, () => {
20
+ describe('basic encoding', () => {
21
+ it('encodes empty Uint8Array', () => {
22
+ const encoded = toBase64(new Uint8Array(0))
23
+ expect(typeof encoded).toBe('string')
24
+ expect(encoded).toBe('')
25
+ })
26
+
27
+ it('encodes 10MB', () => {
28
+ const bytes = Buffer.allocUnsafe(10_000_000).fill('🐩')
29
+ const encoded = toBase64(bytes)
30
+ expect(typeof encoded).toBe('string')
31
+ // Verify by decoding back
32
+ const decoded = Buffer.from(encoded, 'base64')
33
+ expect(decoded.equals(bytes)).toBe(true)
34
+ })
35
+ })
36
+
37
+ describe('base64 alphabet (default)', () => {
38
+ for (const string of [
39
+ '',
40
+ '\0\0',
41
+ '\0\0\0',
42
+ '\0\0\0\0',
43
+ '__',
44
+ 'é',
45
+ 'àç',
46
+ '\0éàç',
47
+ '```\x1b',
48
+ 'aaa',
49
+ 'Hello, World!',
50
+ '😀😃😄😁😆😅😂🤣😊😇',
51
+ '👩‍💻👨‍💻👩‍🔬👨‍🔬👩‍🚀👨‍🚀',
52
+ '🌍🌎🌏🌐🪐🌟✨⚡🔥💧',
53
+ ] as const) {
54
+ const buffer = Buffer.from(string, 'utf8')
55
+ const expected = buffer.toString('base64').replace(/=+$/, '')
56
+
57
+ it(`encodes ${JSON.stringify(string)} as ${JSON.stringify(expected)}`, () => {
58
+ const encoded = toBase64(buffer)
59
+ expect(encoded).toBe(expected)
60
+ })
61
+ }
62
+ })
63
+
64
+ describe('base64url alphabet', () => {
65
+ for (const string of [
66
+ '',
67
+ '\0\0',
68
+ '\0\0\0',
69
+ '\0\0\0\0',
70
+ '__',
71
+ 'é',
72
+ 'àç',
73
+ '\0éàç',
74
+ '```\x1b',
75
+ 'aaa',
76
+ 'Hello, World!',
77
+ '😀😃😄😁😆😅😂🤣😊😇',
78
+ '👩‍💻👨‍💻👩‍🔬👨‍🔬👩‍🚀👨‍🚀',
79
+ '🌍🌎🌏🌐🪐🌟✨⚡🔥💧',
80
+ ] as const) {
81
+ const buffer = Buffer.from(string, 'utf8')
82
+ const expected = buffer.toString('base64url')
83
+
84
+ it(`encodes ${JSON.stringify(string)} as ${JSON.stringify(expected)}`, () => {
85
+ const encoded = toBase64(buffer, 'base64url')
86
+ expect(encoded).toBe(expected)
87
+ })
88
+ }
89
+ })
90
+
91
+ describe('base64 vs base64url character differences', () => {
92
+ // Test data that produces + and / in standard base64
93
+ // These should become - and _ in base64url
94
+ it('uses + and / for base64 alphabet', () => {
95
+ // 0xfb, 0xff, 0xbf produces "+/+/" in base64
96
+ const bytes = new Uint8Array([0xfb, 0xff, 0xbf])
97
+ const encoded = toBase64(bytes)
98
+ expect(encoded).toContain('+')
99
+ expect(encoded).toContain('/')
100
+ expect(encoded).not.toContain('-')
101
+ expect(encoded).not.toContain('_')
102
+ })
103
+
104
+ it('uses - and _ for base64url alphabet', () => {
105
+ // Same bytes should use - and _ in base64url
106
+ const bytes = new Uint8Array([0xfb, 0xff, 0xbf])
107
+ const encoded = toBase64(bytes, 'base64url')
108
+ expect(encoded).toContain('-')
109
+ expect(encoded).toContain('_')
110
+ expect(encoded).not.toContain('+')
111
+ expect(encoded).not.toContain('/')
112
+ })
113
+ })
114
+
115
+ describe('padding behavior', () => {
116
+ it('omits padding by default for 1-byte input', () => {
117
+ // 1 byte -> 2 base64 chars + 2 padding
118
+ const bytes = new Uint8Array([0x4d]) // 'M' -> 'TQ=='
119
+ const encoded = toBase64(bytes)
120
+ expect(encoded).toBe('TQ')
121
+ expect(encoded).not.toContain('=')
122
+ })
123
+
124
+ it('omits padding by default for 2-byte input', () => {
125
+ // 2 bytes -> 3 base64 chars + 1 padding
126
+ const bytes = new Uint8Array([0x4d, 0x61]) // 'Ma' -> 'TWE='
127
+ const encoded = toBase64(bytes)
128
+ expect(encoded).toBe('TWE')
129
+ expect(encoded).not.toContain('=')
130
+ })
131
+
132
+ it('no padding needed for 3-byte input', () => {
133
+ // 3 bytes -> 4 base64 chars, no padding needed
134
+ const bytes = new Uint8Array([0x4d, 0x61, 0x6e]) // 'Man' -> 'TWFu'
135
+ const encoded = toBase64(bytes)
136
+ expect(encoded).toBe('TWFu')
137
+ })
138
+
139
+ it('includes double padding when omitPadding: false for 1-byte input', () => {
140
+ const bytes = new Uint8Array([0x4d]) // 'M' -> 'TQ=='
141
+ const encoded = toBase64(bytes)
142
+ expect(encoded).toBe('TQ')
143
+ })
144
+
145
+ it('includes single padding when omitPadding: false for 2-byte input', () => {
146
+ const bytes = new Uint8Array([0x4d, 0x61]) // 'Ma' -> 'TWE='
147
+ const encoded = toBase64(bytes)
148
+ expect(encoded).toBe('TWE')
149
+ })
150
+ })
151
+
152
+ describe('Uint8Array subarray handling', () => {
153
+ it('correctly encodes a subarray', () => {
154
+ const fullArray = new Uint8Array([0x00, 0x4d, 0x61, 0x6e, 0x00])
155
+ const subarray = fullArray.subarray(1, 4) // 'Man'
156
+ const encoded = toBase64(subarray)
157
+ expect(encoded).toBe('TWFu')
158
+ })
159
+
160
+ it('correctly encodes a subarray with offset', () => {
161
+ const buffer = new ArrayBuffer(10)
162
+ const fullView = new Uint8Array(buffer)
163
+ fullView.set([0x00, 0x00, 0x4d, 0x61, 0x6e, 0x00, 0x00])
164
+ const subarray = new Uint8Array(buffer, 2, 3) // 'Man' at offset 2
165
+ const encoded = toBase64(subarray)
166
+ expect(encoded).toBe('TWFu')
167
+ })
168
+ })
169
+ })
170
+ }
@@ -1,5 +1,6 @@
1
1
  import { toString } from 'uint8arrays/to-string'
2
2
  import { NodeJSBuffer } from './lib/nodejs-buffer.js'
3
+ import { Base64Alphabet } from './uint8array-base64.js'
3
4
 
4
5
  const Buffer = NodeJSBuffer
5
6
 
@@ -18,16 +19,22 @@ declare global {
18
19
 
19
20
  export const toBase64Native =
20
21
  typeof Uint8Array.prototype.toBase64 === 'function'
21
- ? function toBase64Native(bytes: Uint8Array): string {
22
- return bytes.toBase64!({ omitPadding: true })
22
+ ? function toBase64Native(
23
+ bytes: Uint8Array,
24
+ alphabet: Base64Alphabet = 'base64',
25
+ ): string {
26
+ return bytes.toBase64!({ alphabet, omitPadding: true })
23
27
  }
24
28
  : null
25
29
 
26
30
  export const toBase64Node = Buffer
27
- ? function toBase64Node(bytes: Uint8Array): string {
28
- const b64 = (
29
- bytes instanceof Buffer ? bytes : Buffer.from(bytes)
30
- ).toString('base64')
31
+ ? function toBase64Node(
32
+ bytes: Uint8Array,
33
+ alphabet: Base64Alphabet = 'base64',
34
+ ): string {
35
+ const buffer = bytes instanceof Buffer ? bytes : Buffer.from(bytes)
36
+ const b64 = buffer.toString(alphabet)
37
+
31
38
  // @NOTE We strip padding for strict compatibility with
32
39
  // uint8arrays.toString behavior. Tests failing because of the presence of
33
40
  // padding are not really synonymous with an actual error and we might
@@ -40,6 +47,9 @@ export const toBase64Node = Buffer
40
47
  }
41
48
  : null
42
49
 
43
- export function toBase64Ponyfill(bytes: Uint8Array): string {
44
- return toString(bytes, 'base64')
50
+ export function toBase64Ponyfill(
51
+ bytes: Uint8Array,
52
+ alphabet: Base64Alphabet = 'base64',
53
+ ): string {
54
+ return toString(bytes, alphabet)
45
55
  }
package/src/uint8array.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Base64Alphabet } from './uint8array-base64.js'
1
2
  import {
2
3
  fromBase64Native,
3
4
  fromBase64Node,
@@ -9,6 +10,8 @@ import {
9
10
  toBase64Ponyfill,
10
11
  } from './uint8array-to-base64.js'
11
12
 
13
+ export type { Base64Alphabet }
14
+
12
15
  // @TODO drop dependency on uint8arrays package once Uint8Array.fromBase64 /
13
16
  // Uint8Array.prototype.toBase64 is widely supported, and mark fromBase64 /
14
17
  // toBase64 as deprecated. We can also drop NodeJS specific implementations
@@ -19,17 +22,22 @@ import {
19
22
  *
20
23
  * @returns The base64 encoded string
21
24
  */
22
- export const toBase64: (bytes: Uint8Array) => string =
23
- toBase64Native ?? toBase64Node ?? toBase64Ponyfill
25
+ export const toBase64: (
26
+ bytes: Uint8Array,
27
+ alphabet?: Base64Alphabet,
28
+ ) => string = toBase64Native ?? toBase64Node ?? toBase64Ponyfill
24
29
 
25
30
  /**
26
- * Decodes a base64 string into a Uint8Array.
31
+ * Decodes a base64 string into a Uint8Array. This function supports both padded
32
+ * and unpadded base64 strings.
27
33
  *
28
34
  * @returns The decoded {@link Uint8Array}
29
35
  * @throws If the input is not a valid base64 string
30
36
  */
31
- export const fromBase64: (b64: string) => Uint8Array =
32
- fromBase64Native ?? fromBase64Node ?? fromBase64Ponyfill
37
+ export const fromBase64: (
38
+ b64: string,
39
+ alphabet?: Base64Alphabet,
40
+ ) => Uint8Array = fromBase64Native ?? fromBase64Node ?? fromBase64Ponyfill
33
41
 
34
42
  if (toBase64 === toBase64Ponyfill || fromBase64 === fromBase64Ponyfill) {
35
43
  /*#__PURE__*/
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "extends": "../../../tsconfig/tests.json",
3
- "include": ["./tests", "./src/**.test.ts"],
3
+ "include": ["./tests", "./src/**/*.test.ts"],
4
4
  "compilerOptions": {
5
5
  "noImplicitAny": true,
6
6
  "rootDir": "./",