Skip to content

Commit

Permalink
feat: GameChanger data can now optionally have all refs and overrides…
Browse files Browse the repository at this point in the history
… resolved on load, for cases where that's useful.
  • Loading branch information
adam-coster committed Sep 25, 2024
1 parent 12f8070 commit e2fb7c7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 4 deletions.
68 changes: 65 additions & 3 deletions packages/gcdata/src/GameChanger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from './types.cl2.rumpus.js';
import {
Bschema,
BschemaObject,
ChangeType,
Changes,
changeSchema,
Expand All @@ -17,7 +18,9 @@ import {
isBschemaConst,
isBschemaEnum,
isBschemaNumeric,
isBschemaRef,
isBschemaString,
isObject,
type Mote,
type MoteId,
type PackedData,
Expand Down Expand Up @@ -51,7 +54,15 @@ export interface MoteVisitorCtx<T = undefined> {
}

export class Gcdata {
constructor(public data: PackedData) {}
constructor(
public data: PackedData,
options?: { resolveRefsAndOverrides?: boolean },
) {
// Resolve all refs and overrides in the schemas
if (options?.resolveRefsAndOverrides) {
Gcdata.resolveRefsAndOverrides(data);
}
}
get motes(): PackedData['motes'] {
return {
...this.data.motes,
Expand Down Expand Up @@ -201,9 +212,60 @@ export class Gcdata {
) as Mote<D>[];
}

static async from(gcdataFile: Pathy) {
static async from(
gcdataFile: Pathy,
options?: { resolveRefsAndOverrides?: boolean },
) {
const data = JSON.parse(await gcdataFile.read({ parse: false }));
return new Gcdata(data);
return new Gcdata(data, options);
}

/**
* Given a raw packed data object, recurse through to resolve
* all references and overrides.
*/
protected static resolveRefsAndOverrides(data: PackedData): void {
const recursivelyResolve = (subschema: Bschema) => {
while (isBschemaRef(subschema)) {
const ref = data.schemas[subschema.$ref];
assert(ref, `Could not resolve reference ${subschema.$ref}`);
// Mutate in place
Object.assign(subschema, ref);
//@ts-expect-error We've changed the type from a ref
delete subschema.$ref;
}
if (isObject(subschema)) {
if ('overrides' in subschema && isObject(subschema.overrides)) {
Object.assign(subschema, subschema.overrides);
delete subschema.overrides;
}
// If this was an object, need to recurse through properties
// and additionalProperties
if (
'additionalProperties' in subschema &&
isObject(subschema.additionalProperties)
) {
recursivelyResolve(subschema.additionalProperties as BschemaObject);
}
if ('properties' in subschema && isObject(subschema.properties)) {
for (const prop of Object.values(
subschema.properties as Record<string, Bschema>,
)) {
recursivelyResolve(prop);
}
}
// // This gives us a max callstack error,
// // so there must be circularity somewhere
// if ('oneOf' in subschema && Array.isArray(subschema.oneOf)) {
// for (const oneOf of subschema.oneOf) {
// recursivelyResolve(oneOf);
// }
// }
}
};
for (const schema of Object.values(data.schemas)) {
recursivelyResolve(schema);
}
}
}

Expand Down
12 changes: 11 additions & 1 deletion packages/gcdata/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ export function getAdditionalProperties(
return;
}

export function isBschemaRef(schema: any): schema is BschemaRef {
return isObject(schema) && '$ref' in schema && !!schema['$ref'];
}

export function isBschemaObject(schema: any): schema is BschemaObject {
return (
typeof schema === 'object' &&
Expand Down Expand Up @@ -131,7 +135,7 @@ interface BschemaBase {
/**
* A partial schema that will overwrite fields of the current one
*/
overrides?: string;
overrides?: any;

/**
* Internal pointer to the field that holds the mote's name
Expand Down Expand Up @@ -324,3 +328,9 @@ export const changesSchema = z
}),
})
.passthrough();

export function isObject<T extends object>(
value: unknown,
): value is Exclude<T, null> {
return typeof value === 'object' && value !== null;
}
5 changes: 5 additions & 0 deletions packages/gcdata/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export function normalizeSchema(
/** For resolving oneOfs */
data: any,
): Bschema {
let overrides: Bschema | undefined;
if ('$ref' in schema) {
const refParts = schema.$ref.split('/');
schema = gcData.getSchema(refParts[0])!;
Expand All @@ -162,6 +163,9 @@ export function normalizeSchema(
schema = resolvePointer(refParts.slice(1), schema)!;
assert(schema, `Could not resolve subpointer $ref ${refParts.join('/')}`);
}
if ('overrides' in schema) {
overrides = schema.overrides;
}
}
const oneOf = 'oneOf' in schema ? resolveOneOf(schema, data) : undefined;
let properties: BschemaObject['properties'] | undefined;
Expand All @@ -184,6 +188,7 @@ export function normalizeSchema(
// @ts-ignore
additionalProperties,
oneOf: undefined,
...overrides,
};
}

Expand Down

0 comments on commit e2fb7c7

Please sign in to comment.