Skip to content

Commit d2ad4e4

Browse files
authored
Update relativeURL functions to use RRIs (#4923)
1 parent 94633c8 commit d2ad4e4

12 files changed

Lines changed: 219 additions & 80 deletions

File tree

packages/base/card-api.gts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ class ContainsMany<FieldT extends FieldDefConstructor> implements Field<
677677
meta.fields[fieldName] = {
678678
adoptsFrom: identifyCard(
679679
override,
680-
opts?.useAbsoluteURL ? undefined : opts?.maybeRelativeURL,
680+
opts?.useAbsoluteURL ? undefined : opts?.maybeRelativeReference,
681681
),
682682
};
683683
}
@@ -989,7 +989,7 @@ class Contains<CardT extends FieldDefConstructor> implements Field<CardT, any> {
989989
[this.name]: {
990990
adoptsFrom: identifyCard(
991991
this.card,
992-
opts?.useAbsoluteURL ? undefined : opts?.maybeRelativeURL,
992+
opts?.useAbsoluteURL ? undefined : opts?.maybeRelativeReference,
993993
),
994994
},
995995
},
@@ -2242,11 +2242,11 @@ export class BaseDef {
22422242
if (stack.includes(value)) {
22432243
return { id: valueId };
22442244
}
2245-
function makeAbsoluteURL(maybeRelativeURL: string) {
2245+
function makeAbsoluteURL(maybeRelativeReference: string) {
22462246
if (!value[relativeTo]) {
2247-
return maybeRelativeURL;
2247+
return maybeRelativeReference;
22482248
}
2249-
return resolveCardReference(maybeRelativeURL, value[relativeTo]);
2249+
return resolveCardReference(maybeRelativeReference, value[relativeTo]);
22502250
}
22512251
return Object.fromEntries(
22522252
Object.entries(

packages/base/card-serialization.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
isSingleFileMetaDocument,
3636
loadCardDef,
3737
localId,
38-
maybeRelativeURL,
38+
maybeRelativeReference,
3939
maybeURL,
4040
meta,
4141
primitive,
@@ -70,7 +70,7 @@ export interface SerializeOpts {
7070
useAbsoluteURL?: boolean;
7171
omitFields?: [typeof BaseDef];
7272
omitQueryFields?: boolean;
73-
maybeRelativeURL?: (possibleURL: string) => string;
73+
maybeRelativeReference?: (possibleReference: string) => string;
7474
overrides?: Map<string, typeof BaseDef>;
7575
}
7676

@@ -176,8 +176,8 @@ export function makeRelativeURL(
176176
maybeURL: string,
177177
opts?: SerializeOpts,
178178
): string {
179-
return opts?.maybeRelativeURL && !opts?.useAbsoluteURL
180-
? opts.maybeRelativeURL(maybeURL)
179+
return opts?.maybeRelativeReference && !opts?.useAbsoluteURL
180+
? opts.maybeRelativeReference(maybeURL)
181181
: maybeURL;
182182
}
183183

@@ -223,24 +223,24 @@ export function serializeCard(
223223
let data = serializeCardResource(model, doc, {
224224
...opts,
225225
...{
226-
maybeRelativeURL(possibleURL: string) {
226+
maybeRelativeReference(possibleReference: string) {
227227
// Registered prefix refs (e.g. @cardstack/catalog/foo) are already
228228
// in their canonical portable form — return as-is
229-
if (isRegisteredPrefix(possibleURL)) {
230-
return possibleURL;
229+
if (isRegisteredPrefix(possibleReference)) {
230+
return possibleReference;
231231
}
232-
let url = maybeURL(possibleURL, modelRelativeTo);
232+
let url = maybeURL(possibleReference, modelRelativeTo);
233233
if (!url) {
234234
throw new Error(
235-
`could not determine url from '${maybeRelativeURL}' relative to ${modelRelativeTo}`,
235+
`could not determine url from '${possibleReference}' relative to ${modelRelativeTo}`,
236236
);
237237
}
238238
if (!modelRelativeTo) {
239239
return url.href;
240240
}
241241
const realmURLString = getCardMeta(model, 'realmURL');
242242
const realmURL = realmURLString ? new URL(realmURLString) : undefined;
243-
return maybeRelativeURL(url, modelRelativeTo, realmURL);
243+
return maybeRelativeReference(url, modelRelativeTo, realmURL);
244244
},
245245
},
246246
});
@@ -266,7 +266,7 @@ export function serializeCardResource(
266266
): LooseCardResource | LooseFileMetaResource {
267267
let adoptsFrom = identifyCard(
268268
model.constructor,
269-
opts?.useAbsoluteURL ? undefined : opts?.maybeRelativeURL,
269+
opts?.useAbsoluteURL ? undefined : opts?.maybeRelativeReference,
270270
);
271271
if (!adoptsFrom) {
272272
throw new Error(`bug: could not identify card: ${model.constructor.name}`);
@@ -323,16 +323,16 @@ export function serializeFileDef(
323323
{
324324
...opts,
325325
...{
326-
maybeRelativeURL(possibleURL: string) {
326+
maybeRelativeReference(possibleReference: string) {
327327
// Registered prefix refs (e.g. @cardstack/catalog/foo) are already
328328
// in their canonical portable form — return as-is
329-
if (isRegisteredPrefix(possibleURL)) {
330-
return possibleURL;
329+
if (isRegisteredPrefix(possibleReference)) {
330+
return possibleReference;
331331
}
332-
let url = maybeURL(possibleURL, modelRelativeTo);
332+
let url = maybeURL(possibleReference, modelRelativeTo);
333333
if (!url) {
334334
throw new Error(
335-
`could not determine url from '${possibleURL}' relative to ${modelRelativeTo}`,
335+
`could not determine url from '${possibleReference}' relative to ${modelRelativeTo}`,
336336
);
337337
}
338338
if (!modelRelativeTo) {
@@ -342,7 +342,7 @@ export function serializeFileDef(
342342
const realmURL = realmURLString
343343
? new URL(realmURLString)
344344
: undefined;
345-
return maybeRelativeURL(url, modelRelativeTo, realmURL);
345+
return maybeRelativeReference(url, modelRelativeTo, realmURL);
346346
},
347347
},
348348
},

packages/base/codemirror-editor.gts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { eq } from '@cardstack/boxel-ui/helpers';
1010
import {
1111
resolveCardReference,
1212
trimJsonExtension,
13-
maybeRelativeURL,
13+
maybeRelativeReference,
1414
} from '@cardstack/runtime-common';
1515
import { type BaseDef, type CardDef, getComponent } from './card-api';
1616
import { CardContextConsumer } from './field-component';
@@ -100,7 +100,7 @@ function makeCardRef(
100100
): string {
101101
if (!baseUrl) return cardUrl;
102102
try {
103-
return maybeRelativeURL(new URL(cardUrl), new URL(baseUrl), undefined);
103+
return maybeRelativeReference(new URL(cardUrl), new URL(baseUrl), undefined);
104104
} catch {
105105
return cardUrl;
106106
}

packages/host/app/components/operator-mode/create-file-modal.gts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
RealmPaths,
4040
Deferred,
4141
SupportedMimeType,
42-
maybeRelativeURL,
42+
maybeRelativeReference,
4343
GetCardContextName,
4444
isCardInstance,
4545
type getCard,
@@ -844,7 +844,7 @@ export default class CreateFileModal extends Component<Signature> {
844844
) as ResolvedCodeRef
845845
).module;
846846
const absoluteModule = new URL(absoluteModuleHref);
847-
let moduleURL = maybeRelativeURL(
847+
let moduleURL = maybeRelativeReference(
848848
absoluteModule,
849849
url,
850850
new URL(this.selectedRealmURL),

packages/host/app/routes/render/meta.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
cardIdToURL,
1212
identifyCard,
1313
internalKeyFor,
14-
maybeRelativeURL,
14+
maybeRelativeReference,
1515
relationshipEntries,
1616
realmURL,
1717
snapshotRuntimeDependencies,
@@ -56,9 +56,9 @@ export default class RenderMetaRoute extends Route<Model> {
5656

5757
let serialized = api.serializeCard(instance, {
5858
includeComputeds: true,
59-
maybeRelativeURL: (url: string) =>
60-
maybeRelativeURL(
61-
cardIdToURL(url),
59+
maybeRelativeReference: (reference: string) =>
60+
maybeRelativeReference(
61+
cardIdToURL(reference),
6262
cardIdToURL(instance.id),
6363
instance[realmURL],
6464
),

packages/host/tests/unit/url-test.ts

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ import { module, test } from 'qunit';
33
import {
44
type LooseCardResource,
55
type RealmResourceIdentifier,
6-
relativeURL,
6+
maybeRelativeReference,
7+
relativeReference,
8+
ri,
9+
rri,
710
visitInstanceURLs,
811
} from '@cardstack/runtime-common';
912

1013
module('Unit | url', function () {
11-
module('relativeURL', function () {
14+
module('relativeReference', function () {
1215
test('returns undefined for different origins', function (assert) {
13-
let result = relativeURL(
16+
let result = relativeReference(
1417
new URL('https://other.example.com/a'),
1518
new URL('https://example.com/a'),
1619
undefined,
@@ -21,7 +24,7 @@ module('Unit | url', function () {
2124

2225
test('returns undefined when realm URL blocks escaping the realm', function (assert) {
2326
let realm = new URL('https://example.com/realm/');
24-
let result = relativeURL(
27+
let result = relativeReference(
2528
new URL('https://example.com/outside/card'),
2629
new URL('https://example.com/realm/card'),
2730
realm,
@@ -31,7 +34,7 @@ module('Unit | url', function () {
3134
});
3235

3336
test('returns absolute path when first path segment differs and relativeTo is nested', function (assert) {
34-
let result = relativeURL(
37+
let result = relativeReference(
3538
new URL('https://example.com/d/e'),
3639
new URL('https://example.com/a/b/c'),
3740
undefined,
@@ -41,7 +44,7 @@ module('Unit | url', function () {
4144
});
4245

4346
test('creates relative path to upper-level sibling', function (assert) {
44-
let result = relativeURL(
47+
let result = relativeReference(
4548
new URL('https://example.com/d'),
4649
new URL('https://example.com/a/b'),
4750
undefined,
@@ -51,7 +54,7 @@ module('Unit | url', function () {
5154
});
5255

5356
test('creates sibling-relative path', function (assert) {
54-
let result = relativeURL(
57+
let result = relativeReference(
5558
new URL('https://example.com/a/b/other'),
5659
new URL('https://example.com/a/b/file'),
5760
undefined,
@@ -61,7 +64,7 @@ module('Unit | url', function () {
6164
});
6265

6366
test('creates parent-relative path', function (assert) {
64-
let result = relativeURL(
67+
let result = relativeReference(
6568
new URL('https://example.com/a/b/e'),
6669
new URL('https://example.com/a/b/c/d'),
6770
undefined,
@@ -71,7 +74,7 @@ module('Unit | url', function () {
7174
});
7275

7376
test('returns ./file when URL matches relativeTo exactly', function (assert) {
74-
let result = relativeURL(
77+
let result = relativeReference(
7578
new URL('https://example.com/a/b'),
7679
new URL('https://example.com/a/b'),
7780
undefined,
@@ -81,14 +84,86 @@ module('Unit | url', function () {
8184
});
8285

8386
test('returns ./file when relativeTo is root', function (assert) {
84-
let result = relativeURL(
87+
let result = relativeReference(
8588
new URL('https://example.com/b'),
8689
new URL('https://example.com/'),
8790
undefined,
8891
);
8992

9093
assert.strictEqual(result, './b');
9194
});
95+
96+
test('creates sibling-relative path between two prefix-form RRIs in the same scope', function (assert) {
97+
let result = relativeReference(
98+
rri('@cardstack/base/foo'),
99+
rri('@cardstack/base/bar'),
100+
undefined,
101+
);
102+
103+
assert.strictEqual(result, './foo');
104+
});
105+
106+
test('returns undefined for prefix-form RRIs in different scopes', function (assert) {
107+
let result = relativeReference(
108+
rri('@cardstack/base/foo'),
109+
rri('@cardstack/catalog/bar'),
110+
undefined,
111+
);
112+
113+
assert.strictEqual(result, undefined);
114+
});
115+
116+
test('returns undefined for mixed URL + prefix-form RRI inputs', function (assert) {
117+
let result = relativeReference(
118+
rri('@cardstack/base/foo'),
119+
new URL('https://my-realm.com/bar'),
120+
undefined,
121+
);
122+
123+
assert.strictEqual(result, undefined);
124+
});
125+
126+
test('produces a relative path within a prefix-form realm', function (assert) {
127+
let result = relativeReference(
128+
rri('@cardstack/base/foo'),
129+
rri('@cardstack/base/sub/bar'),
130+
ri('@cardstack/base/'),
131+
);
132+
133+
assert.strictEqual(result, '../foo');
134+
});
135+
136+
test('returns undefined when a prefix-form realm blocks escaping', function (assert) {
137+
let result = relativeReference(
138+
rri('@cardstack/base/outside'),
139+
rri('@cardstack/base/sub/inside'),
140+
ri('@cardstack/base/sub/'),
141+
);
142+
143+
assert.strictEqual(result, undefined);
144+
});
145+
});
146+
147+
module('maybeRelativeReference', function () {
148+
test('falls back to absolute href for un-relativizable URL inputs', function (assert) {
149+
let result = maybeRelativeReference(
150+
new URL('https://a.com/foo'),
151+
new URL('https://b.com/bar'),
152+
undefined,
153+
);
154+
155+
assert.strictEqual(result, 'https://a.com/foo');
156+
});
157+
158+
test('falls back to the prefix-form RRI as-is for un-relativizable RRI inputs', function (assert) {
159+
let result = maybeRelativeReference(
160+
rri('@cardstack/base/foo'),
161+
new URL('https://my-realm.com/bar'),
162+
undefined,
163+
);
164+
165+
assert.strictEqual(result, '@cardstack/base/foo');
166+
});
92167
});
93168

94169
module('Unit | document | visitInstanceURLs', function () {

packages/runtime-common/code-ref.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ export async function loadCardDef(
204204

205205
export function identifyCard(
206206
card: typeof BaseDef | undefined,
207-
maybeRelativeURL?: ((possibleURL: string) => string) | null,
207+
maybeRelativeReference?: ((possibleReference: string) => string) | null,
208208
visited = new WeakSet<typeof BaseDef>(),
209209
): CodeRef | undefined {
210210
if (!card) {
@@ -221,10 +221,10 @@ export function identifyCard(
221221

222222
let ref = Loader.identify(card);
223223
if (ref) {
224-
return maybeRelativeURL
224+
return maybeRelativeReference
225225
? {
226226
...ref,
227-
module: maybeRelativeURL(ref.module) as RealmResourceIdentifier,
227+
module: maybeRelativeReference(ref.module) as RealmResourceIdentifier,
228228
}
229229
: (ref as ResolvedCodeRef);
230230
}
@@ -233,7 +233,7 @@ export function identifyCard(
233233
if (!local) {
234234
return undefined;
235235
}
236-
let innerRef = identifyCard(local.card, maybeRelativeURL, visited);
236+
let innerRef = identifyCard(local.card, maybeRelativeReference, visited);
237237
if (!innerRef) {
238238
return undefined;
239239
}

0 commit comments

Comments
 (0)