Skip to content

Commit cdfacc9

Browse files
authored
fix: lift restriction on release perspective name (#1005)
1 parent 99cfa97 commit cdfacc9

File tree

4 files changed

+36
-38
lines changed

4 files changed

+36
-38
lines changed

src/config.ts

+14-26
Original file line numberDiff line numberDiff line change
@@ -28,43 +28,31 @@ function validateApiVersion(apiVersion: string) {
2828
}
2929
}
3030

31+
const VALID_PERSPECTIVE = /^[a-z0-9_]+$/i
32+
3133
/**
3234
* @internal - it may have breaking changes in any release
3335
*/
3436
export function validateApiPerspective(
3537
perspective: unknown,
3638
): asserts perspective is ClientPerspective {
3739
if (Array.isArray(perspective)) {
38-
for (const perspectiveValue of perspective) {
39-
if (perspectiveValue === 'published') {
40-
continue
41-
}
42-
if (perspectiveValue === 'drafts') {
43-
continue
44-
}
45-
if (
46-
typeof perspectiveValue === 'string' &&
47-
perspectiveValue.startsWith('r') &&
48-
perspectiveValue !== 'raw'
49-
) {
50-
continue
51-
}
40+
if (perspective.includes('raw')) {
5241
throw new TypeError(
53-
'Invalid API perspective value, expected `published`, `drafts` or a valid release identifier string',
42+
`Invalid API perspective value: "raw". The raw-perspective can not be combined with other perspectives`,
5443
)
5544
}
56-
return
5745
}
58-
switch (perspective as ClientPerspective) {
59-
case 'previewDrafts':
60-
case 'drafts':
61-
case 'published':
62-
case 'raw':
63-
return
64-
default:
65-
throw new TypeError(
66-
'Invalid API perspective string, expected `published`, `previewDrafts` or `raw`',
67-
)
46+
47+
const invalid = (Array.isArray(perspective) ? perspective : [perspective]).filter(
48+
(perspectiveName) =>
49+
typeof perspectiveName !== 'string' || !VALID_PERSPECTIVE.test(perspectiveName),
50+
)
51+
if (invalid.length > 0) {
52+
const formatted = invalid.map((v) => JSON.stringify(v))
53+
throw new TypeError(
54+
`Invalid API perspective value${invalid.length === 1 ? '' : 's'}: ${formatted.join(', ')}, expected \`published\`, \`drafts\`, \`raw\` or a release identifier string`,
55+
)
6856
}
6957
}
7058

src/csm/resolvePerspectives.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {validateApiPerspective} from '../config'
2-
import type {ReleaseId} from '../types'
2+
import type {StackablePerspective} from '../types'
33
import type {ClientPerspective} from './types'
44

55
/**
@@ -9,7 +9,7 @@ import type {ClientPerspective} from './types'
99
*/
1010
export function resolvePerspectives(
1111
perspective: Exclude<ClientPerspective, 'raw'>,
12-
): ('published' | 'drafts' | ReleaseId)[] {
12+
): ('published' | 'drafts' | StackablePerspective)[] {
1313
validateApiPerspective(perspective)
1414

1515
if (Array.isArray(perspective)) {

src/types.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,22 @@ export interface RequestOptions {
3131
signal?: AbortSignal
3232
}
3333

34-
/** @public */
34+
/**
35+
* @public
36+
* @deprecated – The `r`-prefix is not required, use `string` instead
37+
*/
3538
export type ReleaseId = `r${string}`
3639

40+
/** @public */
41+
export type StackablePerspective = ('published' | 'drafts' | string) & {}
42+
3743
/** @public */
3844
export type ClientPerspective =
3945
| 'previewDrafts'
4046
| 'published'
4147
| 'drafts'
4248
| 'raw'
43-
| ('published' | 'drafts' | ReleaseId)[]
49+
| StackablePerspective[]
4450

4551
/** @public */
4652
export interface ClientConfig {

test/client.test.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -177,30 +177,34 @@ describe('client', async () => {
177177
expect(() => createClient({projectId: 'abc123', perspective: 'raw'})).not.toThrow(
178178
/Invalid API perspective/,
179179
)
180+
expect(() => createClient({projectId: 'abc123', perspective: undefined})).not.toThrow(
181+
/Invalid API perspective/,
182+
)
183+
// no whitespace allowed
180184
// @ts-expect-error -- we want to test that it throws an error
181185
expect(() => createClient({projectId: 'abc123', perspective: 'preview drafts'})).toThrow(
182186
/Invalid API perspective/,
183187
)
184188

185-
// valid because it begins with `r`
186-
const validReleaseIdentifier = 'rfoobar'
189+
const validReleaseIdentifier = 'foobar'
187190
expect(() =>
188191
createClient({
189192
projectId: 'abc123',
190193
perspective: ['published', 'drafts', validReleaseIdentifier],
191194
}),
192195
).not.toThrow(/Invalid API perspective/)
193196

194-
// special case – "raw" would be a valid release id given that it starts with ´r`
195-
// but 'raw' is not possible to use with multiple perspectives and is explicitly
196-
// banned by the backend
197197
expect(() =>
198-
createClient({projectId: 'abc123', perspective: ['published', 'drafts', 'raw']}),
198+
createClient({
199+
projectId: 'abc123',
200+
perspective: ['published', 'drafts', 'this is not valid'],
201+
}),
199202
).toThrow(/Invalid API perspective/)
200203

204+
// special case – 'raw' can not be combined with multiple perspectives and is explicitly
205+
// banned by the backend
201206
expect(() =>
202-
// @ts-expect-error -- we want to test that it throws an error
203-
createClient({projectId: 'abc123', perspective: ['XyzAbC']}),
207+
createClient({projectId: 'abc123', perspective: ['published', 'drafts', 'raw']}),
204208
).toThrow(/Invalid API perspective/)
205209
})
206210

0 commit comments

Comments
 (0)