+5
.changeset/lucky-numbers-work.md
+5
.changeset/lucky-numbers-work.md
+20
-21
packages/lexicons/lexicons/lib/syntax/at-uri.test.ts
+20
-21
packages/lexicons/lexicons/lib/syntax/at-uri.test.ts
···
1
-
import { assert, describe, expect, it } from 'vitest';
2
3
import {
4
-
isResourceUri,
5
-
parseResourceUri,
6
isCanonicalResourceUri,
7
parseCanonicalResourceUri,
8
} from './at-uri.js';
9
10
describe('resourceUri validation', () => {
···
47
];
48
for (const str of validCases) {
49
expect(isResourceUri(str), str).toBe(true);
50
-
51
-
expect(parseResourceUri(str).ok, str).toBe(true);
52
}
53
54
const invalidCases = [
···
106
];
107
for (const str of invalidCases) {
108
expect(isResourceUri(str), str).toBe(false);
109
-
110
-
expect(parseResourceUri(str).ok, str).toBe(false);
111
}
112
113
expect(isResourceUri(null)).toBe(false);
···
116
it('parses valid at-uris', () => {
117
const result = parseResourceUri('at://did:plc:asdf123/com.atproto.feed.post/record');
118
119
-
assert(result.ok);
120
-
expect(result.value).toEqual({
121
repo: 'did:plc:asdf123',
122
collection: 'com.atproto.feed.post',
123
rkey: 'record',
···
127
128
it('parses at-uri with fragment', () => {
129
const result = parseResourceUri('at://did:plc:asdf123/com.atproto.feed.post/record#/fragment');
130
-
assert(result.ok);
131
-
expect(result.value).toEqual({
132
repo: 'did:plc:asdf123',
133
collection: 'com.atproto.feed.post',
134
rkey: 'record',
···
137
});
138
139
it('returns error for invalid at-uri', () => {
140
-
const result = parseResourceUri('invalid-uri');
141
-
assert(!result.ok);
142
-
expect(result.error).toContain('invalid at-uri');
143
});
144
});
145
···
152
for (const str of validCases) {
153
expect(isCanonicalResourceUri(str), str).toBe(true);
154
155
-
expect(parseCanonicalResourceUri(str).ok, str).toBe(true);
156
}
157
158
const invalidCases = [
···
164
for (const str of invalidCases) {
165
expect(isCanonicalResourceUri(str), str).toBe(false);
166
167
-
expect(parseCanonicalResourceUri(str).ok, str).toBe(false);
168
}
169
170
expect(isCanonicalResourceUri(null)).toBe(false);
···
172
173
it('parses valid canonical at-uris', () => {
174
const result = parseCanonicalResourceUri('at://did:plc:asdf123/com.atproto.feed.post/record');
175
-
assert(result.ok);
176
-
expect(result.value).toEqual({
177
repo: 'did:plc:asdf123',
178
collection: 'com.atproto.feed.post',
179
rkey: 'record',
···
182
});
183
184
it('returns error for invalid canonical at-uri', () => {
185
-
const result = parseCanonicalResourceUri('at://user.bsky.social/com.atproto.feed.post/record');
186
-
assert(!result.ok);
187
-
expect(result.error).toContain('invalid repo in canonical-at-uri');
188
});
189
});
···
1
+
import { describe, expect, it } from 'vitest';
2
3
import {
4
isCanonicalResourceUri,
5
+
isResourceUri,
6
parseCanonicalResourceUri,
7
+
parseResourceUri,
8
} from './at-uri.js';
9
10
describe('resourceUri validation', () => {
···
47
];
48
for (const str of validCases) {
49
expect(isResourceUri(str), str).toBe(true);
50
+
expect(() => parseResourceUri(str), str).not.toThrow();
51
}
52
53
const invalidCases = [
···
105
];
106
for (const str of invalidCases) {
107
expect(isResourceUri(str), str).toBe(false);
108
+
expect(() => parseResourceUri(str), str).toThrow();
109
}
110
111
expect(isResourceUri(null)).toBe(false);
···
114
it('parses valid at-uris', () => {
115
const result = parseResourceUri('at://did:plc:asdf123/com.atproto.feed.post/record');
116
117
+
expect(result).toEqual({
118
repo: 'did:plc:asdf123',
119
collection: 'com.atproto.feed.post',
120
rkey: 'record',
···
124
125
it('parses at-uri with fragment', () => {
126
const result = parseResourceUri('at://did:plc:asdf123/com.atproto.feed.post/record#/fragment');
127
+
128
+
expect(result).toEqual({
129
repo: 'did:plc:asdf123',
130
collection: 'com.atproto.feed.post',
131
rkey: 'record',
···
134
});
135
136
it('returns error for invalid at-uri', () => {
137
+
expect(() => parseResourceUri('invalid-uri')).toThrowErrorMatchingInlineSnapshot(
138
+
`[SyntaxError: invalid at-uri: invalid-uri]`,
139
+
);
140
});
141
});
142
···
149
for (const str of validCases) {
150
expect(isCanonicalResourceUri(str), str).toBe(true);
151
152
+
expect(() => parseCanonicalResourceUri(str), str).not.toThrow();
153
}
154
155
const invalidCases = [
···
161
for (const str of invalidCases) {
162
expect(isCanonicalResourceUri(str), str).toBe(false);
163
164
+
expect(() => parseCanonicalResourceUri(str), str).toThrow();
165
}
166
167
expect(isCanonicalResourceUri(null)).toBe(false);
···
169
170
it('parses valid canonical at-uris', () => {
171
const result = parseCanonicalResourceUri('at://did:plc:asdf123/com.atproto.feed.post/record');
172
+
173
+
expect(result).toEqual({
174
repo: 'did:plc:asdf123',
175
collection: 'com.atproto.feed.post',
176
rkey: 'record',
···
179
});
180
181
it('returns error for invalid canonical at-uri', () => {
182
+
expect(() => {
183
+
return parseCanonicalResourceUri('at://user.bsky.social/com.atproto.feed.post/record');
184
+
}).toThrowErrorMatchingInlineSnapshot(
185
+
`[SyntaxError: invalid repo in canonical-at-uri: user.bsky.social]`,
186
+
);
187
});
188
});
+12
-14
packages/lexicons/lexicons/lib/syntax/at-uri.ts
+12
-14
packages/lexicons/lexicons/lib/syntax/at-uri.ts
···
3
import { isNsid, type Nsid } from './nsid.js';
4
import { isRecordKey, type RecordKey } from './record-key.js';
5
6
-
import { type Result } from '../utils.js';
7
-
8
/**
9
* represents a general AT Protocol URI, representing either an entire
10
* repository, a specific collection within a repository, or a record.
···
41
};
42
43
// #__NO_SIDE_EFFECTS__
44
-
export const parseResourceUri = (input: string): Result<ParsedResourceUri, string> => {
45
const match = ATURI_RE.exec(input);
46
if (match === null) {
47
-
return { ok: false, error: `invalid at-uri: ${input}` };
48
}
49
50
const [, r, c, k, f] = match;
51
52
if (!isActorIdentifier(r)) {
53
-
return { ok: false, error: `invalid repo in at-uri: ${r}` };
54
}
55
56
if (c !== undefined && !isNsid(c)) {
57
-
return { ok: false, error: `invalid collection in at-uri: ${c}` };
58
}
59
60
if (k !== undefined && !isRecordKey(k)) {
61
-
return { ok: false, error: `invalid rkey in at-uri: ${k}` };
62
}
63
64
-
return { ok: true, value: { repo: r, collection: c, rkey: k, fragment: f } };
65
};
66
67
/**
···
97
};
98
99
// #__NO_SIDE_EFFECTS__
100
-
export const parseCanonicalResourceUri = (input: string): Result<ParsedCanonicalResourceUri, string> => {
101
const match = ATURI_RE.exec(input);
102
if (match === null) {
103
-
return { ok: false, error: `invalid canonical-at-uri: ${input}` };
104
}
105
106
const [, r, c, k, f] = match;
107
108
if (!isDid(r)) {
109
-
return { ok: false, error: `invalid repo in canonical-at-uri: ${r}` };
110
}
111
112
if (!isNsid(c)) {
113
-
return { ok: false, error: `invalid collection in canonical-at-uri: ${c}` };
114
}
115
116
if (!isRecordKey(k)) {
117
-
return { ok: false, error: `invalid rkey in canonical-at-uri: ${k}` };
118
}
119
120
-
return { ok: true, value: { repo: r, collection: c, rkey: k, fragment: f } };
121
};
···
3
import { isNsid, type Nsid } from './nsid.js';
4
import { isRecordKey, type RecordKey } from './record-key.js';
5
6
/**
7
* represents a general AT Protocol URI, representing either an entire
8
* repository, a specific collection within a repository, or a record.
···
39
};
40
41
// #__NO_SIDE_EFFECTS__
42
+
export const parseResourceUri = (input: string): ParsedResourceUri => {
43
const match = ATURI_RE.exec(input);
44
if (match === null) {
45
+
throw new SyntaxError(`invalid at-uri: ${input}`);
46
}
47
48
const [, r, c, k, f] = match;
49
50
if (!isActorIdentifier(r)) {
51
+
throw new SyntaxError(`invalid repo in at-uri: ${r}`);
52
}
53
54
if (c !== undefined && !isNsid(c)) {
55
+
throw new SyntaxError(`invalid collection in at-uri: ${c}`);
56
}
57
58
if (k !== undefined && !isRecordKey(k)) {
59
+
throw new SyntaxError(`invalid rkey in at-uri: ${k}`);
60
}
61
62
+
return { repo: r, collection: c, rkey: k, fragment: f };
63
};
64
65
/**
···
95
};
96
97
// #__NO_SIDE_EFFECTS__
98
+
export const parseCanonicalResourceUri = (input: string): ParsedCanonicalResourceUri => {
99
const match = ATURI_RE.exec(input);
100
if (match === null) {
101
+
throw new SyntaxError(`invalid canonical-at-uri: ${input}`);
102
}
103
104
const [, r, c, k, f] = match;
105
106
if (!isDid(r)) {
107
+
throw new SyntaxError(`invalid repo in canonical-at-uri: ${r}`);
108
}
109
110
if (!isNsid(c)) {
111
+
throw new SyntaxError(`invalid collection in canonical-at-uri: ${c}`);
112
}
113
114
if (!isRecordKey(k)) {
115
+
throw new SyntaxError(`invalid rkey in canonical-at-uri: ${k}`);
116
}
117
118
+
return { repo: r, collection: c, rkey: k, fragment: f };
119
};
-2
packages/lexicons/lexicons/lib/utils.ts
-2
packages/lexicons/lexicons/lib/utils.ts