diff --git a/app/imports/api/creature/archive/ArchiveCreatureFiles.js b/app/imports/api/creature/archive/ArchiveCreatureFiles.js index 044e6158..206f187c 100644 --- a/app/imports/api/creature/archive/ArchiveCreatureFiles.js +++ b/app/imports/api/creature/archive/ArchiveCreatureFiles.js @@ -1,7 +1,7 @@ import SimpleSchema from 'simpl-schema'; import { incrementFileStorageUsed } from '/imports/api/users/methods/updateFileStorageUsed.js'; -import { CreaturePropertySchema } from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import { CreaturePropertySchema } from '/imports/api/creature/creatureProperties/CreatureProperties'; import { CreatureSchema } from '/imports/api/creature/creatures/Creatures.js'; let createS3FilesCollection; if (Meteor.isServer) { diff --git a/app/imports/api/creature/archive/methods/archiveCreatureToFile.js b/app/imports/api/creature/archive/methods/archiveCreatureToFile.js index 92b6f3bd..ca3f212e 100644 --- a/app/imports/api/creature/archive/methods/archiveCreatureToFile.js +++ b/app/imports/api/creature/archive/methods/archiveCreatureToFile.js @@ -4,18 +4,18 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { assertOwnership } from '/imports/api/creature/creatures/creaturePermissions.js'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; import Experiences from '/imports/api/creature/experience/Experiences.js'; import { removeCreatureWork } from '/imports/api/creature/creatures/methods/removeCreature.js'; import ArchiveCreatureFiles from '/imports/api/creature/archive/ArchiveCreatureFiles.js'; -export function getArchiveObj(creatureId){ +export function getArchiveObj(creatureId) { // Build the archive document const creature = Creatures.findOne(creatureId); - const properties = CreatureProperties.find({'ancestors.id': creatureId}).fetch(); - const experiences = Experiences.find({creatureId}).fetch(); - const logs = CreatureLogs.find({creatureId}).fetch(); + const properties = CreatureProperties.find({ 'ancestors.id': creatureId }).fetch(); + const experiences = Experiences.find({ creatureId }).fetch(); + const logs = CreatureLogs.find({ creatureId }).fetch(); let archiveCreature = { meta: { type: 'DiceCloud V2 Creature Archive', @@ -31,7 +31,7 @@ export function getArchiveObj(creatureId){ return archiveCreature; } -export function archiveCreature(creatureId){ +export function archiveCreature(creatureId) { const archive = getArchiveObj(creatureId); const buffer = Buffer.from(JSON.stringify(archive, null, 2)); ArchiveCreatureFiles.write(buffer, { @@ -44,7 +44,7 @@ export function archiveCreature(creatureId){ creatureName: archive.creature.name, }, }, (error) => { - if (error){ + if (error) { throw error; } else { removeCreatureWork(creatureId); @@ -65,9 +65,9 @@ const archiveCreatureToFile = new ValidatedMethod({ numRequests: 10, timeInterval: 5000, }, - async run({creatureId}) { + async run({ creatureId }) { assertOwnership(creatureId, this.userId); - if (Meteor.isServer){ + if (Meteor.isServer) { archiveCreature(creatureId, this.userId); } else { removeCreatureWork(creatureId); diff --git a/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js b/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js index 112ea06d..516af6e9 100644 --- a/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js +++ b/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js @@ -3,7 +3,7 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; import Experiences from '/imports/api/creature/experience/Experiences.js'; import { removeCreatureWork } from '/imports/api/creature/creatures/methods/removeCreature.js'; diff --git a/app/imports/api/creature/creatureProperties/CreatureProperties.js b/app/imports/api/creature/creatureProperties/CreatureProperties.ts similarity index 79% rename from app/imports/api/creature/creatureProperties/CreatureProperties.js rename to app/imports/api/creature/creatureProperties/CreatureProperties.ts index b451dd1d..e42d9a6c 100644 --- a/app/imports/api/creature/creatureProperties/CreatureProperties.js +++ b/app/imports/api/creature/creatureProperties/CreatureProperties.ts @@ -1,15 +1,35 @@ import { Mongo } from 'meteor/mongo'; import SimpleSchema from 'simpl-schema'; import ColorSchema from '/imports/api/properties/subSchemas/ColorSchema.js'; -import ChildSchema from '/imports/api/parenting/ChildSchema.js'; +import ChildSchema, { TreeDoc } from '/imports/api/parenting/ChildSchema'; import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema.js'; import propertySchemasIndex from '/imports/api/properties/computedPropertySchemasIndex.js'; import { storedIconsSchema } from '/imports/api/icons/Icons.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; -let CreatureProperties = new Mongo.Collection('creatureProperties'); +const CreatureProperties: Mongo.Collection = new Mongo.Collection('creatureProperties'); -let CreaturePropertySchema = new SimpleSchema({ +export interface CreatureProperty extends TreeDoc { + _id: string + _migrationError?: string + type: string + tags: string[] + disabled?: boolean + icon?: { + name: string + shape: string + }, + libraryNodeId?: string + slotQuantityFilled?: number + inactive?: boolean + deactivatedByAncestor?: boolean + deactivatedBySelf?: boolean + deactivatedByToggle?: boolean + deactivatingToggleId?: boolean + dirty?: boolean +} + +const CreaturePropertySchema = new SimpleSchema({ _id: { type: String, regEx: SimpleSchema.RegEx.Id, @@ -56,7 +76,7 @@ let CreaturePropertySchema = new SimpleSchema({ const DenormalisedOnlyCreaturePropertySchema = new SimpleSchema({ // Denormalised flag if this property is inactive on the sheet for any reason - // Including being disabled, or a decendent of a disabled property + // Including being disabled, or a descendant of a disabled property inactive: { type: Boolean, optional: true, @@ -105,13 +125,14 @@ const DenormalisedOnlyCreaturePropertySchema = new SimpleSchema({ CreaturePropertySchema.extend(DenormalisedOnlyCreaturePropertySchema); -for (let key in propertySchemasIndex) { - let schema = new SimpleSchema({}); +for (const key in propertySchemasIndex) { + const schema = new SimpleSchema({}); schema.extend(propertySchemasIndex[key]); schema.extend(CreaturePropertySchema); schema.extend(ColorSchema); schema.extend(ChildSchema); schema.extend(SoftRemovableSchema); + // @ts-expect-error don't have types for .attachSchema CreatureProperties.attachSchema(schema, { selector: { type: key } }); diff --git a/app/imports/api/creature/creatureProperties/methods/adjustQuantity.js b/app/imports/api/creature/creatureProperties/methods/adjustQuantity.js index d08c43bb..1f2874ef 100644 --- a/app/imports/api/creature/creatureProperties/methods/adjustQuantity.js +++ b/app/imports/api/creature/creatureProperties/methods/adjustQuantity.js @@ -1,7 +1,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; diff --git a/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js b/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js index b46205b9..0cfcd86a 100644 --- a/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js +++ b/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js @@ -1,9 +1,9 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import LibraryNodes from '/imports/api/library/LibraryNodes.js'; -import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; +import { RefSchema } from '/imports/api/parenting/ChildSchema'; import { assertEditPermission, assertDocEditPermission, @@ -13,9 +13,8 @@ import { setLineageOfDocs, getAncestry, renewDocIds -} from '/imports/api/parenting/parenting.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; -import { setDocToLastOrder } from '/imports/api/parenting/order.js'; +} from '/imports/api/parenting/parentingFunctions'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; import Libraries from '/imports/api/library/Libraries.js'; const DUPLICATE_CHILDREN_LIMIT = 500; @@ -57,10 +56,7 @@ const copyPropertyToLibrary = new ValidatedMethod({ const insertedRootNode = insertNodeFromProperty(propId, ancestors, order, this); // Tree structure changed by inserts, reorder the tree - reorderDocs({ - collection: LibraryNodes, - ancestorId: rootLibrary._id, - }); + rebuildNestedSets(LibraryNodes, rootLibrary._id); // Return the docId of the inserted root property return insertedRootNode?._id; @@ -124,10 +120,7 @@ function insertNodeFromProperty(propId, ancestors, order, method) { // Order the root node if (order === undefined) { - setDocToLastOrder({ - collection: LibraryNodes, - doc: prop, - }); + rebuildNestedSets(LibraryNodes, prop.root.id); } else { prop.order = order; } diff --git a/app/imports/api/creature/creatureProperties/methods/damageProperty.js b/app/imports/api/creature/creatureProperties/methods/damageProperty.js index a8cd0696..fee7a24e 100644 --- a/app/imports/api/creature/creatureProperties/methods/damageProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/damageProperty.js @@ -1,10 +1,10 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; -import { applyTriggers } from '/imports/api/engine/actions/applyTriggers.js'; -import ActionContext from '/imports/api/engine/actions/ActionContext.js'; +import { applyTriggers } from '/imports/api/engine/actions/applyTriggers'; +import ActionContext from '/imports/api/engine/actions/ActionContext'; const damageProperty = new ValidatedMethod({ name: 'creatureProperties.damage', @@ -59,7 +59,7 @@ const damageProperty = new ValidatedMethod({ }, }); -export function damagePropertyWork({ prop, operation, value, actionContext, logFunction }) { +export function damagePropertyWork({ prop, operation, value, actionContext, logFunction = undefined }) { // Save the value to the scope before applying the before triggers if (operation === 'increment') { diff --git a/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js b/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js index 88e2f900..7dafa0f0 100644 --- a/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js @@ -1,14 +1,14 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import { setLineageOfDocs, renewDocIds -} from '/imports/api/parenting/parenting.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; +} from '/imports/api/parenting/parentingFunctions'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; var snackbar; if (Meteor.isClient) { snackbar = require( @@ -90,10 +90,7 @@ const duplicateProperty = new ValidatedMethod({ CreatureProperties.batchInsert(allNodes); // Tree structure changed by inserts, reorder the tree - reorderDocs({ - collection: CreatureProperties, - ancestorId: property.ancestors[0].id, - }); + rebuildNestedSets(CreatureProperties, property.root.id); return propertyId; }, diff --git a/app/imports/api/creature/creatureProperties/methods/equipItem.js b/app/imports/api/creature/creatureProperties/methods/equipItem.js index 671908b3..eb0e8057 100644 --- a/app/imports/api/creature/creatureProperties/methods/equipItem.js +++ b/app/imports/api/creature/creatureProperties/methods/equipItem.js @@ -1,5 +1,5 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import { organizeDoc } from '/imports/api/parenting/organizeMethods.js'; diff --git a/app/imports/api/creature/creatureProperties/methods/flipToggle.js b/app/imports/api/creature/creatureProperties/methods/flipToggle.js index dbd814ff..1f60bb2c 100644 --- a/app/imports/api/creature/creatureProperties/methods/flipToggle.js +++ b/app/imports/api/creature/creatureProperties/methods/flipToggle.js @@ -1,6 +1,6 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; diff --git a/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js b/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js index f5236c9f..bdcb4c10 100644 --- a/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js +++ b/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js @@ -1,13 +1,13 @@ -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -export default function getParentRefByTag(creatureId, tag){ +export default function getParentRefByTag(creatureId, tag) { let prop = CreatureProperties.findOne({ 'ancestors.id': creatureId, - removed: {$ne: true}, - inactive: {$ne: true}, + removed: { $ne: true }, + inactive: { $ne: true }, tags: tag, }, { - sort: {order: 1}, + sort: { order: 1 }, }); - return prop && {id: prop._id, collection: 'creatureProperties'}; + return prop && { id: prop._id, collection: 'creatureProperties' }; } diff --git a/app/imports/api/creature/creatureProperties/methods/insertProperty.js b/app/imports/api/creature/creatureProperties/methods/insertProperty.js index 2d872868..7647b64a 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/insertProperty.js @@ -1,13 +1,13 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import SimpleSchema from 'simpl-schema'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; -import { getAncestry } from '/imports/api/parenting/parenting.js'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; +import { getAncestry } from '/imports/api/parenting/parentingFunctions'; import getParentRefByTag from '/imports/api/creature/creatureProperties/methods/getParentRefByTag.js'; -import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; +import { RefSchema } from '/imports/api/parenting/ChildSchema'; import { getHighestOrder } from '/imports/api/parenting/order.js'; const insertProperty = new ValidatedMethod({ @@ -134,10 +134,7 @@ export function insertPropertyWork({ property, creature }) { property.dirty = true; let _id = CreatureProperties.insert(property); // Tree structure changed by insert, reorder the tree - reorderDocs({ - collection: CreatureProperties, - ancestorId: creature._id, - }); + rebuildNestedSets(CreatureProperties, creature._id); return _id; } diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index 8f0eefa6..f4b10416 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -1,19 +1,19 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import LibraryNodes from '/imports/api/library/LibraryNodes.js'; -import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; +import { RefSchema } from '/imports/api/parenting/ChildSchema'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import { setLineageOfDocs, getAncestry, renewDocIds -} from '/imports/api/parenting/parenting.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; +} from '/imports/api/parenting/parentingFunctions'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; import { setDocToLastOrder } from '/imports/api/parenting/order.js'; -import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; +import { fetchDocByRef } from '/imports/api/parenting/parentingFunctions'; import { union } from 'lodash'; const insertPropertyFromLibraryNode = new ValidatedMethod({ @@ -67,10 +67,7 @@ const insertPropertyFromLibraryNode = new ValidatedMethod({ let rootId = node._id; // Tree structure changed by inserts, reorder the tree - reorderDocs({ - collection: CreatureProperties, - ancestorId: rootCreature._id, - }); + rebuildNestedSets(CreatureProperties, rootCreature._id); // Return the docId of the last property, the inserted root property return rootId; }, diff --git a/app/imports/api/creature/creatureProperties/methods/pullFromProperty.js b/app/imports/api/creature/creatureProperties/methods/pullFromProperty.js index 4dd8245e..d4fc9d33 100644 --- a/app/imports/api/creature/creatureProperties/methods/pullFromProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/pullFromProperty.js @@ -1,6 +1,6 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; diff --git a/app/imports/api/creature/creatureProperties/methods/pushToProperty.js b/app/imports/api/creature/creatureProperties/methods/pushToProperty.js index 95735d9b..9fadf1ca 100644 --- a/app/imports/api/creature/creatureProperties/methods/pushToProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/pushToProperty.js @@ -1,6 +1,6 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import { get } from 'lodash'; diff --git a/app/imports/api/creature/creatureProperties/methods/restoreProperty.js b/app/imports/api/creature/creatureProperties/methods/restoreProperty.js index 9e66448e..810fc30f 100644 --- a/app/imports/api/creature/creatureProperties/methods/restoreProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/restoreProperty.js @@ -1,9 +1,9 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; -import { restore } from '/imports/api/parenting/softRemove.js'; +import { restore } from '/imports/api/parenting/softRemove'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; const restoreProperty = new ValidatedMethod({ diff --git a/app/imports/api/creature/creatureProperties/methods/selectAmmoItem.js b/app/imports/api/creature/creatureProperties/methods/selectAmmoItem.js index 57bbe6bd..7379859f 100644 --- a/app/imports/api/creature/creatureProperties/methods/selectAmmoItem.js +++ b/app/imports/api/creature/creatureProperties/methods/selectAmmoItem.js @@ -1,7 +1,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; diff --git a/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js b/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js index a4240ac7..de871b74 100644 --- a/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js @@ -1,9 +1,9 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; -import { softRemove } from '/imports/api/parenting/softRemove.js'; +import { softRemove } from '/imports/api/parenting/softRemove'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; const softRemoveProperty = new ValidatedMethod({ diff --git a/app/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js b/app/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js index 5664d8bd..63739f50 100644 --- a/app/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js @@ -1,6 +1,6 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; diff --git a/app/imports/api/creature/creatures/methods/insertCreature.js b/app/imports/api/creature/creatures/methods/insertCreature.js index c978785b..79373ca5 100644 --- a/app/imports/api/creature/creatures/methods/insertCreature.js +++ b/app/imports/api/creature/creatures/methods/insertCreature.js @@ -2,7 +2,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import simpleSchemaMixin from '/imports/api/creature/mixins/simpleSchemaMixin.js'; import Creatures, { CreatureSchema } from '/imports/api/creature/creatures/Creatures.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import defaultCharacterProperties from '/imports/api/creature/creatures/defaultCharacterProperties.js'; import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js'; import assertHasCharactersSlots from '/imports/api/creature/creatures/methods/assertHasCharacterSlots.js'; diff --git a/app/imports/api/creature/creatures/methods/removeCreature.js b/app/imports/api/creature/creatures/methods/removeCreature.js index d157f5d7..df0b8e5e 100644 --- a/app/imports/api/creature/creatures/methods/removeCreature.js +++ b/app/imports/api/creature/creatures/methods/removeCreature.js @@ -4,15 +4,15 @@ import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { assertOwnership } from '/imports/api/creature/creatures/creaturePermissions.js'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; import Experiences from '/imports/api/creature/experience/Experiences.js'; -function removeRelatedDocuments(creatureId){ - CreatureVariables.remove({_creatureId: creatureId}); - CreatureProperties.remove({'ancestors.id': creatureId}); - CreatureLogs.remove({creatureId}); - Experiences.remove({creatureId}); +function removeRelatedDocuments(creatureId) { + CreatureVariables.remove({ _creatureId: creatureId }); + CreatureProperties.remove({ 'ancestors.id': creatureId }); + CreatureLogs.remove({ creatureId }); + Experiences.remove({ creatureId }); } const removeCreature = new ValidatedMethod({ @@ -28,14 +28,14 @@ const removeCreature = new ValidatedMethod({ numRequests: 5, timeInterval: 5000, }, - run({charId}) { + run({ charId }) { assertOwnership(charId, this.userId) this.unblock(); removeCreatureWork(charId) }, }); -export function removeCreatureWork(creatureId){ +export function removeCreatureWork(creatureId) { Creatures.remove(creatureId); removeRelatedDocuments(creatureId); } diff --git a/app/imports/api/creature/creatures/methods/restCreature.js b/app/imports/api/creature/creatures/methods/restCreature.js index bb351c03..da06d093 100644 --- a/app/imports/api/creature/creatures/methods/restCreature.js +++ b/app/imports/api/creature/creatures/methods/restCreature.js @@ -1,11 +1,11 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; import { union } from 'lodash'; -import ActionContext from '/imports/api/engine/actions/ActionContext.js'; -import { applyTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import ActionContext from '/imports/api/engine/actions/ActionContext'; +import { applyTriggers } from '/imports/api/engine/actions/applyTriggers'; import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js'; const restCreature = new ValidatedMethod({ diff --git a/app/imports/api/creature/log/CreatureLogs.js b/app/imports/api/creature/log/CreatureLogs.js index 62fbf798..e3c2b04b 100644 --- a/app/imports/api/creature/log/CreatureLogs.js +++ b/app/imports/api/creature/log/CreatureLogs.js @@ -1,7 +1,7 @@ import SimpleSchema from 'simpl-schema'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables.js'; -import LogContentSchema from '/imports/api/creature/log/LogContentSchema.js'; +import LogContentSchema from '/imports/api/creature/log/LogContentSchema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; diff --git a/app/imports/api/creature/log/LogContentSchema.js b/app/imports/api/creature/log/LogContentSchema.ts similarity index 86% rename from app/imports/api/creature/log/LogContentSchema.js rename to app/imports/api/creature/log/LogContentSchema.ts index 05d9ce87..5d84d5fe 100644 --- a/app/imports/api/creature/log/LogContentSchema.js +++ b/app/imports/api/creature/log/LogContentSchema.ts @@ -3,6 +3,17 @@ import ErrorSchema from '/imports/api/properties/subSchemas/ErrorSchema.js'; import RollDetailsSchema from '/imports/api/properties/subSchemas/RollDetailsSchema.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; +export interface LogContent { + name?: string + value?: string + inline?: boolean + context?: { + errors: any[] + rolls: any[] + doubleRolls?: boolean + } +} + let LogContentSchema = new SimpleSchema({ // The name of the field, included in discord webhook message name: { @@ -26,7 +37,7 @@ let LogContentSchema = new SimpleSchema({ type: Object, optional: true, }, - 'context.errors':{ + 'context.errors': { type: Array, defaultValue: [], maxCount: STORAGE_LIMITS.errorCount, diff --git a/app/imports/api/creature/mixins/propagateInheritanceUpdateMixin.js b/app/imports/api/creature/mixins/propagateInheritanceUpdateMixin.js index 0ed6ee9f..c238e113 100644 --- a/app/imports/api/creature/mixins/propagateInheritanceUpdateMixin.js +++ b/app/imports/api/creature/mixins/propagateInheritanceUpdateMixin.js @@ -1,21 +1,21 @@ import { updateChildren, updateDescendants, -} from '/imports/api/parenting/parenting.js'; -import { inheritedFields } from '/imports/api/parenting/ChildSchema.js'; +} from '/imports/api/parenting/parentingFunctions'; +import { inheritedFields } from '/imports/api/parenting/ChildSchema'; import MONGO_OPERATORS from '/imports/constants/MONGO_OPERATORS.js'; // This mixin can be safely applied to all update methods which are validated // with the updateSchemaMixin. It will propagate updates to fields which // are inherited and normalised on the parent or ancestor docs // It should have neglible performance impact for updates that aren't inherited -function propagateInheritanceUpdate({_id, update}){ +function propagateInheritanceUpdate({ _id, update }) { let childModifier = {}; let descendantModifier = {}; // For each operator - for (let operator of MONGO_OPERATORS){ + for (let operator of MONGO_OPERATORS) { // If the operator is in the update, for each field - if (update[operator]) for (let field in update[operator]){ + if (update[operator]) for (let field in update[operator]) { // Get the top level field that was actually modified const indexOfDot = field.indexOf('.'); let modifiedField; @@ -25,7 +25,7 @@ function propagateInheritanceUpdate({_id, update}){ modifiedField = field; } // If that field is updated and inherited - if (inheritedFields.has(modifiedField)){ + if (inheritedFields.has(modifiedField)) { // Perform the same update on the descendants if (!childModifier[operator]) childModifier[operator] = {}; if (!descendantModifier[operator]) descendantModifier[operator] = {}; @@ -48,11 +48,11 @@ function propagateInheritanceUpdate({_id, update}){ }); } -export default function propagateInheritanceUpdateMixin(methodOptions){ +export default function propagateInheritanceUpdateMixin(methodOptions) { let runFunc = methodOptions.run; - methodOptions.run = function({_id, update}){ + methodOptions.run = function ({ _id, update }) { const result = runFunc.apply(this, arguments); - propagateInheritanceUpdate({_id, update}); + propagateInheritanceUpdate({ _id, update }); return result; }; return methodOptions; diff --git a/app/imports/api/docs/Docs.js b/app/imports/api/docs/Docs.js index cb8aeb4e..6300c896 100644 --- a/app/imports/api/docs/Docs.js +++ b/app/imports/api/docs/Docs.js @@ -3,14 +3,14 @@ import { Mongo } from 'meteor/mongo'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; -import { softRemove } from '/imports/api/parenting/softRemove.js'; +import { softRemove } from '/imports/api/parenting/softRemove'; import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema.js'; import { storedIconsSchema } from '/imports/api/icons/Icons.js'; import '/imports/api/library/methods/index.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; -import { restore } from '/imports/api/parenting/softRemove.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; -import { getAncestry } from '/imports/api/parenting/parenting.js'; +import { restore } from '/imports/api/parenting/softRemove'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; +import { getAncestry } from '/imports/api/parenting/parentingFunctions'; const Docs = new Mongo.Collection('docs'); @@ -184,10 +184,7 @@ const insertDoc = new ValidatedMethod({ } const docId = Docs.insert(doc); - reorderDocs({ - collection: Docs, - ancestorId: 'root', - }); + rebuildNestedSets(Docs, 'root'); return docId; }, }); @@ -231,10 +228,7 @@ const updateDoc = new ValidatedMethod({ if (pathString === 'name' || pathString === 'urlName') { rebuildDocAncestors(_id); } - reorderDocs({ - collection: Docs, - ancestorId: 'root', - }); + rebuildNestedSets(Docs, 'root'); return updates; }, }); @@ -284,10 +278,7 @@ const softRemoveDoc = new ValidatedMethod({ run({ _id }) { assertDocsEditPermission(this.userId); softRemove({ _id, collection: Docs }); - reorderDocs({ - collection: Docs, - ancestorId: 'root', - }); + rebuildNestedSets(Docs, 'root'); } }); @@ -304,10 +295,7 @@ const restoreDoc = new ValidatedMethod({ run({ _id }) { assertDocsEditPermission(this.userId); restore({ _id, collection: Docs }); - reorderDocs({ - collection: Docs, - ancestorId: 'root', - }); + rebuildNestedSets(Docs, 'root'); } }); diff --git a/app/imports/api/engine/actions/ActionContext.js b/app/imports/api/engine/actions/ActionContext.ts similarity index 96% rename from app/imports/api/engine/actions/ActionContext.js rename to app/imports/api/engine/actions/ActionContext.ts index 9c5e2e50..d7e1311a 100644 --- a/app/imports/api/engine/actions/ActionContext.js +++ b/app/imports/api/engine/actions/ActionContext.ts @@ -4,7 +4,7 @@ import { } from '/imports/api/engine/loadCreatures.js'; import { groupBy, remove } from 'lodash'; -export default class ActionContext{ +export default class ActionContext { constructor(creatureId, targetIds = [], method) { // Get the creature this.creature = getCreature(creatureId) @@ -64,7 +64,7 @@ export default class ActionContext{ } } addLog(content) { - if (content.name || content.value){ + if (content.name || content.value) { this.log.content.push(content); } } diff --git a/app/imports/api/engine/actions/applyProperty.js b/app/imports/api/engine/actions/applyProperty.js deleted file mode 100644 index b8e809d8..00000000 --- a/app/imports/api/engine/actions/applyProperty.js +++ /dev/null @@ -1,35 +0,0 @@ -import action from './applyPropertyByType/applyAction.js'; -import ammo from './applyPropertyByType/applyItemAsAmmo.js' -import adjustment from './applyPropertyByType/applyAdjustment.js'; -import branch from './applyPropertyByType/applyBranch.js'; -import buff from './applyPropertyByType/applyBuff.js'; -import buffRemover from './applyPropertyByType/applyBuffRemover.js'; -import damage from './applyPropertyByType/applyDamage.js'; -import folder from './applyPropertyByType/applyFolder.js'; -import note from './applyPropertyByType/applyNote.js'; -import roll from './applyPropertyByType/applyRoll.js'; -import savingThrow from './applyPropertyByType/applySavingThrow.js'; -import toggle from './applyPropertyByType/applyToggle.js'; - -const applyPropertyByType = { - action, - ammo, - adjustment, - branch, - buff, - buffRemover, - damage, - folder, - note, - propertySlot: folder, - roll, - savingThrow, - spell: action, - toggle, -}; - -export default function applyProperty(node, actionContext, ...rest) { - if (node.node.deactivatedByToggle) return; - actionContext.scope[`#${node.node.type}`] = node.node; - applyPropertyByType[node.node.type]?.(node, actionContext, ...rest); -} diff --git a/app/imports/api/engine/actions/applyProperty.ts b/app/imports/api/engine/actions/applyProperty.ts new file mode 100644 index 00000000..eeb010e6 --- /dev/null +++ b/app/imports/api/engine/actions/applyProperty.ts @@ -0,0 +1,38 @@ +import action from './applyPropertyByType/applyAction'; +import ammo from './applyPropertyByType/applyItemAsAmmo' +import adjustment from './applyPropertyByType/applyAdjustment'; +import branch from './applyPropertyByType/applyBranch'; +import buff from './applyPropertyByType/applyBuff'; +import buffRemover from './applyPropertyByType/applyBuffRemover'; +import damage from './applyPropertyByType/applyDamage'; +import folder from './applyPropertyByType/applyFolder'; +import note from './applyPropertyByType/applyNote'; +import roll from './applyPropertyByType/applyRoll'; +import savingThrow from './applyPropertyByType/applySavingThrow'; +import toggle from './applyPropertyByType/applyToggle'; +import ActionContext from '/imports/api/engine/actions/ActionContext'; +import { TreeNode } from '/imports/api/parenting/parentingFunctions'; +import { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; + +const applyPropertyByType = { + action, + ammo, + adjustment, + branch, + buff, + buffRemover, + damage, + folder, + note, + propertySlot: folder, + roll, + savingThrow, + spell: action, + toggle, +}; + +export default function applyProperty(node: TreeNode, actionContext: ActionContext, ...rest) { + if (node.doc.deactivatedByToggle) return; + actionContext.scope[`#${node.doc.type}`] = node.doc; + applyPropertyByType[node.doc.type]?.(node, actionContext, ...rest); +} diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js b/app/imports/api/engine/actions/applyPropertyByType/applyAction.ts similarity index 83% rename from app/imports/api/engine/actions/applyPropertyByType/applyAction.js rename to app/imports/api/engine/actions/applyPropertyByType/applyAction.ts index b44c1b44..91041ca7 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyAction.ts @@ -1,22 +1,31 @@ import recalculateInlineCalculations from './shared/recalculateInlineCalculations.js'; import recalculateCalculation from './shared/recalculateCalculation.js'; import rollDice from '/imports/parser/rollDice.js'; -import applyProperty from '../applyProperty.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import applyProperty from '../applyProperty'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js'; import numberToSignedString from '/imports/api/utility/numberToSignedString.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; import { resetProperties } from '/imports/api/creature/creatures/methods/restCreature.js'; +import { TreeNode } from '/imports/api/parenting/parentingFunctions'; +import { Action } from '/imports/api/properties/Actions'; +import { LogContent } from '/imports/api/creature/log/LogContentSchema.js'; +import { Item } from '/imports/api/properties/Items.js'; -export default function applyAction(node, actionContext) { +interface Ammo extends Item { + type: 'ammo' + adjustment: number +} + +export default function applyAction(node: TreeNode, actionContext) { applyNodeTriggers(node, 'before', actionContext); - const prop = node.node; + const prop = node.doc; if (prop.target === 'self') actionContext.targets = [actionContext.creature]; const targets = actionContext.targets; // Log the name and summary - let content = { name: prop.name }; + const content: LogContent = { name: prop.name, }; if (prop.summary?.text) { recalculateInlineCalculations(prop.summary, actionContext); content.value = prop.summary.value; @@ -27,7 +36,7 @@ export default function applyAction(node, actionContext) { const failed = spendResources(prop, actionContext); if (failed) return; - const attack = prop.attackRoll || prop.attackRollBonus; + const attack = prop.attackRoll; // Attack if there is an attack roll if (attack && attack.calculation) { @@ -59,7 +68,7 @@ function applyAttackWithoutTarget({ attack, actionContext }) { recalculateCalculation(attack, actionContext); const scope = actionContext.scope; - let { + const { resultPrefix, result, criticalHit, @@ -96,7 +105,7 @@ function applyAttackToTarget({ attack, target, actionContext }) { recalculateCalculation(attack, actionContext); - let { + const { resultPrefix, result, criticalHit, @@ -176,7 +185,7 @@ function applyCrits(value, scope) { scopeCrit = scopeCrit.value; } const criticalHitTarget = scopeCrit || 20; - let criticalHit = value >= criticalHitTarget; + const criticalHit = value >= criticalHitTarget; let criticalMiss; if (criticalHit) { scope['~criticalHit'] = { value: true }; @@ -189,9 +198,9 @@ function applyCrits(value, scope) { return { criticalHit, criticalMiss }; } -function spendResources(prop, actionContext) { +function spendResources(prop: Action, actionContext) { // Check Uses - if (prop.usesLeft <= 0) { + if (!prop.usesLeft || prop.usesLeft <= 0) { if (!prop.silent) actionContext.addLog({ name: 'Error', value: `${prop.name || 'action'} does not have enough uses left`, @@ -207,42 +216,45 @@ function spendResources(prop, actionContext) { return true; } // Items - let spendLog = []; - let gainLog = []; - const ammoToApply = []; + const spendLog: string[] = []; + const gainLog: string[] = []; + const ammoToApply: TreeNode[] = []; try { prop.resources.itemsConsumed.forEach(itemConsumed => { recalculateCalculation(itemConsumed.quantity, actionContext); if (!itemConsumed.itemId) { throw 'No ammo was selected for this prop'; } - let item = CreatureProperties.findOne(itemConsumed.itemId); - if (!item || item.ancestors[0].id !== prop.ancestors[0].id) { + const item = CreatureProperties.findOne(itemConsumed.itemId) as Item; + if (!item || item.root.id !== prop.root.id) { throw 'The prop\'s ammo was not found on the creature'; } + if ( !itemConsumed?.quantity?.value || - !isFinite(itemConsumed.quantity.value) + !isFinite(+itemConsumed.quantity.value) ) return; + const quantityConsumed = +itemConsumed.quantity.value; + let logName = item.name; - if (itemConsumed.quantity.value > 1 || itemConsumed.quantity.value < -1) { + if (quantityConsumed > 1 || quantityConsumed < -1) { logName = item.plural || logName; } - if (itemConsumed.quantity.value > 0) { - spendLog.push(logName + ': ' + itemConsumed.quantity.value); - } else if (itemConsumed.quantity.value < 0) { - gainLog.push(logName + ': ' + -itemConsumed.quantity.value); + if (quantityConsumed > 0) { + spendLog.push(logName + ': ' + quantityConsumed); + } else if (quantityConsumed < 0) { + gainLog.push(logName + ': ' + -quantityConsumed); } // So long as the item isn't an ancestor of the current prop apply it // If it was an ancestor this would be an infinite loop if (!hasAncestorRelationship(item, prop)) { ammoToApply.push({ - node: { + doc: { ...item, // Use ammo pseudo-type type: 'ammo', // Store the adjustment to be applied - adjustment: itemConsumed.quantity.value, + adjustment: quantityConsumed, }, children: [] }); @@ -263,6 +275,7 @@ function spendResources(prop, actionContext) { CreatureProperties.update(prop._id, { $inc: { usesUsed: 1 } }, { + //@ts-expect-error no typings for collection 2 selector selector: prop }); if (!prop.silent) actionContext.addLog({ @@ -277,8 +290,9 @@ function spendResources(prop, actionContext) { recalculateCalculation(attConsumed.quantity, actionContext); if (!attConsumed.quantity?.value) return; + const quantityConsumed = +attConsumed.quantity.value; if (!attConsumed.variableName) return; - let stat = actionContext.scope[attConsumed.variableName]; + const stat = actionContext.scope[attConsumed.variableName]; if (!stat) { spendLog.push(attConsumed.variableName + ': ' + ' not found'); return; @@ -289,10 +303,10 @@ function spendResources(prop, actionContext) { value: attConsumed.quantity.value, actionContext, }); - if (attConsumed.quantity.value > 0) { - spendLog.push(stat.name + ': ' + attConsumed.quantity.value); - } else if (attConsumed.quantity.value < 0) { - gainLog.push(stat.name + ': ' + -attConsumed.quantity.value); + if (quantityConsumed > 0) { + spendLog.push(stat.name + ': ' + quantityConsumed); + } else if (quantityConsumed < 0) { + gainLog.push(stat.name + ': ' + -quantityConsumed); } }); diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js b/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js index 5ca17972..756b244c 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js @@ -1,7 +1,7 @@ import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; import recalculateCalculation from './shared/recalculateCalculation.js'; import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; export default function applyAdjustment(node, actionContext) { applyNodeTriggers(node, 'before', actionContext); diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js b/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js index 8888c461..b336c929 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js @@ -1,8 +1,8 @@ -import applyProperty from '../applyProperty.js'; +import applyProperty from '../applyProperty'; import recalculateCalculation from './shared/recalculateCalculation.js'; import rollDice from '/imports/parser/rollDice.js'; import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; export default function applyBranch(node, actionContext) { applyNodeTriggers(node, 'before', actionContext); diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js b/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js index 49adf4eb..56ffb109 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js @@ -1,9 +1,8 @@ import { setLineageOfDocs, renewDocIds -} from '/imports/api/parenting/parenting.js'; -import { setDocToLastOrder } from '/imports/api/parenting/order.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +} from '/imports/api/parenting/parentingFunctions'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import computedSchemas from '/imports/api/properties/computedPropertySchemasIndex.js'; import applyFnToKey from '/imports/api/engine/computation/utility/applyFnToKey.js'; import { get } from 'lodash'; @@ -12,7 +11,7 @@ import symbol from '/imports/parser/parseTree/symbol.js'; import logErrors from './shared/logErrors.js'; import { insertCreatureLog } from '/imports/api/creature/log/CreatureLogs.js'; import cyrb53 from '/imports/api/engine/computation/utility/cyrb53.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; import INLINE_CALCULATION_REGEX from '/imports/constants/INLINE_CALCULTION_REGEX.js'; import recalculateInlineCalculations from './shared/recalculateInlineCalculations.js'; @@ -92,10 +91,12 @@ function copyNodeListToTarget(propList, target, oldParent) { renewDocIds({ docArray: propList, }); + /* setDocToLastOrder({ collection: CreatureProperties, doc: propList[0], }); + */ CreatureProperties.batchInsert(propList); } diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js b/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js index a9915bdf..d73954cc 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js @@ -1,9 +1,9 @@ import { findLast, difference, intersection, filter } from 'lodash'; -import applyProperty from '../applyProperty.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import applyProperty from '../applyProperty'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; import { getProperyAncestors, getPropertiesOfType } from '/imports/api/engine/loadCreatures.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; -import { softRemove } from '/imports/api/parenting/softRemove.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; +import { softRemove } from '/imports/api/parenting/softRemove'; import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags.js'; import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js b/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js index 3cbe225c..d2e27a05 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js @@ -8,7 +8,7 @@ import { damagePropertyWork } from '/imports/api/creature/creatureProperties/met import { getPropertiesOfType } from '/imports/api/engine/loadCreatures.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags.js'; import applySavingThrow from '/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js'; diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js b/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js index ea216685..c97c22dc 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js @@ -1,5 +1,5 @@ import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; export default function applyFolder(node, actionContext) { // Apply triggers diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyItemAsAmmo.js b/app/imports/api/engine/actions/applyPropertyByType/applyItemAsAmmo.js index 3bc3b24e..d148184c 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyItemAsAmmo.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyItemAsAmmo.js @@ -1,7 +1,7 @@ import { getPropertyDecendants } from '/imports/api/engine/loadCreatures.js'; -import applyProperty from '../applyProperty.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; -import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js'; +import applyProperty from '../applyProperty'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; +import { docsToForest as nodeArrayToTree } from '/imports/api/parenting/parentingFunctions'; import { adjustQuantityWork } from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js'; export default function applyItemAsAmmo(node, actionContext) { diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyNote.js b/app/imports/api/engine/actions/applyPropertyByType/applyNote.js index 332d93dc..27d320f0 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyNote.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyNote.js @@ -1,6 +1,6 @@ import recalculateInlineCalculations from './shared/recalculateInlineCalculations.js'; import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; export default function applyNote(node, actionContext) { applyNodeTriggers(node, 'before', actionContext); diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js b/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js index d3b7bf12..f24d5dcc 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js @@ -2,7 +2,7 @@ import applyChildren from '/imports/api/engine/actions/applyPropertyByType/share import logErrors from './shared/logErrors.js'; import applyEffectsToCalculationParseNode from '/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js'; import resolve, { toString } from '/imports/parser/resolve.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; export default function applyRoll(node, actionContext) { applyNodeTriggers(node, 'before', actionContext); diff --git a/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js b/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js index ae2f878e..1c5d4cec 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js @@ -1,9 +1,9 @@ import rollDice from '/imports/parser/rollDice.js'; import recalculateCalculation from './shared/recalculateCalculation.js'; -import applyProperty from '../applyProperty.js'; +import applyProperty from '../applyProperty'; import numberToSignedString from '/imports/api/utility/numberToSignedString.js'; import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; import { applyUnresolvedEffects } from '/imports/api/engine/actions/doCheck.js'; export default function applySavingThrow(node, actionContext) { diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js b/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js index 47ec3e08..a73831c0 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js @@ -1,5 +1,5 @@ import recalculateCalculation from './shared/recalculateCalculation.js'; -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js'; export default function applyToggle(node, actionContext) { diff --git a/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js b/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js index 9c5c0cbd..0ec454db 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js +++ b/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js @@ -1,5 +1,5 @@ -import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js'; -import applyProperty from '/imports/api/engine/actions/applyProperty.js'; +import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; +import applyProperty from '/imports/api/engine/actions/applyProperty'; export default function applyChildren(node, actionContext) { applyNodeTriggers(node, 'after', actionContext); diff --git a/app/imports/api/engine/actions/applyTriggers.testFn.js b/app/imports/api/engine/actions/applyTriggers.testFn.js index f2955afb..9bec8b5f 100644 --- a/app/imports/api/engine/actions/applyTriggers.testFn.js +++ b/app/imports/api/engine/actions/applyTriggers.testFn.js @@ -1,4 +1,4 @@ -import { triggerMatchTags } from '/imports/api/engine/actions/applyTriggers.js'; +import { triggerMatchTags } from '/imports/api/engine/actions/applyTriggers'; import clean from '/imports/api/engine/computation/utility/cleanProp.testFn.js'; import { assert } from 'chai'; diff --git a/app/imports/api/engine/actions/applyTriggers.js b/app/imports/api/engine/actions/applyTriggers.ts similarity index 93% rename from app/imports/api/engine/actions/applyTriggers.js rename to app/imports/api/engine/actions/applyTriggers.ts index cbaf2108..03c254de 100644 --- a/app/imports/api/engine/actions/applyTriggers.js +++ b/app/imports/api/engine/actions/applyTriggers.ts @@ -1,13 +1,13 @@ import recalculateCalculation from '/imports/api/engine/actions/applyPropertyByType/shared/recalculateCalculation.js'; import recalculateInlineCalculations from '/imports/api/engine/actions/applyPropertyByType/shared/recalculateInlineCalculations.js'; import { getPropertyDecendants } from '/imports/api/engine/loadCreatures.js'; -import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js'; -import applyProperty from '/imports/api/engine/actions/applyProperty.js'; +import { TreeNode, docsToForest as nodeArrayToTree } from '/imports/api/parenting/parentingFunctions'; +import applyProperty from '/imports/api/engine/actions/applyProperty'; import { difference, intersection } from 'lodash'; import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags.js'; -export function applyNodeTriggers(node, timing, actionContext) { - const prop = node.node; +export function applyNodeTriggers(node: TreeNode, timing, actionContext) { + const prop = node.doc; const type = prop.type; const triggers = actionContext.triggers?.doActionProperty?.[type]?.[timing]; if (triggers) { diff --git a/app/imports/api/engine/actions/doAction.js b/app/imports/api/engine/actions/doAction.js index 57c7beac..a25c5310 100644 --- a/app/imports/api/engine/actions/doAction.js +++ b/app/imports/api/engine/actions/doAction.js @@ -2,14 +2,14 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; -import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js'; +import { docsToForest } from '/imports/api/parenting/parentingFunctions'; import { getProperyAncestors, getPropertyDecendants } from '/imports/api/engine/loadCreatures.js'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; -import applyProperty from './applyProperty.js'; -import ActionContext from '/imports/api/engine/actions/ActionContext.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; +import applyProperty from './applyProperty'; +import ActionContext from '/imports/api/engine/actions/ActionContext'; const doAction = new ValidatedMethod({ name: 'creatureProperties.doAction', @@ -38,8 +38,9 @@ const doAction = new ValidatedMethod({ }, run({ actionId, targetIds = [], scope }) { // Get action context - let action = CreatureProperties.findOne(actionId); - const creatureId = action.ancestors[0].id; + const action = CreatureProperties.findOne(actionId); + if (!action) throw new Meteor.Error('not-found', 'The action was not found'); + const creatureId = action.root.id; const actionContext = new ActionContext(creatureId, targetIds, this); // Check permissions @@ -74,7 +75,7 @@ export function doActionWork({ }) { // get the docs const ancestorScope = getAncestorScope(ancestors); - const propertyForest = nodeArrayToTree(properties); + const propertyForest = docsToForest(properties); if (propertyForest.length !== 1) { throw new Meteor.Error(`The action has ${propertyForest.length} top level properties, expected 1`); } @@ -92,7 +93,7 @@ export function doActionWork({ // Assumes ancestors are in tree order already function getAncestorScope(ancestors) { - let scope = {}; + const scope = {}; ancestors.forEach(prop => { scope[`#${prop.type}`] = prop; }); diff --git a/app/imports/api/engine/actions/doAction.test.js b/app/imports/api/engine/actions/doAction.test.js index b9fdfa23..9e5b7c37 100644 --- a/app/imports/api/engine/actions/doAction.test.js +++ b/app/imports/api/engine/actions/doAction.test.js @@ -3,7 +3,7 @@ import '/imports/api/simpleSchemaConfig.js'; import applyTriggers from '/imports/api/engine/actions/applyTriggers.testFn.js'; import { doActionWork } from './doAction.js'; import { CreatureLogSchema } from '/imports/api/creature/log/CreatureLogs.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; function cleanProp(prop) { diff --git a/app/imports/api/engine/actions/doCastSpell.js b/app/imports/api/engine/actions/doCastSpell.js index 4ea03630..2d2da615 100644 --- a/app/imports/api/engine/actions/doCastSpell.js +++ b/app/imports/api/engine/actions/doCastSpell.js @@ -5,11 +5,11 @@ import Creatures from '/imports/api/creature/creatures/Creatures.js'; import { getProperyAncestors, getPropertyDecendants } from '/imports/api/engine/loadCreatures.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js'; import { doActionWork } from '/imports/api/engine/actions/doAction.js'; -import ActionContext from '/imports/api/engine/actions/ActionContext.js'; +import ActionContext from '/imports/api/engine/actions/ActionContext'; const doAction = new ValidatedMethod({ name: 'creatureProperties.doCastSpell', diff --git a/app/imports/api/engine/actions/doCheck.js b/app/imports/api/engine/actions/doCheck.js index 452c32eb..56c6e2ea 100644 --- a/app/imports/api/engine/actions/doCheck.js +++ b/app/imports/api/engine/actions/doCheck.js @@ -1,12 +1,12 @@ import SimpleSchema from 'simpl-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; import rollDice from '/imports/parser/rollDice.js'; import numberToSignedString from '/imports/api/utility/numberToSignedString.js'; -import { applyTriggers } from '/imports/api/engine/actions/applyTriggers.js'; -import ActionContext from '/imports/api/engine/actions/ActionContext.js'; +import { applyTriggers } from '/imports/api/engine/actions/applyTriggers'; +import ActionContext from '/imports/api/engine/actions/ActionContext'; import evaluateCalculation from '/imports/api/engine/computation/utility/evaluateCalculation.js'; const doCheck = new ValidatedMethod({ diff --git a/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js b/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.ts similarity index 63% rename from app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js rename to app/imports/api/engine/computation/buildComputation/computeInactiveStatus.ts index 982f1c60..6dd96867 100644 --- a/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js +++ b/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.ts @@ -1,7 +1,10 @@ +import { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; import walkDown from '/imports/api/engine/computation/utility/walkdown.js'; +import { TreeNode } from '/imports/api/parenting/parentingFunctions'; +import { isSpell } from '/imports/api/properties/Spells'; -export default function computeInactiveStatus(node) { - const prop = node.node; +export default function computeInactiveStatus(node: TreeNode): void { + const prop = node.doc; if (!isActive(prop)) { // Mark prop inactive due to self prop.inactive = true; @@ -16,16 +19,16 @@ export default function computeInactiveStatus(node) { } } -function isActive(prop) { +function isActive(prop: CreatureProperty): boolean { if (prop.disabled) return false; - switch (prop.type) { - // Unprepared spells are inactive - case 'spell': return !!prop.prepared || !!prop.alwaysPrepared; - default: return true; + if (isSpell(prop)) { + return !!prop.prepared || !!prop.alwaysPrepared; + } else { + return true; } } -function childrenActive(prop) { +function childrenActive(prop): boolean { // Children of disabled properties are always inactive if (prop.disabled) return false; switch (prop.type) { diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js index e9dbb625..776d0db5 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.js @@ -1,13 +1,13 @@ -import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js'; +import { docsToForest as nodeArrayToTree } from '/imports/api/parenting/parentingFunctions'; import { DenormalisedOnlyCreaturePropertySchema as denormSchema } - from '/imports/api/creature/creatureProperties/CreatureProperties.js'; + from '/imports/api/creature/creatureProperties/CreatureProperties'; import { getProperties, getCreature, getVariables } from '/imports/api/engine/loadCreatures.js'; import computedOnlySchemas from '/imports/api/properties/computedOnlyPropertySchemasIndex.js'; import computedSchemas from '/imports/api/properties/computedPropertySchemasIndex.js'; import linkInventory from './buildComputation/linkInventory.js'; import walkDown from './utility/walkdown.js'; import parseCalculationFields from './buildComputation/parseCalculationFields.js'; -import computeInactiveStatus from './buildComputation/computeInactiveStatus.js'; +import computeInactiveStatus from './buildComputation/computeInactiveStatus'; import computeToggleDependencies from './buildComputation/computeToggleDependencies.js'; import linkCalculationDependencies from './buildComputation/linkCalculationDependencies.js'; import linkTypeDependencies from './buildComputation/linkTypeDependencies.js'; diff --git a/app/imports/api/engine/computation/buildCreatureComputation.test.js b/app/imports/api/engine/computation/buildCreatureComputation.test.js index 33b3830b..c77f6712 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.test.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.test.js @@ -1,7 +1,7 @@ import '/imports/api/simpleSchemaConfig.js'; import { buildComputationFromProps } from './buildCreatureComputation.js'; import { assert } from 'chai'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import computeInactiveStatus from './buildComputation/tests/computeInactiveStatus.testFn.js'; import computeSlotQuantityFilled from './buildComputation/tests/computeSlotQuantityFilled.testFn.js'; import computeToggleDependencies from './buildComputation/tests/computeToggleDependencies.testFn.js'; @@ -9,8 +9,8 @@ import linkCalculationDependencies from './buildComputation/tests/linkCalculatio import linkInventory from './buildComputation/tests/linkInventory.testFn.js'; import linkTypeDependencies from './buildComputation/tests/linkTypeDependencies.testFn.js'; -describe('buildComputation', function(){ - it('Builds something at all', function(){ +describe('buildComputation', function () { + it('Builds something at all', function () { let computation = buildComputationFromProps(testProperties); assert.exists(computation); }); @@ -37,7 +37,7 @@ var testProperties = [ }), ]; -function clean(prop){ +function clean(prop) { let schema = CreatureProperties.simpleSchema(prop); return schema.clean(prop); } diff --git a/app/imports/api/engine/computation/computeCreatureComputation.test.js b/app/imports/api/engine/computation/computeCreatureComputation.test.js index f64e6e7f..09876a75 100644 --- a/app/imports/api/engine/computation/computeCreatureComputation.test.js +++ b/app/imports/api/engine/computation/computeCreatureComputation.test.js @@ -1,11 +1,11 @@ import computeCreatureComputation from './computeCreatureComputation.js'; import { buildComputationFromProps } from './buildCreatureComputation.js'; import { assert } from 'chai'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import computeTests from './computeComputation/tests/index.js'; -describe('Compute compuation', function(){ - it('Computes something at all', function(){ +describe('Compute compuation', function () { + it('Computes something at all', function () { let computation = buildComputationFromProps(testProperties); computeCreatureComputation(computation); assert.exists(computation); @@ -28,7 +28,7 @@ var testProperties = [ }), ]; -function clean(prop){ +function clean(prop) { let schema = CreatureProperties.simpleSchema(prop); return schema.clean(prop); } diff --git a/app/imports/api/engine/computation/utility/cleanProp.testFn.js b/app/imports/api/engine/computation/utility/cleanProp.testFn.js index 1c845150..155fe000 100644 --- a/app/imports/api/engine/computation/utility/cleanProp.testFn.js +++ b/app/imports/api/engine/computation/utility/cleanProp.testFn.js @@ -1,6 +1,6 @@ -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -export default function cleanProp(prop){ +export default function cleanProp(prop) { let schema = CreatureProperties.simpleSchema(prop); return schema.clean(prop); } diff --git a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js index 0548fedd..4a4dadea 100644 --- a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js +++ b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor' import { EJSON } from 'meteor/ejson'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import propertySchemasIndex from '/imports/api/properties/computedOnlyPropertySchemasIndex.js'; export default function writeAlteredProperties(computation) { diff --git a/app/imports/api/engine/loadCreatures.js b/app/imports/api/engine/loadCreatures.js index aa036a37..d831e26b 100644 --- a/app/imports/api/engine/loadCreatures.js +++ b/app/imports/api/engine/loadCreatures.js @@ -1,11 +1,12 @@ import { debounce } from 'lodash'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import computeCreature from './computeCreature'; const COMPUTE_DEBOUNCE_TIME = 100; // ms export const loadedCreatures = new Map(); // creatureId => {creature, properties, etc.} +// TODO: migrate to nested sets export function loadCreature(creatureId, subscription) { if (!creatureId) throw 'creatureId is required'; @@ -43,7 +44,7 @@ export function getSingleProperty(creatureId, propertyId) { const prop = CreatureProperties.findOne({ _id: propertyId, 'ancestors.id': creatureId, - 'removed': {$ne: true}, + 'removed': { $ne: true }, }, { sort: { order: 1 }, }); @@ -61,7 +62,7 @@ export function getProperties(creatureId) { // console.time(`Cache miss on creature properties: ${creatureId}`) const props = CreatureProperties.find({ 'ancestors.id': creatureId, - 'removed': {$ne: true}, + 'removed': { $ne: true }, }, { sort: { order: 1 }, }).fetch(); @@ -73,7 +74,7 @@ export function getPropertiesOfType(creatureId, propType) { if (loadedCreatures.has(creatureId)) { const creature = loadedCreatures.get(creatureId); const props = [] - for (const prop of creature.properties.values()){ + for (const prop of creature.properties.values()) { if (prop.type === propType) { props.push(prop); } @@ -97,7 +98,7 @@ export function getCreature(creatureId) { if (loadedCreatures.has(creatureId)) { const loadedCreature = loadedCreatures.get(creatureId); const creature = loadedCreature.creature; - if (creature) { + if (creature) { const cloneCreature = EJSON.clone(creature); return cloneCreature; } @@ -118,7 +119,7 @@ export function getVariables(creatureId) { } } // console.time(`Cache miss on variables: ${creatureId}`); - const variables = CreatureVariables.findOne({_creatureId: creatureId}); + const variables = CreatureVariables.findOne({ _creatureId: creatureId }); // console.timeEnd(`Cache miss on variables: ${creatureId}`); return variables; } @@ -148,7 +149,7 @@ export function getProperyAncestors(creatureId, propertyId) { // Fetch from database return CreatureProperties.find({ _id: { $in: ancestorIds }, - removed: {$ne: true}, + removed: { $ne: true }, }, { sort: { order: 1 }, }).fetch(); @@ -164,7 +165,7 @@ export function getPropertyDecendants(creatureId, propertyId) { if (loadedCreatures.has(creatureId)) { const creature = loadedCreatures.get(creatureId); const props = []; - for(const prop of creature.properties.values()){ + for (const prop of creature.properties.values()) { if (prop.ancestors[expectedAncestorPostition]?.id === propertyId) { props.push(prop); } @@ -216,7 +217,7 @@ class LoadedCreature { compute(); }, }); - + // Observe the creature itself self.creatureObserver = Creatures.find({ _id: creatureId, @@ -239,7 +240,7 @@ class LoadedCreature { self.variablesObserver = CreatureVariables.find({ _creatureId: creatureId, }, { - fields: { _creatureId: 0}, + fields: { _creatureId: 0 }, }).observeChanges({ added(id, fields) { fields._id = id; diff --git a/app/imports/api/library/LibraryNodes.js b/app/imports/api/library/LibraryNodes.js index 39264fb6..9cdcfb56 100644 --- a/app/imports/api/library/LibraryNodes.js +++ b/app/imports/api/library/LibraryNodes.js @@ -4,19 +4,19 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import SimpleSchema from 'simpl-schema'; import ColorSchema from '/imports/api/properties/subSchemas/ColorSchema.js'; -import ChildSchema, { RefSchema } from '/imports/api/parenting/ChildSchema.js'; +import ChildSchema, { RefSchema } from '/imports/api/parenting/ChildSchema'; import propertySchemasIndex from '/imports/api/properties/propertySchemasIndex.js'; import Libraries from '/imports/api/library/Libraries.js'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; -import { softRemove } from '/imports/api/parenting/softRemove.js'; +import { softRemove } from '/imports/api/parenting/softRemove'; import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema.js'; import { storedIconsSchema } from '/imports/api/icons/Icons.js'; import '/imports/api/library/methods/index.js'; import { updateReferenceNodeWork } from '/imports/api/library/methods/updateReferenceNode.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; -import { restore } from '/imports/api/parenting/softRemove.js'; -import { getAncestry } from '/imports/api/parenting/parenting.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; +import { restore } from '/imports/api/parenting/softRemove'; +import { getAncestry } from '/imports/api/parenting/parentingFunctions'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; let LibraryNodes = new Mongo.Collection('libraryNodes'); @@ -178,10 +178,7 @@ const insertNode = new ValidatedMethod({ } // Tree structure changed by insert, reorder the tree - reorderDocs({ - collection: LibraryNodes, - ancestorId: root._id, - }); + rebuildNestedSets(LibraryNodes, root._id); // Return the id of the inserted node return nodeId; diff --git a/app/imports/api/library/methods/copyLibraryNodeTo.js b/app/imports/api/library/methods/copyLibraryNodeTo.js index ea9ce06f..cda54150 100644 --- a/app/imports/api/library/methods/copyLibraryNodeTo.js +++ b/app/imports/api/library/methods/copyLibraryNodeTo.js @@ -1,7 +1,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import SimpleSchema from 'simpl-schema'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; +import { RefSchema } from '/imports/api/parenting/ChildSchema'; import LibraryNodes from '/imports/api/library/LibraryNodes.js'; import { assertDocCopyPermission, @@ -10,9 +10,9 @@ import { import { setLineageOfDocs, renewDocIds -} from '/imports/api/parenting/parenting.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; -import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; +} from '/imports/api/parenting/parentingFunctions'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; +import { fetchDocByRef } from '/imports/api/parenting/parentingFunctions'; var snackbar; if (Meteor.isClient) { @@ -87,10 +87,9 @@ const copyLibraryNodeTo = new ValidatedMethod({ LibraryNodes.batchInsert(nodes); // Tree structure changed by inserts, reorder the tree - reorderDocs({ - collection: LibraryNodes, - ancestorId: parent.collection === 'libraries' ? parent.id : parentDoc.ancestors[0].id, - }); + // TODO: rebuild tree nested sets + + rebuildNestedSets(LibraryNodes, parentDoc.root.id); }, }); diff --git a/app/imports/api/library/methods/duplicateLibraryNode.js b/app/imports/api/library/methods/duplicateLibraryNode.js index eef9f10c..88a6e42b 100644 --- a/app/imports/api/library/methods/duplicateLibraryNode.js +++ b/app/imports/api/library/methods/duplicateLibraryNode.js @@ -6,8 +6,8 @@ import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions import { setLineageOfDocs, renewDocIds -} from '/imports/api/parenting/parenting.js'; -import { reorderDocs } from '/imports/api/parenting/order.js'; +} from '/imports/api/parenting/parentingFunctions'; +import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; var snackbar; if (Meteor.isClient) { diff --git a/app/imports/api/library/methods/updateReferenceNode.js b/app/imports/api/library/methods/updateReferenceNode.js index aa2a5407..440ff59e 100644 --- a/app/imports/api/library/methods/updateReferenceNode.js +++ b/app/imports/api/library/methods/updateReferenceNode.js @@ -6,7 +6,7 @@ import { assertDocEditPermission, assertViewPermission, } from '/imports/api/sharing/sharingPermissions.js'; -import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; +import { fetchDocByRef } from '/imports/api/parenting/parentingFunctions'; const updateReferenceNode = new ValidatedMethod({ name: 'libraryNodes.updateReferenceNode', diff --git a/app/imports/api/parenting/ChildSchema.ts b/app/imports/api/parenting/ChildSchema.ts index 251128fa..dd5ffb4d 100644 --- a/app/imports/api/parenting/ChildSchema.ts +++ b/app/imports/api/parenting/ChildSchema.ts @@ -14,13 +14,17 @@ const RefSchema = new SimpleSchema({ const ChildSchema = new SimpleSchema({ root: { - type: RefSchema, + type: Object, }, 'root.id': { type: String, regEx: SimpleSchema.RegEx.Id, index: 1, }, + 'root.collection': { + type: String, + max: STORAGE_LIMITS.collectionName, + }, // Parent id of a document in the same collection // Undefined parent id implies the root is the parent parentId: { diff --git a/app/imports/api/parenting/parentingFunctions.test.ts b/app/imports/api/parenting/parentingFunctions.test.ts index 8c4f9104..5e4375cb 100644 --- a/app/imports/api/parenting/parentingFunctions.test.ts +++ b/app/imports/api/parenting/parentingFunctions.test.ts @@ -1,4 +1,4 @@ -import { docsToForest, calculateNestedSetOperations } from '/imports/api/parenting/parentingFunctions' +import { docsToForest, calculateNestedSetOperations, getFilter } from '/imports/api/parenting/parentingFunctions' import { TreeDoc } from '/imports/api/parenting/ChildSchema'; import { assert } from 'chai'; @@ -75,3 +75,97 @@ describe('Parenting with nested sets', function () { ]); }); }); + +describe('Document tree filters can fetch other documents based on their position in the tree', function () { + // Add the docs to a new collection + /** + * Test the following structure + * + * 1 Books 12 + * ┃ + * 2 Programming 11 + * ┏━━━━━━━━┻━━━━━━━━━┓ + * 3 Languages 4 5 Databases 10 + * ┏━━━━━━━┻━━━━━━━┓ + * 6 MongoDB 7 8 dbm 9 + */ + const treeCollection: Mongo.Collection = new Mongo.Collection('treeDocs'); + treeCollection.remove({}); + [ + doc('Books', 1, 12, undefined), + doc('Programming', 2, 11, 'Books'), + doc('Languages', 3, 4, 'Programming'), + doc('Databases', 5, 10, 'Programming'), + doc('MongoDB', 6, 7, 'Databases'), + doc('dbm', 8, 9, 'Databases'), + ].map(doc => { + return treeCollection.insert(doc); + }); + const docs: TreeDoc[] = treeCollection.find({}).fetch(); + + it('Can filter ancestors', async function () { + const ancestorIds: { [id: string]: string[] } = {}; + docs.forEach(doc => { + ancestorIds[doc._id] = treeCollection.find( + getFilter.ancestors(doc) + ).map(doc => doc._id); + }); + assert.isEmpty(ancestorIds['Books'], 'Books has no ancestors'); + assert.sameMembers(ancestorIds['Programming'], ['Books']); + assert.sameMembers(ancestorIds['Languages'], ['Books', 'Programming']); + assert.sameMembers(ancestorIds['Databases'], ['Books', 'Programming']); + assert.sameMembers(ancestorIds['MongoDB'], ['Books', 'Programming', 'Databases']); + assert.sameMembers(ancestorIds['dbm'], ['Books', 'Programming', 'Databases']); + }); + + it('Can filter descendants', async function () { + const descendantIds: { [id: string]: string[] } = {}; + docs.forEach(doc => { + descendantIds[doc._id] = treeCollection.find( + getFilter.descendants(doc) + ).map(doc => doc._id); + }); + assert.isEmpty(descendantIds['MongoDB'], 'MongoDB has no descendants'); + assert.isEmpty(descendantIds['dbm'], 'dbm has no descendants'); + assert.isEmpty(descendantIds['Languages'], 'Languages has no descendants'); + assert.sameMembers(descendantIds['Databases'], ['dbm', 'MongoDB']); + assert.sameMembers(descendantIds['Programming'], ['dbm', 'MongoDB', 'Languages', 'Databases']); + assert.sameMembers(descendantIds['Books'], [ + 'dbm', 'MongoDB', 'Languages', 'Databases', 'Programming' + ]); + }); + + it('Can filter children', async function () { + const childrenIds: { [id: string]: string[] } = {}; + docs.forEach(doc => { + childrenIds[doc._id] = treeCollection.find( + getFilter.children(doc) + ).map(doc => doc._id); + }); + assert.sameMembers(childrenIds['Books'], ['Programming']); + assert.sameMembers(childrenIds['Programming'], ['Languages', 'Databases']); + assert.isEmpty(childrenIds['Languages'], 'Languages has no children'); + assert.sameMembers(childrenIds['Databases'], ['dbm', 'MongoDB']); + assert.isEmpty(childrenIds['MongoDB'], 'MongoDB has no children'); + assert.isEmpty(childrenIds['dbm'], 'dbm has no children'); + }); + + it('Can filter parents', async function () { + const parentIds: { [id: string]: string[] } = {}; + docs.forEach(doc => { + parentIds[doc._id] = treeCollection.find( + getFilter.parent(doc) + ).map(doc => doc._id); + }); + assert.isEmpty(parentIds['Books'], 'Books has no parent'); + assert.sameMembers(parentIds['Programming'], ['Books']); + assert.sameMembers(parentIds['Languages'], ['Programming']); + assert.sameMembers(parentIds['Databases'], ['Programming']); + assert.sameMembers(parentIds['MongoDB'], ['Databases']); + assert.sameMembers(parentIds['dbm'], ['Databases']); + }); +}); + + + + diff --git a/app/imports/api/parenting/parentingFunctions.ts b/app/imports/api/parenting/parentingFunctions.ts index a5a97aa9..c1cd800e 100644 --- a/app/imports/api/parenting/parentingFunctions.ts +++ b/app/imports/api/parenting/parentingFunctions.ts @@ -11,8 +11,8 @@ export function getCollectionByName(name: string): Mongo.Collection { return collection; } -export async function fetchDocByRef(ref: Reference, options?: Mongo.Options) { - const doc = await getCollectionByName(ref.collection).findOneAsync(ref.id, options); +export function fetchDocByRef(ref: Reference, options?: Mongo.Options): Promise { + const doc = getCollectionByName(ref.collection).findOneAsync(ref.id, options); if (!doc) { throw new Meteor.Error('document-not-found', `No document could be found with id: ${ref.id} in ${ref.collection}` @@ -21,7 +21,7 @@ export async function fetchDocByRef(ref: Reference, options?: Mongo.Options { +export interface TreeNode { doc: T, children: TreeNode[] } @@ -271,8 +271,8 @@ export const getFilter = { }, } -export async function fetchParent({ id, collection }) { - return await fetchDocByRef({ id, collection }); +export function fetchParent({ id, collection }) { + return fetchDocByRef({ id, collection }); } /** diff --git a/app/imports/api/properties/Actions.js b/app/imports/api/properties/Actions.ts similarity index 82% rename from app/imports/api/properties/Actions.js rename to app/imports/api/properties/Actions.ts index 163d938d..9b22f221 100644 --- a/app/imports/api/properties/Actions.js +++ b/app/imports/api/properties/Actions.ts @@ -3,11 +3,58 @@ import createPropertySchema from '/imports/api/properties/subSchemas/createPrope import { storedIconsSchema } from '/imports/api/icons/Icons.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX.js'; +import { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; +import { InlineCalculation } from '/imports/api/properties/subSchemas/inlineCalculationField'; +import { CalculatedField } from '/imports/api/properties/subSchemas/computedField'; + +export interface Action extends ActionBase { + type: 'action' +} + +export interface ActionBase extends CreatureProperty { + name?: string + summary?: InlineCalculation + description?: InlineCalculation + actionType: 'action' | 'bonus' | 'attack' | 'reaction' | 'free' | 'long' | 'event' + variableName?: string + target: 'self' | 'singleTarget' | 'multipleTargets' + attackRoll?: CalculatedField + uses?: CalculatedField + usesUsed?: number + reset?: string + silent?: boolean + insufficientResources?: boolean + usesLeft?: number + overridden?: boolean + // Resources + resources: { + itemsConsumed: { + _id: string + tag?: string + itemName?: string + quantity?: CalculatedField + itemId?: string + available?: number + }[] + attributesConsumed: { + _id: string + variableName?: string + quantity?: CalculatedField + available?: number + statName?: string + }[] + conditions?: { + _id: string, + condition?: CalculatedField + conditionNote?: string, + }[] + } +} /* * Actions are things a character can do */ -let ActionSchema = createPropertySchema({ +const ActionSchema = createPropertySchema({ name: { type: String, optional: true, diff --git a/app/imports/api/properties/Items.js b/app/imports/api/properties/Items.ts similarity index 88% rename from app/imports/api/properties/Items.js rename to app/imports/api/properties/Items.ts index b4bb7319..ba5cedc3 100644 --- a/app/imports/api/properties/Items.js +++ b/app/imports/api/properties/Items.ts @@ -1,6 +1,14 @@ import SimpleSchema from 'simpl-schema'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js'; +import { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; + +export interface Item extends CreatureProperty { + type: 'item' + name?: string + plural?: string + quantity: number +} const ItemSchema = createPropertySchema({ name: { diff --git a/app/imports/api/properties/Spells.js b/app/imports/api/properties/Spells.ts similarity index 75% rename from app/imports/api/properties/Spells.js rename to app/imports/api/properties/Spells.ts index 575c9b5e..bb62bd93 100644 --- a/app/imports/api/properties/Spells.js +++ b/app/imports/api/properties/Spells.ts @@ -1,6 +1,30 @@ -import { ActionSchema, ComputedOnlyActionSchema } from '/imports/api/properties/Actions.js'; +import { ActionBase, ActionSchema, ComputedOnlyActionSchema } from '/imports/api/properties/Actions'; import SimpleSchema from 'simpl-schema'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; +import { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; + +export interface Spell extends ActionBase { + name?: string + type: 'spell' + alwaysPrepared?: boolean + prepared?: boolean + castWithoutSpellSlots?: boolean + hasAttackRoll?: boolean + castingTime?: string + range?: string + duration?: string + verbal?: boolean + somatic?: boolean + concentration?: boolean + material?: string + ritual?: boolean + level?: number + school?: string +} + +export function isSpell(prop: CreatureProperty): prop is Spell { + return prop.type === 'spell'; +} const magicSchools = [ 'abjuration', diff --git a/app/imports/api/properties/computedOnlyPropertySchemasIndex.js b/app/imports/api/properties/computedOnlyPropertySchemasIndex.js index 89cb21e4..872249e5 100644 --- a/app/imports/api/properties/computedOnlyPropertySchemasIndex.js +++ b/app/imports/api/properties/computedOnlyPropertySchemasIndex.js @@ -1,5 +1,5 @@ import SimpleSchema from 'simpl-schema'; -import { ComputedOnlyActionSchema } from '/imports/api/properties/Actions.js'; +import { ComputedOnlyActionSchema } from '/imports/api/properties/Actions'; import { ComputedOnlyAdjustmentSchema } from '/imports/api/properties/Adjustments.js'; import { ComputedOnlyAttributeSchema } from '/imports/api/properties/Attributes.js'; import { ComputedOnlyBuffSchema } from '/imports/api/properties/Buffs.js'; @@ -14,7 +14,7 @@ import { ComputedOnlyDamageMultiplierSchema } from '/imports/api/properties/Dama import { ComputedOnlyEffectSchema } from '/imports/api/properties/Effects.js'; import { ComputedOnlyFeatureSchema } from '/imports/api/properties/Features.js'; import { ComputedOnlyFolderSchema } from '/imports/api/properties/Folders.js'; -import { ComputedOnlyItemSchema } from '/imports/api/properties/Items.js'; +import { ComputedOnlyItemSchema } from '/imports/api/properties/Items'; import { ComputedOnlyNoteSchema } from '/imports/api/properties/Notes.js'; import { ComputedOnlyPointBuySchema } from '/imports/api/properties/PointBuys.js'; import { ComputedOnlyProficiencySchema } from '/imports/api/properties/Proficiencies.js'; @@ -23,7 +23,7 @@ import { ComputedOnlyRollSchema } from '/imports/api/properties/Rolls.js'; import { ComputedOnlySavingThrowSchema } from '/imports/api/properties/SavingThrows.js'; import { ComputedOnlySkillSchema } from '/imports/api/properties/Skills.js'; import { ComputedOnlySlotSchema } from '/imports/api/properties/Slots.js'; -import { ComputedOnlySpellSchema } from '/imports/api/properties/Spells.js'; +import { ComputedOnlySpellSchema } from '/imports/api/properties/Spells'; import { ComputedOnlySpellListSchema } from '/imports/api/properties/SpellLists.js'; import { ComputedOnlyToggleSchema } from '/imports/api/properties/Toggles.js'; import { ComputedOnlyTriggerSchema } from '/imports/api/properties/Triggers.js'; diff --git a/app/imports/api/properties/computedPropertySchemasIndex.js b/app/imports/api/properties/computedPropertySchemasIndex.js index b6adaaa2..f3ce169b 100644 --- a/app/imports/api/properties/computedPropertySchemasIndex.js +++ b/app/imports/api/properties/computedPropertySchemasIndex.js @@ -1,5 +1,5 @@ import SimpleSchema from 'simpl-schema'; -import { ComputedActionSchema } from '/imports/api/properties/Actions.js'; +import { ComputedActionSchema } from '/imports/api/properties/Actions'; import { ComputedAdjustmentSchema } from '/imports/api/properties/Adjustments.js'; import { ComputedAttributeSchema } from '/imports/api/properties/Attributes.js'; import { ComputedBuffSchema } from '/imports/api/properties/Buffs.js'; @@ -14,7 +14,7 @@ import { DamageMultiplierSchema } from '/imports/api/properties/DamageMultiplier import { ComputedEffectSchema } from '/imports/api/properties/Effects.js'; import { ComputedFeatureSchema } from '/imports/api/properties/Features.js'; import { ComputedFolderSchema } from '/imports/api/properties/Folders.js'; -import { ComputedItemSchema } from '/imports/api/properties/Items.js'; +import { ComputedItemSchema } from '/imports/api/properties/Items'; import { ComputedNoteSchema } from '/imports/api/properties/Notes.js'; import { ComputedPointBuySchema } from '/imports/api/properties/PointBuys.js'; import { ProficiencySchema } from '/imports/api/properties/Proficiencies.js'; @@ -23,7 +23,7 @@ import { ComputedRollSchema } from '/imports/api/properties/Rolls.js'; import { ComputedSavingThrowSchema } from '/imports/api/properties/SavingThrows.js'; import { ComputedSkillSchema } from '/imports/api/properties/Skills.js'; import { ComputedSlotSchema } from '/imports/api/properties/Slots.js'; -import { ComputedSpellSchema } from '/imports/api/properties/Spells.js'; +import { ComputedSpellSchema } from '/imports/api/properties/Spells'; import { ComputedSpellListSchema } from '/imports/api/properties/SpellLists.js'; import { ComputedToggleSchema } from '/imports/api/properties/Toggles.js'; import { ComputedTriggerSchema } from '/imports/api/properties/Triggers.js'; diff --git a/app/imports/api/properties/propertySchemasIndex.js b/app/imports/api/properties/propertySchemasIndex.js index ed0a3a22..dd02e2da 100644 --- a/app/imports/api/properties/propertySchemasIndex.js +++ b/app/imports/api/properties/propertySchemasIndex.js @@ -1,5 +1,5 @@ import SimpleSchema from 'simpl-schema'; -import { ActionSchema } from '/imports/api/properties/Actions.js'; +import { ActionSchema } from '/imports/api/properties/Actions'; import { AdjustmentSchema } from '/imports/api/properties/Adjustments.js'; import { AttributeSchema } from '/imports/api/properties/Attributes.js'; import { BuffSchema } from '/imports/api/properties/Buffs.js'; @@ -22,11 +22,11 @@ import { SavingThrowSchema } from '/imports/api/properties/SavingThrows.js'; import { SkillSchema } from '/imports/api/properties/Skills.js'; import { SlotSchema } from '/imports/api/properties/Slots.js'; import { SpellListSchema } from '/imports/api/properties/SpellLists.js'; -import { SpellSchema } from '/imports/api/properties/Spells.js'; +import { SpellSchema } from '/imports/api/properties/Spells'; import { ToggleSchema } from '/imports/api/properties/Toggles.js'; import { TriggerSchema } from '/imports/api/properties/Triggers.js'; import { ContainerSchema } from '/imports/api/properties/Containers.js'; -import { ItemSchema } from '/imports/api/properties/Items.js'; +import { ItemSchema } from '/imports/api/properties/Items'; const propertySchemasIndex = { action: ActionSchema, diff --git a/app/imports/api/properties/subSchemas/computedField.js b/app/imports/api/properties/subSchemas/computedField.ts similarity index 84% rename from app/imports/api/properties/subSchemas/computedField.js rename to app/imports/api/properties/subSchemas/computedField.ts index 0d7ad114..5f5c13e0 100644 --- a/app/imports/api/properties/subSchemas/computedField.js +++ b/app/imports/api/properties/subSchemas/computedField.ts @@ -2,9 +2,19 @@ import SimpleSchema from 'simpl-schema'; import ErrorSchema from '/imports/api/properties/subSchemas/ErrorSchema.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; +export interface CalculatedField { + calculation?: string, + value?: string | number, + effectIds?: string[], + parseNode?: any, + parseError?: any, + hash?: number, + errors?: any[], +} + // Get schemas that apply fields directly so they can be gracefully extended // because {type: Schema} fields can't be extended -function fieldToCompute(field){ +function fieldToCompute(field) { const schemaObj = { [`${field}.calculation`]: { type: String, @@ -17,7 +27,7 @@ function fieldToCompute(field){ return new SimpleSchema(schemaObj); } -function computedOnlyField(field){ +function computedOnlyField(field) { const schemaObj = { [`${field}.value`]: { type: SimpleSchema.oneOf(String, Number), @@ -56,7 +66,7 @@ function computedOnlyField(field){ maxCount: STORAGE_LIMITS.errorCount, removeBeforeCompute: true, }, - [`${field}.errors.$`]:{ + [`${field}.errors.$`]: { type: ErrorSchema, }, } @@ -65,9 +75,9 @@ function computedOnlyField(field){ } // We must include parent array and object fields for the schema to be valid -function includeParentFields(field, schemaObj){ +function includeParentFields(field, schemaObj) { const splitField = field.split('.'); - if (splitField.length === 1){ + if (splitField.length === 1) { schemaObj[field] = { type: Object, optional: true, @@ -78,8 +88,8 @@ function includeParentFields(field, schemaObj){ let key = ''; splitField.push(''); splitField.forEach((value, index) => { - if (key){ - if (value === '$'){ + if (key) { + if (value === '$') { schemaObj[key] = { type: Array, optional: true @@ -90,7 +100,7 @@ function includeParentFields(field, schemaObj){ optional: true, }; // the last object is the computed field - if (index === splitField.length - 1){ + if (index === splitField.length - 1) { schemaObj[key].computedField = true; } } @@ -102,7 +112,7 @@ function includeParentFields(field, schemaObj){ // This should rarely be used, since the other two will merge correctly when // uncomputed and computedOnly schemas are merged -function computedField(field){ +function computedField(field) { return computedField(field).extend(computedOnlyField(field)); } diff --git a/app/imports/api/properties/subSchemas/createPropertySchema.js b/app/imports/api/properties/subSchemas/createPropertySchema.js index a866295c..2d2d6b11 100644 --- a/app/imports/api/properties/subSchemas/createPropertySchema.js +++ b/app/imports/api/properties/subSchemas/createPropertySchema.js @@ -1,17 +1,17 @@ import { inlineCalculationFieldToCompute, computedOnlyInlineCalculationField, -} from '/imports/api/properties/subSchemas/inlineCalculationField.js'; +} from '/imports/api/properties/subSchemas/inlineCalculationField'; import { fieldToCompute, computedOnlyField, -} from '/imports/api/properties/subSchemas/computedField.js'; +} from '/imports/api/properties/subSchemas/computedField'; import SimpleSchema from 'simpl-schema'; // Search through the schema for keys whose type is 'fieldToCompute' etc. // replace the type with Object and attach extend the schema with // the required fields to make the computation work -export default function createPropertySchema(definition){ +export default function createPropertySchema(definition) { const computationFields = { inlineCalculationFieldToCompute: [], computedOnlyInlineCalculationField: [], @@ -20,18 +20,18 @@ export default function createPropertySchema(definition){ }; const computedKeys = Object.keys(computationFields); - for (let key in definition){ + for (let key in definition) { const def = definition[key]; - if (computedKeys.includes(def.type)){ + if (computedKeys.includes(def.type)) { computationFields[def.type].push(key); applyDefaultCalculationValue(definition, key); def.type = Object; - if (!def.optional){ + if (!def.optional) { console.warn( `computed field: '${key}' of '${def.type}' is expected to be optional` ); } - if (def.removeBeforeCompute){ + if (def.removeBeforeCompute) { console.warn( `computed field: '${key}' of '${def.type}' should not be removed before computation` ) @@ -58,12 +58,12 @@ export default function createPropertySchema(definition){ return schema } -function applyDefaultCalculationValue(definition, key){ +function applyDefaultCalculationValue(definition, key) { const def = definition[key]; if ( def.type === 'computedOnlyField' || def.type === 'computedOnlyInlineCalculationField' - ){ + ) { // don't apply defaults to computed only fields // because it would add the calculation field which should only appear // on the fields to compute @@ -72,12 +72,12 @@ function applyDefaultCalculationValue(definition, key){ let defaultValue = def.defaultValue; if (!defaultValue) return; let calcField; - if (def.type === 'fieldToCompute'){ + if (def.type === 'fieldToCompute') { calcField = key + '.calculation' } else { calcField = key + '.text' } - if (definition[calcField]){ + if (definition[calcField]) { definition[calcField].defaultValue = defaultValue; } else { definition[calcField] = { diff --git a/app/imports/api/properties/subSchemas/inlineCalculationField.js b/app/imports/api/properties/subSchemas/inlineCalculationField.ts similarity index 88% rename from app/imports/api/properties/subSchemas/inlineCalculationField.js rename to app/imports/api/properties/subSchemas/inlineCalculationField.ts index 22e37654..a0e27827 100644 --- a/app/imports/api/properties/subSchemas/inlineCalculationField.js +++ b/app/imports/api/properties/subSchemas/inlineCalculationField.ts @@ -1,10 +1,18 @@ import SimpleSchema from 'simpl-schema'; import ErrorSchema from '/imports/api/properties/subSchemas/ErrorSchema.js'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; +import { CalculatedField } from './computedField'; + +export interface InlineCalculation { + text?: string, + hash?: number, + value?: string, + inlineCalculations: CalculatedField[], +} // Get schemas that apply fields directly so they can be gracefully extended // because {type: Schema} fields can't be extended -function inlineCalculationFieldToCompute(field){ +function inlineCalculationFieldToCompute(field) { return new SimpleSchema({ // The object should already be set, but set again just in case [field]: { @@ -20,7 +28,7 @@ function inlineCalculationFieldToCompute(field){ }); } -function computedOnlyInlineCalculationField(field){ +function computedOnlyInlineCalculationField(field) { return new SimpleSchema({ // The object should already be set, but set again just in case [field]: { @@ -30,9 +38,8 @@ function computedOnlyInlineCalculationField(field){ }, // a hash of the text to see if the current cached values need to be updated [`${field}.hash`]: { - type: String, + type: Number, optional: true, - max: STORAGE_LIMITS.inlineCalculationField, }, [`${field}.value`]: { type: String, @@ -90,7 +97,7 @@ function computedOnlyInlineCalculationField(field){ }); } -function computedInlineCalculationField(field){ +function computedInlineCalculationField(field) { return inlineCalculationFieldToCompute(field).extend( computedOnlyInlineCalculationField(field) ) diff --git a/app/imports/api/sharing/sharing.js b/app/imports/api/sharing/sharing.js index 7062ff40..84386618 100644 --- a/app/imports/api/sharing/sharing.js +++ b/app/imports/api/sharing/sharing.js @@ -1,8 +1,7 @@ import SimpleSchema from 'simpl-schema'; import { assertOwnership } from '/imports/api/sharing/sharingPermissions.js'; -import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; -import getCollectionByName from '/imports/api/parenting/getCollectionByName.js'; -import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; +import { getCollectionByName, fetchDocByRef } from '/imports/api/parenting/parentingFunctions'; +import { RefSchema } from '/imports/api/parenting/ChildSchema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { getUserTier } from '/imports/api/users/patreon/tiers.js'; diff --git a/app/imports/api/sharing/sharingPermissions.js b/app/imports/api/sharing/sharingPermissions.js index c01675f4..dcea4605 100644 --- a/app/imports/api/sharing/sharingPermissions.js +++ b/app/imports/api/sharing/sharingPermissions.js @@ -1,5 +1,5 @@ import { includes } from 'lodash'; -import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; +import { fetchDocByRef } from '/imports/api/parenting/parentingFunctions'; function assertIdValid(userId) { if (!userId || typeof userId !== 'string') { diff --git a/app/imports/client/ui/components/tree/TreeNode.vue b/app/imports/client/ui/components/tree/TreeNode.vue index 18df392e..1fc0af75 100644 --- a/app/imports/client/ui/components/tree/TreeNode.vue +++ b/app/imports/client/ui/components/tree/TreeNode.vue @@ -83,7 +83,7 @@ * the tree view shows off the full character structure, and where each part of * character comes from. **/ -import { canBeParent } from '/imports/api/parenting/parenting.js'; +import { canBeParent } from '/imports/api/parenting/parentingFunctions'; import { getPropertyIcon } from '/imports/constants/PROPERTIES.js'; import TreeNodeView from '/imports/client/ui/properties/treeNodeViews/TreeNodeView.vue'; import { some } from 'lodash'; diff --git a/app/imports/client/ui/components/tree/TreeNodeList.vue b/app/imports/client/ui/components/tree/TreeNodeList.vue index 5199180f..54c5d212 100644 --- a/app/imports/client/ui/components/tree/TreeNodeList.vue +++ b/app/imports/client/ui/components/tree/TreeNodeList.vue @@ -34,7 +34,7 @@