Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 20 additions & 23 deletions packages/base/card-api.gts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ import {
runtimeQueryDependencyContext,
type RuntimeDependencyTrackingContext,
resolveCardReference,
cardIdToURL,
rri,
type RealmResourceIdentifier,
} from '@cardstack/runtime-common';
import {
Expand Down Expand Up @@ -540,7 +540,7 @@ export interface Field<
store: CardStore | undefined,
instancePromise: Promise<BaseDef>,
loadedValue: any,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts?: DeserializeOpts,
): Promise<any>;
emptyValue(instance: BaseDef): any;
Expand Down Expand Up @@ -760,7 +760,7 @@ class ContainsMany<FieldT extends FieldDefConstructor> implements Field<
store: CardStore,
instancePromise: Promise<BaseDef>,
_loadedValue: any,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts: DeserializeOpts,
): Promise<BaseInstanceType<FieldT>[] | null> {
if (value == null) {
Expand Down Expand Up @@ -1053,7 +1053,7 @@ class Contains<CardT extends FieldDefConstructor> implements Field<CardT, any> {
store: CardStore,
_instancePromise: Promise<BaseDef>,
_loadedValue: any,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts: DeserializeOpts,
): Promise<BaseInstanceType<CardT>> {
if (primitive in this.card) {
Expand Down Expand Up @@ -1325,7 +1325,7 @@ class LinksTo<CardT extends LinkableDefConstructor> implements Field<CardT> {
store: CardStore,
_instancePromise: Promise<CardDef>,
loadedValue: any,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts: DeserializeOpts,
): Promise<BaseInstanceType<CardT> | null | NotLoadedValue> {
if (!isRelationship(value)) {
Expand Down Expand Up @@ -1821,7 +1821,7 @@ class LinksToMany<FieldT extends LinkableDefConstructor> implements Field<
store: CardStore,
instancePromise: Promise<BaseDef>,
loadedValues: any,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts: DeserializeOpts,
): Promise<(BaseInstanceType<FieldT> | NotLoadedValue)[]> {
let relationships: Relationship[];
Expand Down Expand Up @@ -2191,7 +2191,7 @@ export class BaseDef {
// may contain interior fields that have relative links. FieldDef's though have no ID.
// So we need a [relativeTo] property that derives from the root document ID in order to
// resolve relative links at the FieldDef level.
[relativeTo]: URL | undefined = undefined;
[relativeTo]: RealmResourceIdentifier | URL | undefined = undefined;
[meta]: CardResourceMeta | undefined = undefined;
declare ['constructor']: BaseDefConstructor;
static baseDef: undefined;
Expand Down Expand Up @@ -2300,7 +2300,7 @@ export class BaseDef {
static async [deserialize]<T extends BaseDefConstructor>(
this: T,
data: any,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
doc?: CardDocument,
store?: CardStore,
opts?: DeserializeOpts,
Expand Down Expand Up @@ -2341,7 +2341,7 @@ export class Component<

export type CreateCardFn = (
ref: CodeRef,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts?: {
realmURL?: URL; // the realm to create the card in
localDir?: LocalPath; // the local directory path within the realm to create the card file
Expand Down Expand Up @@ -3293,7 +3293,7 @@ function lazilyLoadLink(
fieldValue = (await createFromSerialized(
fileMetaDoc.data,
fileMetaDoc,
cardIdToURL(fileMetaDoc.data.id!),
fileMetaDoc.data.id!,
{ store, dependencyTrackingContext },
)) as FileDef;
} else {
Expand All @@ -3309,7 +3309,7 @@ function lazilyLoadLink(
fieldValue = (await createFromSerialized(
cardDoc.data,
cardDoc,
cardIdToURL(cardDoc.data.id!),
cardDoc.data.id!,
{ store, dependencyTrackingContext },
)) as CardDef;
}
Expand Down Expand Up @@ -3548,7 +3548,7 @@ async function getDeserializedValue<CardT extends BaseDefConstructor>({
modelPromise: Promise<BaseDef>;
doc: LooseSingleCardDocument | CardDocument;
store: CardStore;
relativeTo: URL | undefined;
relativeTo: RealmResourceIdentifier | URL | undefined;
opts?: DeserializeOpts;
}): Promise<any> {
let field = getField(isCardInstance(value) ? value : card, fieldName);
Expand Down Expand Up @@ -3588,7 +3588,7 @@ export async function createFromSerialized<T extends BaseDefConstructor>(
doc:
| LooseSingleResourceDocument<CardResource | FileMetaResource>
| LinkableDocument,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
opts?: DeserializeOpts & {
store?: CardStore;
dependencyTrackingContext?: RuntimeDependencyTrackingContext;
Expand Down Expand Up @@ -3634,7 +3634,7 @@ export async function updateFromSerialized<T extends BaseDefConstructor>(
): Promise<BaseInstanceType<T>> {
stores.set(instance, store);
if (!instance[relativeTo] && doc.data.id) {
instance[relativeTo] = cardIdToURL(doc.data.id);
instance[relativeTo] = rri(doc.data.id);
}

if (isCardInstance(instance)) {
Expand All @@ -3660,7 +3660,7 @@ async function _createFromSerialized<T extends BaseDefConstructor>(
card: T,
data: T extends { [primitive]: infer P } ? P : LooseCardResource,
doc: LooseSingleCardDocument | CardDocument | undefined,
_relativeTo: URL | undefined,
_relativeTo: RealmResourceIdentifier | URL | undefined,
store: CardStore = new FallbackCardStore(),
opts?: DeserializeOpts,
): Promise<BaseInstanceType<T>> {
Expand Down Expand Up @@ -3757,10 +3757,10 @@ async function _updateFromSerialized<T extends BaseDefConstructor>({

let existingOverrides = getFieldOverrides(instance);
let loadedValues = getDataBucket(instance);
let instanceRelativeTo =
let instanceRelativeTo: RealmResourceIdentifier | URL | undefined =
instance[relativeTo] ??
('id' in instance && typeof instance.id === 'string'
? cardIdToURL(instance.id)
? (instance.id as RealmResourceIdentifier)
: undefined);

function getFieldMeta(
Expand Down Expand Up @@ -3830,10 +3830,7 @@ async function _updateFromSerialized<T extends BaseDefConstructor>({
// Prefer the deserialization context (instanceRelativeTo) so overrides resolve
// relative to the document we fetched (e.g. catalog/index), then fall back to the resource id.
relativeTo:
instanceRelativeTo ??
(resource.id && typeof resource.id === 'string'
? cardIdToURL(resource.id)
: undefined),
instanceRelativeTo ?? (resource.id ? rri(resource.id) : undefined),
dependencyTrackingContext: opts?.dependencyTrackingContext,
});
if (!override) {
Expand Down Expand Up @@ -3940,10 +3937,10 @@ async function _updateFromSerialized<T extends BaseDefConstructor>({
field = (getField(instance, fieldName) ?? field) as Field<T>;
}
// Prefer the deserialization context ([relativeTo]) when available; fall back to the instance id
let relativeToVal =
let relativeToVal: RealmResourceIdentifier | URL | undefined =
instance[relativeTo] ??
('id' in instance && typeof instance.id === 'string'
? cardIdToURL(instance.id)
? (instance.id as RealmResourceIdentifier)
: undefined);
let deserializedValue = await getDeserializedValue({
card,
Expand Down
31 changes: 18 additions & 13 deletions packages/base/card-serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
LooseSingleCardDocument,
LooseSingleFileMetaDocument,
Meta,
RealmResourceIdentifier,
RuntimeDependencyTrackingContext,
SingleFileMetaDocument,
} from '@cardstack/runtime-common';
Expand Down Expand Up @@ -40,6 +41,7 @@ import {
meta,
primitive,
relativeTo,
rri,
} from '@cardstack/runtime-common';
import { getFieldOverrides, getFields, serializedGet } from './field-support';

Expand Down Expand Up @@ -100,7 +102,7 @@ function myLoader(): Loader {
export async function cardClassFromResource<CardT extends BaseDefConstructor>(
resource: LooseCardResource | CardResource | FileMetaResource | undefined,
fallback: CardT,
relativeTo: URL | undefined,
relativeTo: RealmResourceIdentifier | URL | undefined,
): Promise<CardT> {
let cardIdentity = identifyCard(fallback);
if (!cardIdentity) {
Expand All @@ -113,8 +115,7 @@ export async function cardClassFromResource<CardT extends BaseDefConstructor>(
resource.meta.adoptsFrom,
{
loader: myLoader(),
relativeTo:
relativeTo ?? (resource.id ? cardIdToURL(resource.id) : undefined),
relativeTo: relativeTo ?? (resource.id ? rri(resource.id) : undefined),
},
);
if (!card) {
Expand Down Expand Up @@ -216,10 +217,8 @@ export function serializeCard(
...(model.id != null ? { id: model.id } : { lid: model[localId] }),
},
};
let modelRelativeTo =
model.id != null
? cardIdToURL(model.id)
: (model[relativeTo] as URL | undefined);
let modelRelativeTo: RealmResourceIdentifier | URL | undefined =
model.id ?? model[relativeTo];
let data = serializeCardResource(model, doc, {
...opts,
...{
Expand All @@ -229,7 +228,11 @@ export function serializeCard(
if (isRegisteredPrefix(possibleReference)) {
return possibleReference;
}
let url = maybeURL(possibleReference, modelRelativeTo);
let modelRelativeToForURL =
typeof modelRelativeTo === 'string'
? cardIdToURL(modelRelativeTo)
: modelRelativeTo;
let url = maybeURL(possibleReference, modelRelativeToForURL);
if (!url) {
throw new Error(
`could not determine url from '${possibleReference}' relative to ${modelRelativeTo}`,
Expand Down Expand Up @@ -313,10 +316,8 @@ export function serializeFileDef(
...(model.id != null ? { id: model.id } : {}),
},
};
let modelRelativeTo =
model.id != null
? cardIdToURL(model.id)
: (model[relativeTo] as URL | undefined);
let modelRelativeTo: RealmResourceIdentifier | URL | undefined =
model.id ?? model[relativeTo];
let data = serializeCardResource(
model,
doc,
Expand All @@ -329,7 +330,11 @@ export function serializeFileDef(
if (isRegisteredPrefix(possibleReference)) {
return possibleReference;
}
let url = maybeURL(possibleReference, modelRelativeTo);
let modelRelativeToForURL =
typeof modelRelativeTo === 'string'
? cardIdToURL(modelRelativeTo)
: modelRelativeTo;
let url = maybeURL(possibleReference, modelRelativeToForURL);
if (!url) {
throw new Error(
`could not determine url from '${possibleReference}' relative to ${modelRelativeTo}`,
Expand Down
26 changes: 22 additions & 4 deletions packages/base/rich-markdown.gts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
cardIdToURL,
extractCardReferenceUrls,
fieldSerializer,
relativeTo,
Expand Down Expand Up @@ -53,7 +54,12 @@ export class RichMarkdownField extends FieldDef {
if (!this.content) {
return [];
}
let baseUrl = this[relativeTo]?.href ?? '';
let rel = this[relativeTo];
let baseUrl = rel
? typeof rel === 'string'
? cardIdToURL(rel).href
: rel.href
: '';
return extractCardReferenceUrls(this.content, baseUrl);
},
});
Expand All @@ -73,7 +79,11 @@ export class RichMarkdownField extends FieldDef {
return this.args.model?.content ?? null;
}
get baseUrl(): string | null {
return this.args.model?.[relativeTo]?.href ?? null;
let rel = this.args.model?.[relativeTo];
if (!rel) {
return null;
}
return typeof rel === 'string' ? cardIdToURL(rel).href : rel.href;
}
<template>
<MarkdownTemplate
Expand All @@ -89,7 +99,11 @@ export class RichMarkdownField extends FieldDef {
return this.args.model?.content ?? null;
}
get baseUrl(): string | null {
return this.args.model?.[relativeTo]?.href ?? null;
let rel = this.args.model?.[relativeTo];
if (!rel) {
return null;
}
return typeof rel === 'string' ? cardIdToURL(rel).href : rel.href;
}
<template>
<MarkdownTemplate
Expand Down Expand Up @@ -121,7 +135,11 @@ export class RichMarkdownField extends FieldDef {
this.args.model.content = markdown;
};
get baseUrl(): string | null {
return this.args.model?.[relativeTo]?.href ?? null;
let rel = this.args.model?.[relativeTo];
if (!rel) {
return null;
}
return typeof rel === 'string' ? cardIdToURL(rel).href : rel.href;
}
get linkedCards(): CardDef[] | null {
try {
Expand Down
6 changes: 3 additions & 3 deletions packages/base/spec.gts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export class SpecHeader extends GlimmerComponent<SpecHeaderSignature> {
if (this.args.model.ref && this.args.model.id) {
let cardDef = await loadCardDef(this.args.model.ref, {
loader: myLoader(),
relativeTo: cardIdToURL(this.args.model.id),
relativeTo: this.args.model.id,
});
cardDefObj.value = cardDef;
}
Expand Down Expand Up @@ -377,7 +377,7 @@ export class SpecExamplesSection extends GlimmerComponent<SpecExamplesSectionSig
if (this.args.model.ref && this.args.model.id) {
let cardDef = await loadCardDef(this.args.model.ref, {
loader: myLoader(),
relativeTo: cardIdToURL(this.args.model.id),
relativeTo: this.args.model.id,
});
cardDefObj.value = cardDef;
}
Expand Down Expand Up @@ -720,7 +720,7 @@ class Fitted extends Component<typeof Spec> {
if (this.args.model.ref && this.args.model.id) {
let card = await loadCardDef(this.args.model.ref, {
loader: myLoader(),
relativeTo: cardIdToURL(this.args.model.id),
relativeTo: this.args.model.id,
});
icon.value = card.icon;
}
Expand Down
11 changes: 9 additions & 2 deletions packages/experiments-realm/asset.gts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Component,
relativeTo,
} from 'https://cardstack.com/base/card-api';
import { cardIdToURL } from '@cardstack/runtime-common';
import StringField from 'https://cardstack.com/base/string';
import CurrencyIcon from '@cardstack/boxel-icons/currency';
import CircleDotIcon from '@cardstack/boxel-icons/circle-dot';
Expand All @@ -20,7 +21,10 @@ export class Asset extends CardDef {
if (!this.logoURL) {
return null;
}
return new URL(this.logoURL, this[relativeTo] || this.id).href;
let rel = this[relativeTo] || this.id;
let base =
typeof rel === 'string' ? cardIdToURL(rel) : rel;
return new URL(this.logoURL, base).href;
},
});
@field cardTitle = contains(StringField, {
Expand Down Expand Up @@ -89,7 +93,10 @@ class AssetField extends FieldDef {
if (!this.logoURL) {
return null;
}
return new URL(this.logoURL, this[relativeTo] || this.id).href;
let rel = this[relativeTo] || this.id;
let base =
typeof rel === 'string' ? cardIdToURL(rel) : rel;
return new URL(this.logoURL, base).href;
},
});
@field cardTitle = contains(StringField, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
} from '@cardstack/boxel-ui/icons';

import {
cardIdToURL,
specRef,
chooseCard,
baseRealm,
Expand Down Expand Up @@ -946,7 +945,7 @@ export class ${className} extends ${exportName} {

let { ref } = (this.definitionClass ? this.definitionClass : spec)!; // we just checked above to make sure one of these exist

let relativeTo = spec?.id ? cardIdToURL(spec.id) : undefined;
let relativeTo = spec?.id;
// we make the code ref use an absolute URL for safety in
// the case it's being created in a different realm than where the card
// definition comes from. The server will make relative URL if appropriate after creation
Expand Down
Loading
Loading