The type system starts to infect the computation engine
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -20,7 +20,9 @@
|
||||
"multigraph",
|
||||
"nearley",
|
||||
"ngraph",
|
||||
"nonreactive",
|
||||
"ostrio",
|
||||
"pather",
|
||||
"recomputation",
|
||||
"Ruleset",
|
||||
"snackbars",
|
||||
|
||||
@@ -8,8 +8,7 @@ import { storedIconsSchema } from '/imports/api/icons/Icons';
|
||||
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
|
||||
import { ConvertToUnion, InferType, TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
|
||||
import { Simplify } from 'type-fest';
|
||||
|
||||
type PropertyType = Exclude<keyof typeof propertySchemasIndex, 'any'>;
|
||||
import type { PropertyType } from '/imports/api/properties/PropertyType.type';
|
||||
|
||||
const PreComputeCreaturePropertySchema = TypedSimpleSchema.from({
|
||||
_id: {
|
||||
|
||||
@@ -1,59 +1,11 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import ColorSchema, { Colored } from '/imports/api/properties/subSchemas/ColorSchema';
|
||||
import SharingSchema, { Shared } from '/imports/api/sharing/SharingSchema';
|
||||
import ColorSchema from '/imports/api/properties/subSchemas/ColorSchema';
|
||||
import SharingSchema from '/imports/api/sharing/SharingSchema';
|
||||
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
|
||||
import { InferType, TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
|
||||
import type { Simplify } from 'type-fest';
|
||||
|
||||
export type Creature = Colored & Shared & {
|
||||
// Strings
|
||||
_id: string,
|
||||
name?: string,
|
||||
alignment?: string,
|
||||
gender?: string,
|
||||
picture?: string,
|
||||
avatarPicture?: string,
|
||||
|
||||
// Libraries
|
||||
allowedLibraries?: string[],
|
||||
allowedLibraryCollections?: string[],
|
||||
|
||||
// Stats that are computed and denormalized outside of recomputation
|
||||
denormalizedStats?: {
|
||||
xp: number,
|
||||
milestoneLevels: number,
|
||||
},
|
||||
propCount?: number,
|
||||
// Does the character need a recompute?
|
||||
dirty?: boolean,
|
||||
// Version of computation engine that was last used to compute this creature
|
||||
computeVersion?: string,
|
||||
type: 'pc' | 'npc' | 'monster',
|
||||
computeErrors?: {
|
||||
type: string,
|
||||
details?: any,
|
||||
}[],
|
||||
|
||||
// Tabletop
|
||||
tabletopId?: string,
|
||||
initiativeRoll?: number,
|
||||
|
||||
settings: {
|
||||
useVariantEncumbrance?: true,
|
||||
hideSpellcasting?: true,
|
||||
hideRestButtons?: true,
|
||||
swapStatAndModifier?: true,
|
||||
hideUnusedStats?: true,
|
||||
showTreeTab?: true,
|
||||
hideSpellsTab?: true,
|
||||
hideCalculationErrors?: true,
|
||||
hitDiceResetMultiplier?: number,
|
||||
discordWebhook?: string,
|
||||
},
|
||||
};
|
||||
|
||||
//set up the collection for creatures
|
||||
const Creatures = new Mongo.Collection<Creature>('creatures');
|
||||
|
||||
const CreatureSettingsSchema = new SimpleSchema({
|
||||
const CreatureSettingsSchema = TypedSimpleSchema.from({
|
||||
//slowed down by carrying too much?
|
||||
useVariantEncumbrance: {
|
||||
type: Boolean,
|
||||
@@ -108,24 +60,7 @@ const CreatureSettingsSchema = new SimpleSchema({
|
||||
},
|
||||
});
|
||||
|
||||
const IconGroupSchema = new SimpleSchema({
|
||||
name: {
|
||||
type: String,
|
||||
max: STORAGE_LIMITS.name,
|
||||
optional: true,
|
||||
},
|
||||
iconIds: {
|
||||
type: Array,
|
||||
max: 4,
|
||||
defaultValue: [],
|
||||
},
|
||||
'iconIds.$': {
|
||||
type: String,
|
||||
max: STORAGE_LIMITS.variableName,
|
||||
},
|
||||
});
|
||||
|
||||
const CreatureSchema = new SimpleSchema({
|
||||
const CreatureSchema = TypedSimpleSchema.from({
|
||||
// Strings
|
||||
name: {
|
||||
type: String,
|
||||
@@ -246,10 +181,13 @@ const CreatureSchema = new SimpleSchema({
|
||||
CreatureSchema.extend(ColorSchema);
|
||||
CreatureSchema.extend(SharingSchema);
|
||||
|
||||
export type Creature = Simplify<{ _id: string } & InferType<typeof CreatureSchema>>;
|
||||
|
||||
//set up the collection for creatures
|
||||
const Creatures = new Mongo.Collection<Creature>('creatures');
|
||||
|
||||
//@ts-expect-error attachSchema not defined
|
||||
Creatures.attachSchema(CreatureSchema);
|
||||
|
||||
|
||||
|
||||
export default Creatures;
|
||||
export { CreatureSchema };
|
||||
|
||||
@@ -1,40 +1,53 @@
|
||||
import { EJSON } from 'meteor/ejson';
|
||||
import createGraph, { Graph } from 'ngraph.graph';
|
||||
import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags';
|
||||
import type { Creature } from '/imports/api/creature/creatures/Creatures';
|
||||
import type { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
|
||||
interface CreatureProperty {
|
||||
_id: string;
|
||||
type: string;
|
||||
}
|
||||
type ComputationProperty = CreatureProperty & {
|
||||
_computationDetails: {
|
||||
calculations: any[],
|
||||
emptyCalculations: any[],
|
||||
inlineCalculations: any[],
|
||||
toggleAncestors: any[],
|
||||
}
|
||||
};
|
||||
|
||||
export default class CreatureComputation {
|
||||
originalPropsById: Record<string, CreatureProperty>;
|
||||
propsById: Record<string, CreatureProperty>;
|
||||
propsWithTag: Record<string, string[]>;
|
||||
scope: Record<string, any>;
|
||||
props: Array<CreatureProperty>;
|
||||
props: ComputationProperty[];
|
||||
dependencyGraph: Graph<any, string>;
|
||||
errors: Array<object>;
|
||||
creature: object;
|
||||
creature: Creature;
|
||||
variables: object;
|
||||
|
||||
constructor(properties: Array<CreatureProperty>, creature: object, variables: object) {
|
||||
constructor(properties: Array<CreatureProperty>, creature: Creature, variables: object) {
|
||||
// Set up fields
|
||||
this.originalPropsById = {};
|
||||
this.propsById = {};
|
||||
this.propsWithTag = {};
|
||||
this.scope = {};
|
||||
this.props = properties;
|
||||
this.dependencyGraph = createGraph();
|
||||
this.errors = [];
|
||||
this.creature = creature;
|
||||
this.variables = variables;
|
||||
|
||||
// Store properties for easy access later
|
||||
properties.forEach(prop => {
|
||||
// Store properties and index for easy access later
|
||||
this.props = properties.map(originalProp => {
|
||||
const prop: ComputationProperty = Object.assign(EJSON.clone(originalProp), {
|
||||
_computationDetails: {
|
||||
calculations: [],
|
||||
emptyCalculations: [],
|
||||
inlineCalculations: [],
|
||||
toggleAncestors: [],
|
||||
}
|
||||
});
|
||||
// Store a copy of the unmodified prop
|
||||
// EJSON clone is ~4x faster than lodash cloneDeep for EJSONable objects
|
||||
this.originalPropsById[prop._id] = EJSON.clone(prop);
|
||||
this.originalPropsById[prop._id] = originalProp;
|
||||
// Store by id
|
||||
this.propsById[prop._id] = prop;
|
||||
|
||||
@@ -50,6 +63,8 @@ export default class CreatureComputation {
|
||||
|
||||
// Store the prop in the dependency graph
|
||||
this.dependencyGraph.addNode(prop._id, prop);
|
||||
|
||||
return prop;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import linkTypeDependencies from './buildComputation/linkTypeDependencies';
|
||||
import computeSlotQuantityFilled from './buildComputation/computeSlotQuantityFilled';
|
||||
import CreatureComputation from './CreatureComputation';
|
||||
import removeSchemaFields from './buildComputation/removeSchemaFields';
|
||||
import type { Creature } from '/imports/api/creature/creatures/Creatures';
|
||||
|
||||
/**
|
||||
* Store index of properties
|
||||
@@ -31,6 +32,7 @@ import removeSchemaFields from './buildComputation/removeSchemaFields';
|
||||
|
||||
export default function buildCreatureComputation(creatureId: string) {
|
||||
const creature = getCreature(creatureId);
|
||||
if (!creature) return;
|
||||
const variables = getVariables(creatureId);
|
||||
const properties = getProperties(creatureId);
|
||||
const computation = buildComputationFromProps(properties, creature, variables);
|
||||
@@ -38,7 +40,7 @@ export default function buildCreatureComputation(creatureId: string) {
|
||||
}
|
||||
|
||||
export function buildComputationFromProps(
|
||||
properties: CreatureProperty[], creature, variables
|
||||
properties: CreatureProperty[], creature: Creature, variables: any
|
||||
) {
|
||||
|
||||
const computation = new CreatureComputation(properties, creature, variables);
|
||||
@@ -67,24 +69,15 @@ export function buildComputationFromProps(
|
||||
}
|
||||
|
||||
// Process the properties one by one
|
||||
properties.forEach(prop => {
|
||||
computation.props.forEach(prop => {
|
||||
// The prop has been processed, it's no longer dirty
|
||||
delete prop.dirty;
|
||||
|
||||
const computedSchema = computedOnlySchemas[prop.type];
|
||||
removeSchemaFields([computedSchema, denormSchema], prop);
|
||||
|
||||
// Add a place to store all the computation details
|
||||
prop._computationDetails = {
|
||||
calculations: [],
|
||||
emptyCalculations: [],
|
||||
inlineCalculations: [],
|
||||
toggleAncestors: [],
|
||||
};
|
||||
|
||||
// Parse all the calculations
|
||||
parseCalculationFields(prop, computedSchemas);
|
||||
|
||||
});
|
||||
|
||||
// Get all the properties as a forest, with their nested set properties set
|
||||
|
||||
@@ -3,13 +3,20 @@ import computeByType from '/imports/api/engine/computation/computeComputation/co
|
||||
import embedInlineCalculations from './utility/embedInlineCalculations';
|
||||
import { removeEmptyCalculations } from './buildComputation/parseCalculationFields';
|
||||
import path from 'ngraph.path';
|
||||
import type CreatureComputation from './CreatureComputation';
|
||||
import type { Graph, Node, NodeId } from 'ngraph.graph';
|
||||
|
||||
export default async function computeCreatureComputation(computation) {
|
||||
const stack = [];
|
||||
type TraversedNode = Node<any> & {
|
||||
_visited?: boolean,
|
||||
_visitedChildren?: boolean,
|
||||
}
|
||||
|
||||
export default async function computeCreatureComputation(computation: CreatureComputation) {
|
||||
const stack: (TraversedNode)[] = [];
|
||||
// Computation scope of {variableName: prop}
|
||||
const graph = computation.dependencyGraph;
|
||||
// Add all nodes to the stack
|
||||
graph.forEachNode(node => {
|
||||
graph.forEachNode((node: TraversedNode) => {
|
||||
node._visited = false;
|
||||
node._visitedChildren = false;
|
||||
stack.push(node)
|
||||
@@ -22,7 +29,7 @@ export default async function computeCreatureComputation(computation) {
|
||||
|
||||
// Depth first traversal of nodes
|
||||
while (stack.length) {
|
||||
let top = stack[stack.length - 1];
|
||||
const top = stack[stack.length - 1];
|
||||
if (top._visited) {
|
||||
// The object has already been computed, skip
|
||||
stack.pop();
|
||||
@@ -45,21 +52,21 @@ export default async function computeCreatureComputation(computation) {
|
||||
}
|
||||
}
|
||||
|
||||
async function compute(computation, node) {
|
||||
async function compute(computation: CreatureComputation, node: TraversedNode) {
|
||||
// Determine the prop's active status by its toggles
|
||||
computeToggles(computation, node);
|
||||
// Compute the property by type
|
||||
await computeByType[node.data?.type || '_variable']?.(computation, node);
|
||||
}
|
||||
|
||||
function pushDependenciesToStack(nodeId, graph, stack, computation) {
|
||||
graph.forEachLinkedNode(nodeId, linkedNode => {
|
||||
function pushDependenciesToStack(nodeId: NodeId, graph: Graph, stack: TraversedNode[], computation: CreatureComputation) {
|
||||
graph.forEachLinkedNode(nodeId, (linkedNode: TraversedNode) => {
|
||||
if (linkedNode._visitedChildren && !linkedNode._visited) {
|
||||
// This is a dependency loop, find a path from the node to itself
|
||||
// and store that path as a dependency loop error
|
||||
const pather = path.nba(graph, { oriented: true });
|
||||
let loop = [];
|
||||
// Pather doesn't like going from a node to iteself, so find all the
|
||||
const loop: TraversedNode[] = [];
|
||||
// Pather doesn't like going from a node to itself, so find all the
|
||||
// paths going from the next node back to the original node
|
||||
// and return the shortest one
|
||||
graph.forEachLinkedNode(nodeId, nextNode => {
|
||||
@@ -3,34 +3,32 @@ import computeCreatureComputation from './computation/computeCreatureComputation
|
||||
import writeAlteredProperties from './computation/writeComputation/writeAlteredProperties';
|
||||
import writeScope from './computation/writeComputation/writeScope';
|
||||
import writeErrorsAndPropCount from './computation/writeComputation/writeErrorsAndPropCount';
|
||||
import type CreatureComputation from './computation/CreatureComputation';
|
||||
|
||||
export default async function computeCreature(creatureId) {
|
||||
export default async function computeCreature(creatureId: string) {
|
||||
if (Meteor.isClient) return;
|
||||
// console.log('compute ' + creatureId);
|
||||
const computation = buildCreatureComputation(creatureId);
|
||||
await computeComputation(computation, creatureId);
|
||||
}
|
||||
|
||||
async function computeComputation(computation, creatureId) {
|
||||
async function computeComputation(computation: CreatureComputation, creatureId: string) {
|
||||
try {
|
||||
await computeCreatureComputation(computation);
|
||||
const writePromise = writeAlteredProperties(computation);
|
||||
const scopeWritePromise = writeScope(creatureId, computation);
|
||||
await Promise.all([writePromise, scopeWritePromise]);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
const errorText = e.reason || e.message || e.toString();
|
||||
computation.errors.push({
|
||||
type: 'crash',
|
||||
details: { error: errorText },
|
||||
});
|
||||
const logError = {
|
||||
console.error({
|
||||
creatureId,
|
||||
computeError: errorText,
|
||||
};
|
||||
if (e.stack) {
|
||||
logError.location = e.stack.split('\n')[1];
|
||||
}
|
||||
console.error(logError);
|
||||
...e.stack && { location: e.stack.split('\n')[1] },
|
||||
});
|
||||
} finally {
|
||||
checkPropertyCount(computation)
|
||||
writeErrorsAndPropCount(creatureId, computation.errors, computation.props.length);
|
||||
@@ -38,7 +36,7 @@ async function computeComputation(computation, creatureId) {
|
||||
}
|
||||
|
||||
const MAX_PROPS = 1000;
|
||||
function checkPropertyCount(computation) {
|
||||
function checkPropertyCount(computation: CreatureComputation) {
|
||||
const count = computation.props.length;
|
||||
if (count <= MAX_PROPS) return;
|
||||
computation.errors.push({
|
||||
@@ -1,10 +1,10 @@
|
||||
import { debounce } from 'lodash';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures';
|
||||
import Creatures, { Creature } from '/imports/api/creature/creatures/Creatures';
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import CreatureProperties, { CreatureProperty, CreaturePropertyByType } from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
import CreatureProperties, { CreatureProperty, CreaturePropertyTypes } from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
import computeCreature from './computeCreature';
|
||||
import { getFilter } from '/imports/api/parenting/parentingFunctions';
|
||||
import { ComputedPropertyTypeMap } from '../properties/Property.type';
|
||||
import type { PropertyType } from '/imports/api/properties/PropertyType.type';
|
||||
|
||||
const COMPUTE_DEBOUNCE_TIME = 100; // ms
|
||||
export const loadedCreatures: Map<string, LoadedCreature> = new Map(); // creatureId => {creature, properties, etc.}
|
||||
@@ -34,7 +34,7 @@ export function loadCreature(creatureId: string, subscription: Tracker.Computati
|
||||
// logLoadedCreatures()
|
||||
}
|
||||
|
||||
function unloadCreature(creatureId, subscription) {
|
||||
function unloadCreature(creatureId: string, subscription: Tracker.Computation) {
|
||||
if (!creatureId) throw 'creatureId is required';
|
||||
const creature = loadedCreatures.get(creatureId);
|
||||
if (!creature) return;
|
||||
@@ -82,13 +82,13 @@ export function getProperties(creatureId: string): CreatureProperty[] {
|
||||
return props;
|
||||
}
|
||||
|
||||
export function getPropertiesOfType<T extends keyof ComputedPropertyTypeMap>(creatureId, propType: T): CreaturePropertyByType<T>[] {
|
||||
export function getPropertiesOfType<T extends PropertyType>(creatureId: string, propType: T): CreaturePropertyTypes[T][] {
|
||||
const creature = loadedCreatures.get(creatureId);
|
||||
if (creature) {
|
||||
const props = Array.from(creature.properties.values())
|
||||
.filter(prop => !prop.removed && prop.type === propType)
|
||||
.sort((a, b) => a.left - b.left);
|
||||
return EJSON.clone(props) as unknown as CreaturePropertyByType<T>[];
|
||||
return EJSON.clone(props) as unknown as CreaturePropertyTypes[T][];
|
||||
}
|
||||
// console.time(`Cache miss on creature properties: ${creatureId}`)
|
||||
const props = CreatureProperties.find({
|
||||
@@ -99,7 +99,7 @@ export function getPropertiesOfType<T extends keyof ComputedPropertyTypeMap>(cre
|
||||
sort: { left: 1 },
|
||||
}).fetch();
|
||||
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
||||
return props as unknown as CreaturePropertyByType<T>[];
|
||||
return props as unknown as CreaturePropertyTypes[T][];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +108,11 @@ export function getPropertiesOfType<T extends keyof ComputedPropertyTypeMap>(cre
|
||||
* @param filterFn A function that returns true if the given prop matches the filter
|
||||
* @param mongoFilter A mongo selector that is exactly equal to the above function
|
||||
*/
|
||||
export function getPropertiesByFilter(creatureId, filterFn: (any) => boolean, mongoFilter: Mongo.Selector<object>) {
|
||||
export function getPropertiesByFilter(
|
||||
creatureId: string,
|
||||
filterFn: (value: CreatureProperty, index: number, array: CreatureProperty[]) => unknown,
|
||||
mongoFilter: Mongo.Selector<CreatureProperty>
|
||||
) {
|
||||
const creature = loadedCreatures.get(creatureId);
|
||||
if (creature) {
|
||||
const props: CreatureProperty[] = Array.from(creature.properties.values())
|
||||
@@ -121,7 +125,7 @@ export function getPropertiesByFilter(creatureId, filterFn: (any) => boolean, mo
|
||||
'root.id': creatureId,
|
||||
'removed': { $ne: true },
|
||||
...mongoFilter
|
||||
}, {
|
||||
} as any, {
|
||||
sort: { left: 1 },
|
||||
}).fetch();
|
||||
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
||||
@@ -152,7 +156,7 @@ export function getVariables(creatureId: string) {
|
||||
return variables;
|
||||
}
|
||||
|
||||
export function replaceLinkedVariablesWithProps(variables) {
|
||||
export function replaceLinkedVariablesWithProps(variables: any) {
|
||||
for (const key in variables) {
|
||||
const propId = variables[key]?._propId;
|
||||
if (!propId) continue;
|
||||
@@ -185,7 +189,7 @@ export function getPropertyAncestors(creatureId: string, propertyId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getPropertyDescendants(creatureId, propertyId) {
|
||||
export function getPropertyDescendants(creatureId: string, propertyId: string) {
|
||||
const property = getSingleProperty(creatureId, propertyId);
|
||||
if (!property) return [];
|
||||
if (loadedCreatures.has(creatureId)) {
|
||||
@@ -219,7 +223,7 @@ export function getPropertyDescendants(creatureId, propertyId) {
|
||||
* @param {string | any} property prop or prop ID to get children of
|
||||
* @returns {any[]} An array of child properties in tree order
|
||||
*/
|
||||
export function getPropertyChildren(creatureId, property) {
|
||||
export function getPropertyChildren(creatureId: string, property: string | CreatureProperty | undefined) {
|
||||
if (typeof property === 'string') {
|
||||
property = getSingleProperty(creatureId, property);
|
||||
}
|
||||
@@ -247,15 +251,15 @@ export function getPropertyChildren(creatureId, property) {
|
||||
}
|
||||
|
||||
class LoadedCreature {
|
||||
subs: Set<Tracker.Computation>;
|
||||
propertyObserver: Meteor.LiveQueryHandle;
|
||||
creatureObserver: Meteor.LiveQueryHandle;
|
||||
variablesObserver: Meteor.LiveQueryHandle;
|
||||
properties: Map<string, CreatureProperty>;
|
||||
creature: any;
|
||||
subs!: Set<Tracker.Computation>;
|
||||
propertyObserver!: Meteor.LiveQueryHandle;
|
||||
creatureObserver!: Meteor.LiveQueryHandle;
|
||||
variablesObserver!: Meteor.LiveQueryHandle;
|
||||
properties!: Map<string, CreatureProperty>;
|
||||
creature?: Creature;
|
||||
variables: any;
|
||||
|
||||
constructor(sub, creatureId) {
|
||||
constructor(sub: Tracker.Computation, creatureId: string) {
|
||||
const self = this;
|
||||
// This may be called from a subscription, but we don't want the observers
|
||||
// to be destroyed with it, so use a non-reactive context to observe
|
||||
@@ -271,7 +275,7 @@ class LoadedCreature {
|
||||
self.propertyObserver = CreatureProperties.find({
|
||||
'root.id': creatureId,
|
||||
}).observeChanges({
|
||||
added(id, fields) {
|
||||
added(id, fields: CreatureProperty) {
|
||||
fields._id = id;
|
||||
self.addProperty(fields);
|
||||
if (fields.dirty) compute();
|
||||
@@ -290,7 +294,7 @@ class LoadedCreature {
|
||||
self.creatureObserver = Creatures.find({
|
||||
_id: creatureId,
|
||||
}).observeChanges({
|
||||
added(id, fields) {
|
||||
added(id, fields: Creature) {
|
||||
fields._id = id;
|
||||
self.addCreature(fields)
|
||||
if (fields.dirty) compute();
|
||||
@@ -310,7 +314,7 @@ class LoadedCreature {
|
||||
}, {
|
||||
fields: { _creatureId: 0 },
|
||||
}).observeChanges({
|
||||
added(id, fields) {
|
||||
added(id, fields: any) {
|
||||
fields._id = id;
|
||||
self.addVariables(fields)
|
||||
},
|
||||
@@ -328,38 +332,38 @@ class LoadedCreature {
|
||||
this.creatureObserver.stop();
|
||||
this.variablesObserver.stop();
|
||||
}
|
||||
addProperty(prop) {
|
||||
addProperty(prop: CreatureProperty) {
|
||||
this.properties.set(prop._id, prop);
|
||||
}
|
||||
changeProperty(id, fields) {
|
||||
changeProperty(id: string, fields: Partial<CreatureProperty>) {
|
||||
LoadedCreature.changeMap(id, fields, this.properties);
|
||||
}
|
||||
removeProperty(id) {
|
||||
removeProperty(id: string) {
|
||||
this.properties.delete(id)
|
||||
}
|
||||
addCreature(creature) {
|
||||
addCreature(creature: Creature) {
|
||||
this.creature = creature;
|
||||
}
|
||||
changeCreature(id, fields) {
|
||||
changeCreature(id: string, fields: Partial<Creature>) {
|
||||
LoadedCreature.changeDoc(this.creature, fields);
|
||||
}
|
||||
removeCreature() {
|
||||
delete this.creature;
|
||||
}
|
||||
addVariables(variables) {
|
||||
addVariables(variables: any) {
|
||||
this.variables = variables;
|
||||
}
|
||||
changeVariables(id, fields) {
|
||||
changeVariables(id: string, fields: any) {
|
||||
LoadedCreature.changeDoc(this.variables, fields);
|
||||
}
|
||||
removeVariables() {
|
||||
delete this.variables;
|
||||
}
|
||||
static changeMap(id, fields, map) {
|
||||
static changeMap(id: string, fields: any, map: any) {
|
||||
const doc = map.get(id);
|
||||
LoadedCreature.changeDoc(doc, fields);
|
||||
}
|
||||
static changeDoc(doc, fields) {
|
||||
static changeDoc(doc: any, fields: any) {
|
||||
if (!doc) return;
|
||||
for (const key in fields) {
|
||||
if (key === undefined) {
|
||||
|
||||
3
app/imports/api/properties/PropertyType.type.ts
Normal file
3
app/imports/api/properties/PropertyType.type.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import propertySchemasIndex from './computedPropertySchemasIndex';
|
||||
|
||||
export type PropertyType = Exclude<keyof typeof propertySchemasIndex, 'any'>;
|
||||
@@ -16,7 +16,6 @@
|
||||
"preserveSymlinks": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noImplicitAny": false,
|
||||
"noErrorTruncation": true,
|
||||
"outDir": "build",
|
||||
"paths": {
|
||||
|
||||
Reference in New Issue
Block a user