diff --git a/.vscode/settings.json b/.vscode/settings.json index a34eb69c..585dd5b0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -36,5 +36,15 @@ "vuetify", "Vuex", "walkdown" - ] + ], + "javascript.preferences.importModuleSpecifier": "non-relative", + "javascript.preferences.importModuleSpecifierEnding": "minimal", + "javascript.preferences.organizeImports": { + "enabled": true, + }, + "typescript.preferences.importModuleSpecifier": "non-relative", + "typescript.preferences.importModuleSpecifierEnding": "minimal", + "typescript.preferences.organizeImports": { + "enabled": true, + } } diff --git a/app/imports/@types/mongo.d.ts b/app/imports/@types/mongo.d.ts index 9b7f223a..5a59ebe3 100644 --- a/app/imports/@types/mongo.d.ts +++ b/app/imports/@types/mongo.d.ts @@ -1,5 +1,5 @@ -import { TypedSimpleSchema } from 'imports/api/utility/TypedSimpleSchema'; -import SimpleSchema from 'simpl-schema'; +type SimpleSchema = import('simpl-schema').default; +type TypedSimpleSchema = import('imports/api/utility/TypedSimpleSchema').TypedSimpleSchema; declare namespace Mongo { interface CollectionStatic { @@ -11,15 +11,17 @@ declare namespace Mongo { /** * Set to `true` if your document must be passed through the collection's transform to properly validate */ - transform: boolean, + transform?: boolean, /** * Set to `true` to replace any existing schema instead of combining */ - replace: boolean + replace?: boolean + selector?: any; } - interface Collection { - schema?: TypedSimpleSchema; + interface Collection { + schema: TypedSimpleSchema; + simpleSchema>(selector?: U): TypedSimpleSchema; /** * Use this method to attach a schema to a collection created by another package, * such as Meteor.users. It is most likely unsafe to call this method more than diff --git a/app/imports/api/creature/archive/methods/archiveCreatureToFile.js b/app/imports/api/creature/archive/methods/archiveCreatureToFile.js index a58ddb47..57d0002b 100644 --- a/app/imports/api/creature/archive/methods/archiveCreatureToFile.js +++ b/app/imports/api/creature/archive/methods/archiveCreatureToFile.js @@ -79,7 +79,7 @@ const archiveCreatureToFile = new ValidatedMethod({ validate: new SimpleSchema({ 'creatureId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/creature/archive/methods/removeArchiveCreature.js b/app/imports/api/creature/archive/methods/removeArchiveCreature.js index c7a20fb2..7018b0b1 100644 --- a/app/imports/api/creature/archive/methods/removeArchiveCreature.js +++ b/app/imports/api/creature/archive/methods/removeArchiveCreature.js @@ -9,7 +9,7 @@ const removeArchiveCreature = new ValidatedMethod({ validate: new SimpleSchema({ 'fileId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js b/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js index 416782a0..4a8da16a 100644 --- a/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js +++ b/app/imports/api/creature/archive/methods/restoreCreatureFromFile.js @@ -65,7 +65,7 @@ const restoreCreaturefromFile = new ValidatedMethod({ validate: new SimpleSchema({ 'fileId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/creature/creatureFolders/CreatureFolders.js b/app/imports/api/creature/creatureFolders/CreatureFolders.js index 6339014a..b5a37b6d 100644 --- a/app/imports/api/creature/creatureFolders/CreatureFolders.js +++ b/app/imports/api/creature/creatureFolders/CreatureFolders.js @@ -16,11 +16,11 @@ let creatureFolderSchema = new SimpleSchema({ }, 'creatures.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, owner: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, index: 1, }, archived: { diff --git a/app/imports/api/creature/creatureProperties/CreatureProperties.ts b/app/imports/api/creature/creatureProperties/CreatureProperties.ts index f4df696d..3342d643 100644 --- a/app/imports/api/creature/creatureProperties/CreatureProperties.ts +++ b/app/imports/api/creature/creatureProperties/CreatureProperties.ts @@ -1,4 +1,3 @@ -import { Mongo } from 'meteor/mongo'; import SimpleSchema from 'simpl-schema'; import ColorSchema from '/imports/api/properties/subSchemas/ColorSchema'; import ChildSchema from '/imports/api/parenting/ChildSchema'; @@ -13,7 +12,7 @@ import type { PropertyType } from '/imports/api/properties/PropertyType.type'; const PreComputeCreaturePropertySchema = TypedSimpleSchema.from({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, _migrationError: { type: String, @@ -44,7 +43,7 @@ const PreComputeCreaturePropertySchema = TypedSimpleSchema.from({ // Reference to the library node that this property was copied from libraryNodeId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, // Fill more than one quantity in a slot, like feats and ability score @@ -87,7 +86,7 @@ const DenormalisedOnlyCreaturePropertySchema = TypedSimpleSchema.from({ }, deactivatingToggleId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, removeBeforeCompute: true, }, @@ -103,7 +102,7 @@ const DenormalisedOnlyCreaturePropertySchema = TypedSimpleSchema.from({ }, 'triggerIds.before.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'triggerIds.after': { type: Array, @@ -111,7 +110,7 @@ const DenormalisedOnlyCreaturePropertySchema = TypedSimpleSchema.from({ }, 'triggerIds.after.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'triggerIds.afterChildren': { type: Array, @@ -119,7 +118,7 @@ const DenormalisedOnlyCreaturePropertySchema = TypedSimpleSchema.from({ }, 'triggerIds.afterChildren.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, // When this is true on any property, the creature needs to be recomputed dirty: { @@ -156,7 +155,6 @@ for (key in propertySchemasIndex) { 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/copyPropertyToLibrary.js b/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js index 838e14c0..5ef9563b 100644 --- a/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js +++ b/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js @@ -23,7 +23,7 @@ const copyPropertyToLibrary = new ValidatedMethod({ validate: new SimpleSchema({ propId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, parentRef: { type: RefSchema, diff --git a/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js b/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js index 8cd7c52b..deadcca1 100644 --- a/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js @@ -23,7 +23,7 @@ const duplicateProperty = new ValidatedMethod({ validate: new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, } }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/creature/creatureProperties/methods/insertProperty.js b/app/imports/api/creature/creatureProperties/methods/insertProperty.js index 56512bfc..678c838b 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/insertProperty.js @@ -52,7 +52,7 @@ const insertPropertyAsChildOfTag = new ValidatedMethod({ }, creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, tag: { type: String, diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index b4d833c8..cc8d29be 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -23,7 +23,7 @@ const insertPropertyFromLibraryNode = new ValidatedMethod({ }, 'nodeIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, parentRef: { type: RefSchema, diff --git a/app/imports/api/creature/creatures/Creatures.ts b/app/imports/api/creature/creatures/Creatures.ts index e05148cb..35e020a5 100644 --- a/app/imports/api/creature/creatures/Creatures.ts +++ b/app/imports/api/creature/creatures/Creatures.ts @@ -97,7 +97,7 @@ const CreatureSchema = TypedSimpleSchema.from({ }, 'allowedLibraries.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, allowedLibraryCollections: { type: Array, @@ -106,7 +106,7 @@ const CreatureSchema = TypedSimpleSchema.from({ }, 'allowedLibraryCollections.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, // Stats that are computed and denormalised outside of recomputation @@ -163,7 +163,7 @@ const CreatureSchema = TypedSimpleSchema.from({ tabletopId: { index: 1, type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, initiativeRoll: { @@ -176,17 +176,14 @@ const CreatureSchema = TypedSimpleSchema.from({ type: CreatureSettingsSchema, defaultValue: {}, }, -}); - -CreatureSchema.extend(ColorSchema); -CreatureSchema.extend(SharingSchema); +}) + .extend(ColorSchema) + .extend(SharingSchema); export type Creature = Simplify<{ _id: string } & InferType>; //set up the collection for creatures const Creatures = new Mongo.Collection('creatures'); - -//@ts-expect-error attachSchema not defined Creatures.attachSchema(CreatureSchema); export default Creatures; diff --git a/app/imports/api/creature/creatures/methods/changeAllowedLibraries.js b/app/imports/api/creature/creatures/methods/changeAllowedLibraries.js index c95aa533..c22d7429 100644 --- a/app/imports/api/creature/creatures/methods/changeAllowedLibraries.js +++ b/app/imports/api/creature/creatures/methods/changeAllowedLibraries.js @@ -11,7 +11,7 @@ const changeAllowedLibraries = new ValidatedMethod({ schema: new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, allowedLibraries: { type: Array, @@ -20,7 +20,7 @@ const changeAllowedLibraries = new ValidatedMethod({ }, 'allowedLibraries.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, allowedLibraryCollections: { type: Array, @@ -29,7 +29,7 @@ const changeAllowedLibraries = new ValidatedMethod({ }, 'allowedLibraryCollections.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }), rateLimit: { @@ -58,7 +58,7 @@ const toggleAllUserLibraries = new ValidatedMethod({ schema: new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, value: { type: Boolean, diff --git a/app/imports/api/creature/creatures/methods/removeCreature.js b/app/imports/api/creature/creatures/methods/removeCreature.js index 646a6bc8..2153d43b 100644 --- a/app/imports/api/creature/creatures/methods/removeCreature.js +++ b/app/imports/api/creature/creatures/methods/removeCreature.js @@ -21,7 +21,7 @@ const removeCreature = new ValidatedMethod({ validate: new SimpleSchema({ charId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/creature/experience/Experiences.js b/app/imports/api/creature/experience/Experiences.js index 26ee5739..1063bae0 100644 --- a/app/imports/api/creature/experience/Experiences.js +++ b/app/imports/api/creature/experience/Experiences.js @@ -39,7 +39,7 @@ let ExperienceSchema = new SimpleSchema({ }, creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, index: 1, }, }); @@ -76,7 +76,7 @@ const insertExperience = new ValidatedMethod({ }, 'creatureIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], @@ -105,7 +105,7 @@ const removeExperience = new ValidatedMethod({ validate: new SimpleSchema({ experienceId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], @@ -146,7 +146,7 @@ const recomputeExperiences = new ValidatedMethod({ validate: new SimpleSchema({ creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/creature/journal/JournalEntry.js b/app/imports/api/creature/journal/JournalEntry.js index bb1a5059..29eab12a 100644 --- a/app/imports/api/creature/journal/JournalEntry.js +++ b/app/imports/api/creature/journal/JournalEntry.js @@ -42,7 +42,7 @@ let ExperienceSchema = new SimpleSchema({ // ID of the journal this entry belongs to journalId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, index: 1, } }); diff --git a/app/imports/api/creature/log/CreatureLogs.js b/app/imports/api/creature/log/CreatureLogs.js index 6ba45991..f606ac7f 100644 --- a/app/imports/api/creature/log/CreatureLogs.js +++ b/app/imports/api/creature/log/CreatureLogs.js @@ -192,7 +192,7 @@ const logRoll = new ValidatedMethod({ }, creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, }).validator(), diff --git a/app/imports/api/docs/Docs.ts b/app/imports/api/docs/Docs.ts index accf8247..00bc8ad1 100644 --- a/app/imports/api/docs/Docs.ts +++ b/app/imports/api/docs/Docs.ts @@ -34,7 +34,7 @@ const Docs: Mongo.Collection & { const DocSchema = new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, name: { type: String, diff --git a/app/imports/api/engine/action/ActionEngine.test.ts b/app/imports/api/engine/action/ActionEngine.test.ts deleted file mode 100644 index 31041ba8..00000000 --- a/app/imports/api/engine/action/ActionEngine.test.ts +++ /dev/null @@ -1,448 +0,0 @@ -import { assert } from 'chai'; -import '/imports/api/simpleSchemaConfig.js'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -import { propsFromForest } from '/imports/api/properties/tests/propTestBuilder.testFn'; -import Creatures from '/imports/api/creature/creatures/Creatures'; -import computeCreature from '/imports/api/engine/computeCreature'; -import { loadCreature } from '/imports/api/engine/loadCreatures'; -import EngineActions, { EngineAction } from '/imports/api/engine/action/EngineActions'; -import applyAction from '/imports/api/engine/action/functions/applyAction'; -import { LogContent, Removal, Update } from '/imports/api/engine/action/tasks/TaskResult'; -import inputProvider from './functions/userInput/inputProviderForTests.testFn'; -import { removeAllCreaturesAndProps } from '/imports/api/engine/action/functions/actionEngineTest.testFn'; - -const creatureId = Random.id(); -const targetId = Random.id(); - -describe('Interrupt action system', function () { - const dummySubscription = Tracker.autorun(() => undefined) - this.timeout(8000); - before(async function () { - // Remove old data - await removeAllCreaturesAndProps(); - - // Add creatures - await Promise.all([ - Creatures.insertAsync({ - _id: creatureId, - name: 'action test creature', - owner: Random.id(), - dirty: true, - type: 'pc', - readers: [], - writers: [], - public: false, - settings: {}, - }), - Creatures.insertAsync({ - _id: targetId, - name: 'action test creature', - owner: Random.id(), - dirty: true, - type: 'pc', - readers: [], - writers: [], - public: false, - settings: {}, - }) - ]); - // Add test props - await insertActionTestProps(); - // Compute before load or we might run tests before the computation changes reflect in the cache - computeCreature(creatureId); - computeCreature(targetId); - loadCreature(creatureId, dummySubscription); - }); - after(function () { - dummySubscription.stop(); - }); - it('writes notes to the log', async function () { - const action = await runActionById(note1Id); - assert.deepEqual( - allLogContent(action), - [{ value: 'Note 1 summary. 1 + 1 = 2' }] - ); - }); - it('Applies children of folders', async function () { - const action = await runActionById(folderId); - assert.deepEqual( - allLogContent(action), - [{ value: 'child of folder' }] - ); - }); - it('Applies the children of if branches', async function () { - let action = await runActionById(ifTruthyBranchId); - assert.deepEqual( - allLogContent(action), - [{ value: 'child of if branch' }] - ); - action = await runActionById(ifFalsyBranchId); - assert.deepEqual( - allLogContent(action), - [] - ); - }); - it('Applies the children of index branches', async function () { - const action = await runActionById(indexBranchId); - assert.deepEqual( - allLogContent(action), - [{ value: 'child 2 of index branch' }] - ); - }); - it('Gets choices from choice branches', async function () { - const action = await runActionById(choiceBranchId); - assert.deepEqual( - allLogContent(action), - [{ value: 'child 1 of choice branch' }] - ); - }); - it('Applies adjustments', async function () { - let action = await runActionById(adjustmentSetId); - assert.deepEqual( - allUpdates(action), - [{ - propId: adjustedStatId, - type: 'attribute', - set: { damage: 5, value: 3 }, - }], - 'Applying set adjustments should return the correct updates' - ); - action = await runActionById(adjustmentIncrementId) - assert.deepEqual( - allUpdates(action), - [{ - propId: adjustedStatId, - type: 'attribute', - inc: { damage: 2, value: -2 }, // damage goes up by 2, value down by 2 - }], - 'Applying increment adjustments should return the correct updates' - ); - }); - it('Applies rolls', async function () { - const action = await runActionById(rollId); - assert.deepEqual(allLogContent(action), [ - { - name: 'New Roll', - value: '7d1 [1, 1, 1, 1, 1, 1, 1] + 9\n**16**', - inline: true, - }, { - value: 'rollVar: 16' - } - ]); - }); - it('Applies buffs', async function () { - const action = await runActionById(buffId); - const inserts = allInserts(action); - const newIds = inserts.map(p => p._id); - assert.notEqual(buffId, newIds[0]); - assert.deepEqual(inserts, [ - { - _id: newIds[0], - left: 43, - parentId: null, - right: 48, - root: { - collection: 'creatures', - id: creatureId, - }, - tags: [], - target: 'self', - type: 'buff', - }, { - _id: newIds[1], - attributeType: 'stat', - baseValue: { - calculation: '13 + buffSourceStat + 7', - }, - left: 44, - parentId: newIds[0], - right: 45, - root: { - collection: 'creatures', - id: creatureId, - }, - tags: [], - type: 'attribute', - variableName: 'buffStat', - }, { - _id: newIds[2], - left: 46, - parentId: newIds[0], - removeAll: true, - right: 47, - root: { - collection: 'creatures', - id: creatureId, - }, - tags: [], - target: 'self', - targetParentBuff: true, - type: 'buffRemover', - } - ]); - }); - it('Removes parent buffs', async function () { - const action = await runActionById(removeParentBuffId); - assert.deepEqual(allRemovals(action), [ - { propId: buffId } - ]); - }); - it('Removes all buffs by tag', async function () { - const action = await runActionById(removeTaggedBuffsId); - assert.deepEqual(allRemovals(action), [ - { propId: taggedBuffId }, - { propId: secondTaggedBuffId }, - ]); - }); - it('Removes a single buff by tag', async function () { - const action = await runActionById(removeOneTaggedBuffId); - assert.deepEqual(allRemovals(action), [ - { propId: taggedBuffId }, - ]); - }); -}); - -function createAction(prop, targetIds?) { - const action: EngineAction = { - creatureId: prop.root.id, - results: [], - taskCount: 0, - task: { - prop, - targetIds, - } - }; - return EngineActions.insertAsync(action); -} - -async function runActionById(propId) { - const prop = await CreatureProperties.findOneAsync(propId); - const actionId = await createAction(prop); - const action = await EngineActions.findOneAsync(actionId); - if (!action) throw 'Action is expected to exist'; - await applyAction(action, inputProvider, { simulate: true }); - return action; -} - -function allUpdates(action: EngineAction) { - const updates: Update[] = []; - action.results.forEach(result => { - result.mutations.forEach(mutation => { - mutation.updates?.forEach(update => { - updates.push(update); - }); - }); - }); - return updates; -} - -function allInserts(action: EngineAction) { - const inserts: any[] = []; - action.results.forEach(result => { - result.mutations.forEach(mutation => { - mutation.inserts?.forEach(update => { - inserts.push(update); - }); - }); - }); - return inserts; -} - -function allRemovals(action: EngineAction) { - const removals: Removal[] = []; - action.results.forEach(result => { - result.mutations.forEach(mutation => { - mutation.removals?.forEach(update => { - removals.push(update); - }); - }); - }); - return removals -} - -function allLogContent(action: EngineAction) { - const contents: LogContent[] = []; - action.results.forEach(result => { - result.mutations.forEach(mutation => { - mutation.contents?.forEach(logContent => { - contents.push(logContent); - }); - }); - }); - return contents; -} - -let note1Id, folderId, ifTruthyBranchId, ifFalsyBranchId, indexBranchId, choiceBranchId, - adjustedStatId, adjustmentIncrementId, adjustmentSetId, rollId, buffId, - removeParentBuffId, removeTaggedBuffsId, removeOneTaggedBuffId, taggedBuffId, secondTaggedBuffId; - -const propForest = [ - // Apply a simple note - { - _id: note1Id = Random.id(), - type: 'note', - summary: { - text: 'Note 1 summary. 1 + 1 = {1 + 1}' - }, - }, - // Apply a folder with a note inside - { - _id: folderId = Random.id(), - type: 'folder', - children: [{ type: 'note', summary: { text: 'child of folder' } }], - }, - // Apply an if branch with a truthy condition - { - _id: ifTruthyBranchId = Random.id(), - type: 'branch', - branchType: 'if', - condition: { calculation: '1 + 1' }, - children: [{ type: 'note', summary: { text: 'child of if branch' } }], - }, - // Apply an if branch with a falsy condition - { - _id: ifFalsyBranchId = Random.id(), - type: 'branch', - branchType: 'if', - condition: { calculation: '1 - 1' }, - children: [{ type: 'note', summary: { text: 'child of if branch' } }], - }, - // Apply an index branch - { - _id: indexBranchId = Random.id(), - type: 'branch', - branchType: 'index', - condition: { calculation: '1 + 1' }, - children: [ - { type: 'note', summary: { text: 'child 1 of index branch' } }, - { type: 'note', summary: { text: 'child 2 of index branch' } }, - { type: 'note', summary: { text: 'child 3 of index branch' } }, - ], - }, - // Apply a choice branch - { - _id: choiceBranchId = Random.id(), - type: 'branch', - branchType: 'choice', - children: [ - { type: 'note', summary: { text: 'child 1 of choice branch' } }, - { type: 'note', summary: { text: 'child 2 of choice branch' } }, - { type: 'note', summary: { text: 'child 3 of choice branch' } }, - ], - }, - // Apply adjustments - { - _id: adjustedStatId = Random.id(), - type: 'attribute', - attributeType: 'stat', - variableName: 'adjustedStat', - baseValue: { calculation: '8' }, - }, { - _id: adjustmentSetId = Random.id(), - type: 'adjustment', - stat: 'adjustedStat', - operation: 'set', - amount: { calculation: '3' }, - target: 'self', - children: [ - { type: 'note', summary: { text: 'adjustment set applied' } }, - ], - }, { - _id: adjustmentIncrementId = Random.id(), - type: 'adjustment', - stat: 'adjustedStat', - operation: 'increment', - amount: { calculation: '2' }, - target: 'self', - children: [ - { type: 'note', summary: { text: 'adjustment increment applied' } }, - ], - }, - // Apply buffs - { - _id: Random.id(), - type: 'attribute', - attributeType: 'stat', - variableName: 'buffSourceStat', - baseValue: { calculation: '13' }, - }, { - _id: buffId = Random.id(), - type: 'buff', - target: 'self', - children: [ - { - _id: Random.id(), - type: 'attribute', - attributeType: 'stat', - variableName: 'buffStat', - baseValue: { calculation: 'buffSourceStat + ~target.buffSourceStat + 7' }, - }, { - _id: removeParentBuffId = Random.id(), - type: 'buffRemover', - target: 'self', - targetParentBuff: true, - }, - ], - }, - // Extra buffs with and without tags - { - _id: taggedBuffId = Random.id(), - name: 'Tagged Buff', - type: 'buff', - tags: ['buff tag', 'other tag'] - }, { - _id: secondTaggedBuffId = Random.id(), - name: 'Tagged buff 2', - type: 'buff', - tags: ['buff tag', 'yet another tag'] - }, { - _id: Random.id(), - name: 'Untagged buff', - type: 'buff', - tags: ['other tag'] - }, - // Remove buffs by tag - { - _id: removeTaggedBuffsId = Random.id(), - type: 'buffRemover', - target: 'self', - removeAll: true, - targetTags: 'buff tag', - }, { - _id: removeOneTaggedBuffId = Random.id(), - type: 'buffRemover', - target: 'self', - removeAll: false, - targetTags: 'buff tag', - }, - // Apply rolls - { - _id: rollId = Random.id(), - type: 'roll', - // Roll d1's because it's a pain to test random numbers - roll: { calculation: '1 + 3 + 7d1 + 5' }, - variableName: 'rollVar', - children: [ - { type: 'note', summary: { text: 'rollVar: {rollVar}' } } - ] - } -]; - -const targetPropForest = [ - { - type: 'attribute', - attributeType: 'stat', - variableName: 'armor', - baseValue: { calculation: '10' }, - } -]; - -function insertActionTestProps() { - const promises = propsFromForest(propForest, creatureId).map(prop => { - return CreatureProperties.insertAsync(prop); - }); - propsFromForest(targetPropForest, targetId).forEach(prop => { - promises.push(CreatureProperties.insertAsync(prop)); - }); - return Promise.all(promises); -} diff --git a/app/imports/api/engine/action/EngineActions.ts b/app/imports/api/engine/action/EngineActions.ts index 966e5a87..e420bd62 100644 --- a/app/imports/api/engine/action/EngineActions.ts +++ b/app/imports/api/engine/action/EngineActions.ts @@ -20,18 +20,18 @@ export interface EngineAction { const ActionSchema = new SimpleSchema({ creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, // @ts-expect-error index not defined index: 1, }, rootPropId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, tabletopId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, // @ts-expect-error index not defined index: 1, @@ -53,7 +53,7 @@ const ActionSchema = new SimpleSchema({ // Should re-run the action identically from this point 'results.$.propId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'results.$.targetIds': { type: Array, @@ -61,7 +61,7 @@ const ActionSchema = new SimpleSchema({ }, 'results.$.targetIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, // Changes that override the local scope 'results.$.scope': { @@ -94,7 +94,7 @@ const ActionSchema = new SimpleSchema({ }, 'results.$.mutations.$.targetIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'results.$.mutations.$.updates': { type: Array, @@ -105,7 +105,7 @@ const ActionSchema = new SimpleSchema({ }, 'results.$.mutations.$.updates.$.propId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, // Required, because CreatureProperties.update requires a selector of { type } 'results.$.mutations.$.updates.$.type': { diff --git a/app/imports/api/engine/action/applyProperties/applyAdjustmentProperty.test.ts b/app/imports/api/engine/action/applyProperties/applyAdjustmentProperty.test.ts index d4063fe2..6d841889 100644 --- a/app/imports/api/engine/action/applyProperties/applyAdjustmentProperty.test.ts +++ b/app/imports/api/engine/action/applyProperties/applyAdjustmentProperty.test.ts @@ -4,14 +4,15 @@ import { createTestCreature, getRandomIds, removeAllCreaturesAndProps, - runActionById + runActionById, + TestCreature } from '/imports/api/engine/action/functions/actionEngineTest.testFn'; const [ creatureId, targetCreatureId, targetCreature2Id, adjustmentToTargetId, adjustmentToSelfId, targetCreatureStrengthId, targetCreature2StrengthId, selfDexterityId ] = getRandomIds(100); -const actionTestCreature = { +const actionTestCreature: TestCreature = { _id: creatureId, props: [ { @@ -41,7 +42,7 @@ const actionTestCreature = { ], } -const actionTargetCreature = { +const actionTargetCreature: TestCreature = { _id: targetCreatureId, props: [ { @@ -54,7 +55,7 @@ const actionTargetCreature = { ] } -const actionTargetCreature2 = { +const actionTargetCreature2: TestCreature = { _id: targetCreature2Id, props: [ { diff --git a/app/imports/api/engine/action/functions/actionEngineTest.testFn.ts b/app/imports/api/engine/action/functions/actionEngineTest.testFn.ts index 4c389c19..048da6b9 100644 --- a/app/imports/api/engine/action/functions/actionEngineTest.testFn.ts +++ b/app/imports/api/engine/action/functions/actionEngineTest.testFn.ts @@ -1,10 +1,10 @@ import '/imports/api/simpleSchemaConfig.js'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -import { propsFromForest } from '/imports/api/properties/tests/propTestBuilder.testFn'; +import propsFromForest, { ForestProp } from '/imports/api/engine/computation/utility/propsFromForest.testFn'; import Creatures from '/imports/api/creature/creatures/Creatures'; import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables'; import computeCreature from '/imports/api/engine/computeCreature'; -import { loadCreature } from '/imports/api/engine/loadCreatures'; +import { loadCreature, unloadAllCreatures } from '/imports/api/engine/loadCreatures'; import EngineActions, { EngineAction } from '/imports/api/engine/action/EngineActions'; import applyAction from '/imports/api/engine/action/functions/applyAction'; import { LogContent, Mutation, Removal, Update } from '/imports/api/engine/action/tasks/TaskResult'; @@ -14,6 +14,7 @@ import inputProvider from './userInput/inputProviderForTests.testFn'; */ export async function removeAllCreaturesAndProps() { if (Meteor.isServer) { + unloadAllCreatures(); return Promise.all([ CreatureProperties.removeAsync({}), Creatures.removeAsync({}), @@ -38,7 +39,7 @@ export async function createTestCreature(creature: TestCreature) { name: creature.name || 'Test Creature', owner: Random.id(), dirty: true, - }); + } as any); const propsInserted = propsFromForest(creature.props, creature._id).map(prop => { return CreatureProperties.insertAsync(prop); }); @@ -47,16 +48,16 @@ export async function createTestCreature(creature: TestCreature) { await computeCreature(creature._id,); } -type TestCreature = { +export type TestCreature = { _id: string; name?: string; - props: any[]; + props: ForestProp[]; } /** * get a list of random Ids */ -export const getRandomIds = (count) => new Array(count).fill(undefined).map(() => Random.id()); +export const getRandomIds = (count: number) => new Array(count).fill(undefined).map(() => Random.id()); /** * Creates a new Engine Action and applies the specified creature property @@ -64,7 +65,7 @@ export const getRandomIds = (count) => new Array(count).fill(undefined).map(() = * @param userInputFn A function that simulates user input * @returns The Engine Action with mutations resulting from running the action */ -export async function runActionById(propId, targetIds?, userInput = inputProvider) { +export async function runActionById(propId: string, targetIds?: string[], userInput = inputProvider) { const prop = await CreatureProperties.findOneAsync(propId); const actionId = await createAction(prop, targetIds); const action = await EngineActions.findOneAsync(actionId); diff --git a/app/imports/api/engine/computation/buildComputation/tests/computeInactiveStatus.testFn.js b/app/imports/api/engine/computation/buildComputation/tests/computeInactiveStatus.testFn.js index c4119e2d..fff1dec9 100644 --- a/app/imports/api/engine/computation/buildComputation/tests/computeInactiveStatus.testFn.js +++ b/app/imports/api/engine/computation/buildComputation/tests/computeInactiveStatus.testFn.js @@ -12,7 +12,7 @@ export default function () { // Items active('itemUnequippedId', 'Unequipped items should be active'); - byAncestor('itemUnequippedChildId', 'Children of unequipped items should be inactive'); + byAncestor('itemUnEQChildId', 'Children of unequipped items should be inactive'); active('itemEquippedId', 'Equipped items should be active'); active('itemEquippedChildId', 'Children of equipped items should be active'); @@ -56,7 +56,7 @@ var testProperties = [ parentId: 'charId', }), clean({ - _id: 'itemUnequippedChildId', + _id: 'itemUnEQChildId', type: 'folder', parentId: 'itemUnequippedId', }), diff --git a/app/imports/api/engine/computation/buildCreatureComputation.ts b/app/imports/api/engine/computation/buildCreatureComputation.ts index 44dde3f6..a08a1fda 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.ts +++ b/app/imports/api/engine/computation/buildCreatureComputation.ts @@ -34,7 +34,8 @@ export default function buildCreatureComputation(creatureId: string) { const creature = getCreature(creatureId); if (!creature) { throw new Meteor.Error('not-found', - 'Build computation failed, the creature was not found' + 'Build computation failed, the creature was not found.' + + '\nid: ' + creatureId ); } const variables = getVariables(creatureId); diff --git a/app/imports/api/engine/computation/computeComputation/tstFns/buildTestComputation.ts b/app/imports/api/engine/computation/computeComputation/tstFns/buildTestComputation.ts new file mode 100644 index 00000000..9afb9756 --- /dev/null +++ b/app/imports/api/engine/computation/computeComputation/tstFns/buildTestComputation.ts @@ -0,0 +1,18 @@ +import Creatures from '/imports/api/creature/creatures/Creatures'; +import { TestCreature } from '/imports/api/engine/action/functions/actionEngineTest.testFn'; +import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; +import propsFromForest from '/imports/api/engine/computation/utility/propsFromForest.testFn'; +import { cleanAndValidate } from '/imports/api/utility/TypedSimpleSchema'; + +export default function buildTestComputation(testCreature: TestCreature) { + const creature = cleanAndValidate(Creatures.simpleSchema(), { + _id: testCreature._id, + name: testCreature.name || 'Test Creature', + dirty: true, + owner: Random.id(), + readers: [], + writers: [], + }); + const props = propsFromForest(testCreature.props, creature._id); + return buildComputationFromProps(props, creature, {}); +} diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeAction.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeAction.testFn.ts similarity index 59% rename from app/imports/api/engine/computation/computeComputation/tests/computeAction.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeAction.testFn.ts index 6bec5740..143e001f 100644 --- a/app/imports/api/engine/computation/computeComputation/tests/computeAction.testFn.js +++ b/app/imports/api/engine/computation/computeComputation/tstFns/computeAction.testFn.ts @@ -1,36 +1,42 @@ -import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; import { assert } from 'chai'; -import computeCreatureComputation from '../../computeCreatureComputation'; -import clean from '../../utility/cleanProp.testFn'; +import computeCreatureComputation from '/imports/api/engine/computation/computeCreatureComputation'; +import buildTestComputation from './buildTestComputation'; +import type { ForestProp } from '/imports/api/engine/computation/utility/propsFromForest.testFn'; +import { CreaturePropertyTypes } from '/imports/api/creature/creatureProperties/CreatureProperties'; export default async function () { - const computation = buildComputationFromProps(testProperties); + const computation = buildTestComputation({ + _id: 'testCreatureId', + props: testProperties, + }); await computeCreatureComputation(computation); - const prop = computation.propsById['actionId']; - assert.equal(prop.summary.value, 'test summary 3 without referencing anything 7'); - assert.equal(prop.description.value, 'test description 12 with reference 0.25 prop'); - assert.equal(prop.uses.value, 7); + const prop = computation.propsById['actionId'] as CreaturePropertyTypes['action']; + assert.equal(prop.summary?.value, 'test summary 3 without referencing anything 7'); + assert.equal(prop.description?.value, 'test description 12 with reference 0.25 prop'); + assert.equal(prop.uses?.value, 7); assert.equal(prop.usesLeft, 2); - const rolled = computation.propsById['rolledDescriptionId']; - assert.equal(rolled.summary.value, 'test roll gets compiled 8 properly'); + const rolled = computation.propsById['rolledDescriptionId'] as CreaturePropertyTypes['action']; + assert.equal(rolled.summary?.value, 'test roll gets compiled 8 properly'); const itemConsumed = prop.resources.itemsConsumed[0]; - assert.equal(itemConsumed.quantity.value, 3); + assert.exists(itemConsumed); + assert.equal(itemConsumed.quantity?.value, 3); assert.equal(itemConsumed.available, 27); assert.equal(itemConsumed.itemName, 'Arrow'); - assert.equal(itemConsumed.itemIcon, 'itemIcon'); - assert.equal(itemConsumed.itemColor, 'itemColor'); + assert.equal(itemConsumed.itemIcon?.name, 'itemIcon'); + assert.equal(itemConsumed.itemColor, '#fff'); const attConsumed = prop.resources.attributesConsumed[0]; - assert.equal(attConsumed.quantity.value, 4); + assert.exists(attConsumed); + assert.equal(attConsumed.quantity?.value, 4); assert.equal(attConsumed.available, 9); assert.equal(attConsumed.statName, 'Resource Var'); } -var testProperties = [ - clean({ +const testProperties: ForestProp[] = [ + { _id: 'actionId', type: 'action', summary: { @@ -55,6 +61,7 @@ var testProperties = [ calculation: 'resourceConsumedQuantity' } }], + conditions: [], }, uses: { calculation: 'nonExistentProperty + 7', @@ -62,8 +69,8 @@ var testProperties = [ usesUsed: 5, left: 1, right: 2, - }), - clean({ + }, + { _id: 'rolledDescriptionId', type: 'action', summary: { @@ -71,9 +78,9 @@ var testProperties = [ }, left: 3, right: 4, - }), - clean({ - _id: 'numItemsConumedId', + }, + { + _id: 'numItemsConsumedId', type: 'attribute', variableName: 'itemConsumedQuantity', baseValue: { @@ -81,9 +88,9 @@ var testProperties = [ }, left: 5, right: 6, - }), - clean({ - _id: 'numResourceConumedId', + }, + { + _id: 'numResourceConsumedId', type: 'attribute', variableName: 'resourceConsumedQuantity', baseValue: { @@ -91,8 +98,8 @@ var testProperties = [ }, left: 7, right: 8, - }), - clean({ + }, + { _id: 'resourceVarId', name: 'Resource Var', type: 'attribute', @@ -102,8 +109,8 @@ var testProperties = [ }, left: 9, right: 10, - }), - clean({ + }, + { _id: 'inlineRefResourceId', type: 'attribute', variableName: 'inlineRef', @@ -112,15 +119,15 @@ var testProperties = [ }, left: 11, right: 12, - }), - clean({ + }, + { _id: 'arrowId', type: 'item', name: 'Arrow', quantity: 27, - icon: 'itemIcon', - color: 'itemColor', + icon: { name: 'itemIcon', shape: 'itemIconShape' }, + color: '#fff', left: 13, right: 14, - }), + }, ]; diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeAttribute.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeAttribute.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeAttribute.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeAttribute.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeCalculations.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeCalculations.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeCalculations.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeCalculations.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeClasses.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeClasses.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeClasses.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeClasses.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeConstants.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeConstants.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeConstants.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeConstants.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeDamageMultipliers.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeDamageMultipliers.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeDamageMultipliers.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeDamageMultipliers.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeEffects.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeEffects.testFn.js similarity index 93% rename from app/imports/api/engine/computation/computeComputation/tests/computeEffects.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeEffects.testFn.js index 9ef3d6ef..d2d96cd6 100644 --- a/app/imports/api/engine/computation/computeComputation/tests/computeEffects.testFn.js +++ b/app/imports/api/engine/computation/computeComputation/tstFns/computeEffects.testFn.js @@ -2,7 +2,7 @@ import { buildComputationFromProps } from '/imports/api/engine/computation/build import { assert } from 'chai'; import computeCreatureComputation from '../../computeCreatureComputation'; import clean from '../../utility/cleanProp.testFn'; -import { propsFromForest } from '/imports/api/properties/tests/propTestBuilder.testFn'; +import propsFromForest from '/imports/api/engine/computation/utility/propsFromForest.testFn'; export default async function () { const computation = buildComputationFromProps(testProperties); diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeInventory.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeInventory.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeInventory.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeInventory.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computePointBuys.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computePointBuys.testFn.js similarity index 92% rename from app/imports/api/engine/computation/computeComputation/tests/computePointBuys.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computePointBuys.testFn.js index 21b4897e..8e2a906f 100644 --- a/app/imports/api/engine/computation/computeComputation/tests/computePointBuys.testFn.js +++ b/app/imports/api/engine/computation/computeComputation/tstFns/computePointBuys.testFn.js @@ -1,7 +1,7 @@ import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; import { assert } from 'chai'; import computeCreatureComputation from '../../computeCreatureComputation'; -import { propsFromForest } from '/imports/api/properties/tests/propTestBuilder.testFn'; +import propsFromForest from '/imports/api/engine/computation/utility/propsFromForest.testFn'; export default async function () { const computation = buildComputationFromProps(testProperties); diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeProficiencies.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeProficiencies.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeProficiencies.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeProficiencies.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeSkills.testFn.js b/app/imports/api/engine/computation/computeComputation/tstFns/computeSkills.testFn.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/computeSkills.testFn.js rename to app/imports/api/engine/computation/computeComputation/tstFns/computeSkills.testFn.js diff --git a/app/imports/api/engine/computation/computeComputation/tests/index.js b/app/imports/api/engine/computation/computeComputation/tstFns/index.js similarity index 100% rename from app/imports/api/engine/computation/computeComputation/tests/index.js rename to app/imports/api/engine/computation/computeComputation/tstFns/index.js diff --git a/app/imports/api/engine/computation/computeCreatureComputation.test.ts b/app/imports/api/engine/computation/computeCreatureComputation.test.ts index 754db290..d6e07c52 100644 --- a/app/imports/api/engine/computation/computeCreatureComputation.test.ts +++ b/app/imports/api/engine/computation/computeCreatureComputation.test.ts @@ -2,12 +2,18 @@ import computeCreatureComputation from './computeCreatureComputation'; import { buildComputationFromProps } from './buildCreatureComputation'; import { assert } from 'chai'; import CreatureProperties, { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; -import computeTests from './computeComputation/tests/index'; -import Creatures, { Creature } from 'imports/api/creature/creatures/Creatures'; +import computeTests from '/imports/api/engine/computation/computeComputation/tstFns'; +import Creatures from '/imports/api/creature/creatures/Creatures'; +import { cleanAndValidate } from '/imports/api/utility/TypedSimpleSchema'; +import { createTestCreature } from '/imports/api/engine/action/functions/actionEngineTest.testFn'; describe('Compute computation', function () { - it('Computes something at all', function () { - const creature: Creature = Creatures.schema.clean({}); + it('Computes something at all', async function () { + const creature = cleanAndValidate(Creatures.simpleSchema(), { + owner: Random.id(), + readers: [], + writers: [], + }); const computation = buildComputationFromProps(testProperties, creature, {}); computeCreatureComputation(computation); assert.exists(computation); @@ -30,8 +36,8 @@ const testProperties = [ }), ]; -function clean(prop: Partial): CreatureProperty { - // @ts-expect-error don't have types for .simpleSchema +function clean(prop: Partial) { + prop.root ??= { collection: 'creatures', id: 'testCreature' }; const schema = CreatureProperties.simpleSchema(prop); - return schema.clean(prop); + return cleanAndValidate(schema, prop); } diff --git a/app/imports/api/engine/computation/utility/cleanProp.testFn.js b/app/imports/api/engine/computation/utility/cleanProp.testFn.js deleted file mode 100644 index 32bbbfe3..00000000 --- a/app/imports/api/engine/computation/utility/cleanProp.testFn.js +++ /dev/null @@ -1,9 +0,0 @@ -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; - -export default function cleanProp(prop) { - if (!prop.root) { - prop.root = { collection: 'creatures', id: 'testCreature' } - } - let schema = CreatureProperties.simpleSchema(prop); - return schema.clean(prop); -} diff --git a/app/imports/api/engine/computation/utility/cleanProp.testFn.ts b/app/imports/api/engine/computation/utility/cleanProp.testFn.ts new file mode 100644 index 00000000..01ea4dd3 --- /dev/null +++ b/app/imports/api/engine/computation/utility/cleanProp.testFn.ts @@ -0,0 +1,11 @@ +import { SetRequired } from 'type-fest'; +import CreatureProperties, { CreatureProperty, CreaturePropertyTypes } from '/imports/api/creature/creatureProperties/CreatureProperties'; +import { cleanAndValidate } from '/imports/api/utility/TypedSimpleSchema'; + +export default function cleanProp, 'type'>>(prop: T): CreaturePropertyTypes[T['type']] { + if (!prop.root) { + prop.root = { collection: 'creatures', id: 'testCreature' } + } + const schema = CreatureProperties.simpleSchema(prop); + return cleanAndValidate(schema, prop as Partial) as CreaturePropertyTypes[T['type']]; +} diff --git a/app/imports/api/properties/tests/propTestBuilder.testFn.js b/app/imports/api/engine/computation/utility/propsFromForest.testFn.ts similarity index 64% rename from app/imports/api/properties/tests/propTestBuilder.testFn.js rename to app/imports/api/engine/computation/utility/propsFromForest.testFn.ts index 4d17e677..701b0f0f 100644 --- a/app/imports/api/properties/tests/propTestBuilder.testFn.js +++ b/app/imports/api/engine/computation/utility/propsFromForest.testFn.ts @@ -1,4 +1,12 @@ +import type { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions'; +import { cleanAndValidate } from '/imports/api/utility/TypedSimpleSchema'; + +export type ForestProp = Partial & { + type: CreatureProperty['type']; + children?: ForestProp[]; +} /** * Take a forest of props, which can have sub-props nested in children: [], and return a list of @@ -6,13 +14,13 @@ import { applyNestedSetProperties } from '/imports/api/parenting/parentingFuncti * @param props * @returns */ -export function propsFromForest( - props, +export default function propsFromForest( + props: ForestProp[], creatureId = Random.id(), - parentId = undefined, + parentId?: string, recursionDepth = 0 ) { - const result = []; + const result: CreatureProperty[] = []; props.forEach(prop => { const children = prop.children; // Check the property has a type @@ -32,9 +40,10 @@ export function propsFromForest( doc._id = Random.id(); } delete doc.children; + const creatureProp = cleanAndValidate(CreatureProperties.simpleSchema(doc), doc); // Add the doc to the result and ancestry - result.push(doc); + result.push(creatureProp); if (children) { result.push(...propsFromForest(children, creatureId, doc._id, recursionDepth + 1)); } diff --git a/app/imports/api/engine/loadCreatures.ts b/app/imports/api/engine/loadCreatures.ts index 56519e46..1aec0a56 100644 --- a/app/imports/api/engine/loadCreatures.ts +++ b/app/imports/api/engine/loadCreatures.ts @@ -34,6 +34,13 @@ export function loadCreature(creatureId: string, subscription: Tracker.Computati // logLoadedCreatures() } +export function unloadAllCreatures() { + loadedCreatures.forEach((creature, id) => { + creature.stop(); + loadedCreatures.delete(id); + }); +} + function unloadCreature(creatureId: string, subscription: Tracker.Computation) { if (!creatureId) throw 'creatureId is required'; const creature = loadedCreatures.get(creatureId); @@ -86,20 +93,20 @@ export function getPropertiesOfType(creatureId: string, const creature = loadedCreatures.get(creatureId); if (creature) { const props = Array.from(creature.properties.values()) - .filter(prop => !prop.removed && prop.type === propType) + .filter((prop): prop is CreaturePropertyTypes[T] => !prop.removed && prop.type === propType) .sort((a, b) => a.left - b.left); - return EJSON.clone(props) as unknown as CreaturePropertyTypes[T][]; + return EJSON.clone(props); } // console.time(`Cache miss on creature properties: ${creatureId}`) - const props = CreatureProperties.find({ + const props: CreaturePropertyTypes[T][] = CreatureProperties.find({ 'root.id': creatureId, 'removed': { $ne: true }, - 'type': propType, + 'type': propType as any, }, { sort: { left: 1 }, - }).fetch(); + }).fetch() as unknown as CreaturePropertyTypes[T][]; // console.timeEnd(`Cache miss on creature properties: ${creatureId}`); - return props as unknown as CreaturePropertyTypes[T][]; + return props; } /** @@ -267,6 +274,8 @@ class LoadedCreature { Tracker.nonreactive(() => { self.subs = new Set([sub]); const compute = debounce(Meteor.bindEnvironment(() => { + // It's possible that the creature was unloaded before we get around to computing it + if (!loadedCreatures.has(creatureId)) return; computeCreature(creatureId); }), COMPUTE_DEBOUNCE_TIME); diff --git a/app/imports/api/engine/shared/bulkWrite.ts b/app/imports/api/engine/shared/bulkWrite.ts index 4a9bacd9..f7f404e2 100644 --- a/app/imports/api/engine/shared/bulkWrite.ts +++ b/app/imports/api/engine/shared/bulkWrite.ts @@ -2,7 +2,7 @@ // in the UI because of incompatibility with latency compensation. If the // duplicate redraws can be fixed, this is a strictly better way of processing // writes -export default function bulkWrite(bulkWriteOps, collection): void | Promise { +export default function bulkWrite(bulkWriteOps, collection: Mongo.Collection): void | Promise { if (!bulkWriteOps.length) return; // bulkWrite is only available on the server if (!Meteor.isServer) { diff --git a/app/imports/api/files/userImages/methods/removeUserImage.ts b/app/imports/api/files/userImages/methods/removeUserImage.ts index e81b4b11..473b0757 100644 --- a/app/imports/api/files/userImages/methods/removeUserImage.ts +++ b/app/imports/api/files/userImages/methods/removeUserImage.ts @@ -9,7 +9,7 @@ const removeUserImage = new ValidatedMethod({ validate: new SimpleSchema({ 'fileId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/library/LibraryCollections.js b/app/imports/api/library/LibraryCollections.js index b09912db..4288f9a1 100644 --- a/app/imports/api/library/LibraryCollections.js +++ b/app/imports/api/library/LibraryCollections.js @@ -30,7 +30,7 @@ const LibraryCollectionSchema = new SimpleSchema({ }, 'libraries.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, showInMarket: { index: 1, @@ -78,7 +78,7 @@ const updateLibraryCollection = new ValidatedMethod({ schema: { _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, update: { type: LibraryCollectionSchema diff --git a/app/imports/api/library/LibraryNodes.js b/app/imports/api/library/LibraryNodes.js index c3e4f91d..0231c9e0 100644 --- a/app/imports/api/library/LibraryNodes.js +++ b/app/imports/api/library/LibraryNodes.js @@ -23,7 +23,7 @@ let LibraryNodes = new Mongo.Collection('libraryNodes'); let LibraryNodeSchema = new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, type: { type: String, diff --git a/app/imports/api/library/methods/copyLibraryNodeTo.js b/app/imports/api/library/methods/copyLibraryNodeTo.js index a77f8d39..f3b6eb54 100644 --- a/app/imports/api/library/methods/copyLibraryNodeTo.js +++ b/app/imports/api/library/methods/copyLibraryNodeTo.js @@ -29,7 +29,7 @@ const copyLibraryNodeTo = new ValidatedMethod({ validate: new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, parent: { type: RefSchema, diff --git a/app/imports/api/library/methods/duplicateLibraryNode.js b/app/imports/api/library/methods/duplicateLibraryNode.js index ee8116b9..e91955e4 100644 --- a/app/imports/api/library/methods/duplicateLibraryNode.js +++ b/app/imports/api/library/methods/duplicateLibraryNode.js @@ -24,7 +24,7 @@ const duplicateLibraryNode = new ValidatedMethod({ validate: new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, } }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/library/methods/updateReferenceNode.js b/app/imports/api/library/methods/updateReferenceNode.js index f0303ec0..ee970e4e 100644 --- a/app/imports/api/library/methods/updateReferenceNode.js +++ b/app/imports/api/library/methods/updateReferenceNode.js @@ -13,7 +13,7 @@ const updateReferenceNode = new ValidatedMethod({ validate: new SimpleSchema({ _id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, } }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/parenting/ChildSchema.ts b/app/imports/api/parenting/ChildSchema.ts index 21ad044b..2200b3b7 100644 --- a/app/imports/api/parenting/ChildSchema.ts +++ b/app/imports/api/parenting/ChildSchema.ts @@ -11,7 +11,7 @@ export interface Reference { const RefSchema = TypedSimpleSchema.from({ id: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, collection: { type: String, @@ -25,7 +25,7 @@ const ChildSchema = TypedSimpleSchema.from({ }, 'root.id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, index: 1, }, 'root.collection': { @@ -36,7 +36,7 @@ const ChildSchema = TypedSimpleSchema.from({ // Undefined parent id implies the root is the parent parentId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, /** diff --git a/app/imports/api/parenting/SoftRemovableSchema.js b/app/imports/api/parenting/SoftRemovableSchema.js index 09a64f24..767e4910 100644 --- a/app/imports/api/parenting/SoftRemovableSchema.js +++ b/app/imports/api/parenting/SoftRemovableSchema.js @@ -15,7 +15,7 @@ let SoftRemovableSchema = TypedSimpleSchema.from({ 'removedWith': { optional: true, type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, index: 1, }, }); diff --git a/app/imports/api/properties/Actions.ts b/app/imports/api/properties/Actions.ts index 7d73bb41..bd0238c2 100644 --- a/app/imports/api/properties/Actions.ts +++ b/app/imports/api/properties/Actions.ts @@ -85,7 +85,7 @@ const ActionSchema = createPropertySchema({ }, 'resources.itemsConsumed.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } @@ -100,7 +100,7 @@ const ActionSchema = createPropertySchema({ }, 'resources.itemsConsumed.$.itemId': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, 'resources.attributesConsumed': { @@ -113,7 +113,7 @@ const ActionSchema = createPropertySchema({ }, 'resources.attributesConsumed.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } @@ -137,7 +137,7 @@ const ActionSchema = createPropertySchema({ }, 'resources.conditions.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/properties/Attributes.ts b/app/imports/api/properties/Attributes.ts index 318c1f47..6138f27b 100644 --- a/app/imports/api/properties/Attributes.ts +++ b/app/imports/api/properties/Attributes.ts @@ -247,7 +247,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({ }, 'damageTriggerIds.before.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'damageTriggerIds.after': { type: Array, @@ -255,7 +255,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({ }, 'damageTriggerIds.after.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'damageTriggerIds.afterChildren': { type: Array, @@ -263,7 +263,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({ }, 'damageTriggerIds.afterChildren.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, // Triggers that fire when this property is used to make a check 'checkTriggerIds': { @@ -277,7 +277,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({ }, 'checkTriggerIds.before.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'checkTriggerIds.after': { type: Array, @@ -285,7 +285,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({ }, 'checkTriggerIds.after.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'checkTriggerIds.afterChildren': { type: Array, @@ -293,7 +293,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({ }, 'checkTriggerIds.afterChildren.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }); diff --git a/app/imports/api/properties/Buffs.ts b/app/imports/api/properties/Buffs.ts index 0e2ba08a..69992f57 100644 --- a/app/imports/api/properties/Buffs.ts +++ b/app/imports/api/properties/Buffs.ts @@ -67,7 +67,7 @@ const ComputedOnlyBuffSchema = createPropertySchema({ }, 'appliedBy.id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'appliedBy.collection': { type: String, diff --git a/app/imports/api/properties/Classes.ts b/app/imports/api/properties/Classes.ts index 7596ee3c..e894fdfe 100644 --- a/app/imports/api/properties/Classes.ts +++ b/app/imports/api/properties/Classes.ts @@ -40,7 +40,7 @@ const ClassSchema = createPropertySchema({ }, 'extraTags.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/properties/Items.ts b/app/imports/api/properties/Items.ts index 4cdc7dfe..b1dedaaf 100644 --- a/app/imports/api/properties/Items.ts +++ b/app/imports/api/properties/Items.ts @@ -73,7 +73,7 @@ const ItemSchema = createPropertySchema({ }, 'ammoTriggerIds.before.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'ammoTriggerIds.after': { type: Array, @@ -81,7 +81,7 @@ const ItemSchema = createPropertySchema({ }, 'ammoTriggerIds.after.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'ammoTriggerIds.afterChildren': { type: Array, @@ -89,7 +89,7 @@ const ItemSchema = createPropertySchema({ }, 'ammoTriggerIds.afterChildren.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }); diff --git a/app/imports/api/properties/PointBuys.ts b/app/imports/api/properties/PointBuys.ts index 04bb02c4..61ffc617 100644 --- a/app/imports/api/properties/PointBuys.ts +++ b/app/imports/api/properties/PointBuys.ts @@ -29,7 +29,7 @@ const PointBuySchema = createPropertySchema({ }, 'values.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/properties/Slots.ts b/app/imports/api/properties/Slots.ts index a61485bf..71c91402 100644 --- a/app/imports/api/properties/Slots.ts +++ b/app/imports/api/properties/Slots.ts @@ -37,7 +37,7 @@ const SlotSchema = createPropertySchema({ }, 'extraTags.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/properties/Triggers.ts b/app/imports/api/properties/Triggers.ts index 633a66ad..8dca3261 100644 --- a/app/imports/api/properties/Triggers.ts +++ b/app/imports/api/properties/Triggers.ts @@ -94,7 +94,7 @@ const TriggerSchema = createPropertySchema({ }, 'extraTags.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/properties/subSchemas/AdjustmentSchema.ts b/app/imports/api/properties/subSchemas/AdjustmentSchema.ts index 78f92a01..6b2304f9 100644 --- a/app/imports/api/properties/subSchemas/AdjustmentSchema.ts +++ b/app/imports/api/properties/subSchemas/AdjustmentSchema.ts @@ -4,7 +4,7 @@ import { TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema'; const AdjustmentSchema = TypedSimpleSchema.from({ _id: { type: String, - max: 17, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/properties/subSchemas/TagTargetingSchema.ts b/app/imports/api/properties/subSchemas/TagTargetingSchema.ts index 4c7b940f..db74481e 100644 --- a/app/imports/api/properties/subSchemas/TagTargetingSchema.ts +++ b/app/imports/api/properties/subSchemas/TagTargetingSchema.ts @@ -34,7 +34,7 @@ const TagTargetingSchema = TypedSimpleSchema.from({ }, 'extraTags.$._id': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, autoValue() { if (!this.isSet) return Random.id(); } diff --git a/app/imports/api/sharing/SharingSchema.ts b/app/imports/api/sharing/SharingSchema.ts index e33413ed..6b3a0c8d 100644 --- a/app/imports/api/sharing/SharingSchema.ts +++ b/app/imports/api/sharing/SharingSchema.ts @@ -1,5 +1,6 @@ import SimpleSchema from 'simpl-schema'; import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS'; +import { TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema'; export interface Shared { owner: string, @@ -9,17 +10,15 @@ export interface Shared { readersCanCopy?: true, } -const SharingSchema = new SimpleSchema({ +const SharingSchema = TypedSimpleSchema.from({ owner: { type: String, - regEx: SimpleSchema.RegEx.Id, - //@ts-expect-error index not defined + max: 32, index: 1 }, readers: { type: Array, defaultValue: [], - //@ts-expect-error index not defined index: 1, maxCount: STORAGE_LIMITS.readersCount, }, @@ -30,7 +29,6 @@ const SharingSchema = new SimpleSchema({ writers: { type: Array, defaultValue: [], - //@ts-expect-error index not defined index: 1, maxCount: STORAGE_LIMITS.writersCount, }, @@ -41,7 +39,6 @@ const SharingSchema = new SimpleSchema({ public: { type: Boolean, defaultValue: false, - //@ts-expect-error index not defined index: 1, }, readersCanCopy: { diff --git a/app/imports/api/sharing/sharing.js b/app/imports/api/sharing/sharing.js index 89222dbf..ed6c7611 100644 --- a/app/imports/api/sharing/sharing.js +++ b/app/imports/api/sharing/sharing.js @@ -52,7 +52,7 @@ const updateUserSharePermissions = new ValidatedMethod({ docRef: RefSchema, userId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, role: { type: String, @@ -100,7 +100,7 @@ const transferOwnership = new ValidatedMethod({ docRef: RefSchema, userId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/tabletop/Messages.js b/app/imports/api/tabletop/Messages.js index 07cd270a..f0ac672a 100644 --- a/app/imports/api/tabletop/Messages.js +++ b/app/imports/api/tabletop/Messages.js @@ -9,7 +9,7 @@ let Messages = new Mongo.Collection('messages'); let MessagesSchema = new SimpleSchema({ tabletopId: { type: String, - regEx: SimpleSchema.RegEx.id, + max: 32, }, content: { type: String, @@ -21,7 +21,7 @@ let MessagesSchema = new SimpleSchema({ }, userId: { type: String, - regEx: SimpleSchema.RegEx.id, + max: 32, }, username: { type: String, @@ -41,7 +41,7 @@ const sendMessage = new ValidatedMethod({ }, tabletopId: { type: String, - regEx: SimpleSchema.RegEx.id, + max: 32, }, }).validator(), @@ -77,7 +77,7 @@ const removeMessages = new ValidatedMethod({ validate: new SimpleSchema({ messageId: { type: String, - regEx: SimpleSchema.RegEx.id, + max: 32, }, }).validator(), diff --git a/app/imports/api/tabletop/TabletopMaps.js b/app/imports/api/tabletop/TabletopMaps.js index e315daf8..45a56f50 100644 --- a/app/imports/api/tabletop/TabletopMaps.js +++ b/app/imports/api/tabletop/TabletopMaps.js @@ -10,7 +10,7 @@ let TabletopMapschema = new SimpleSchema({ }, texture: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, position: { type: Object, @@ -36,7 +36,7 @@ let TabletopMapschema = new SimpleSchema({ // If this map was copied from a library map, this ID will be set libraryMapId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, }); diff --git a/app/imports/api/tabletop/TabletopObjects.js b/app/imports/api/tabletop/TabletopObjects.js index 907ef01c..791c4e50 100644 --- a/app/imports/api/tabletop/TabletopObjects.js +++ b/app/imports/api/tabletop/TabletopObjects.js @@ -10,7 +10,7 @@ let TabletopObjectSchema = new SimpleSchema({ }, texture: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, position: { type: Object, diff --git a/app/imports/api/tabletop/Tabletops.ts b/app/imports/api/tabletop/Tabletops.ts index 6b701960..9def2efe 100644 --- a/app/imports/api/tabletop/Tabletops.ts +++ b/app/imports/api/tabletop/Tabletops.ts @@ -35,7 +35,7 @@ const InitiativeSchema = new SimpleSchema({ }, activeCreature: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, }, }); diff --git a/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts b/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts index 13314d28..c15fbd9a 100644 --- a/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts +++ b/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts @@ -22,11 +22,11 @@ const addCreaturesFromLibraryToTabletop = new ValidatedMethod({ }, 'libraryNodeIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, tabletopId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), diff --git a/app/imports/api/tabletop/methods/addCreaturesToTabletop.js b/app/imports/api/tabletop/methods/addCreaturesToTabletop.js index 4f18fdf1..29d47872 100644 --- a/app/imports/api/tabletop/methods/addCreaturesToTabletop.js +++ b/app/imports/api/tabletop/methods/addCreaturesToTabletop.js @@ -18,11 +18,11 @@ const addCreaturesToTabletop = new ValidatedMethod({ }, 'creatureIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, tabletopId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), diff --git a/app/imports/api/tabletop/methods/removeCreatureFromTabletop.ts b/app/imports/api/tabletop/methods/removeCreatureFromTabletop.ts index cd8a50bc..3bda2fc9 100644 --- a/app/imports/api/tabletop/methods/removeCreatureFromTabletop.ts +++ b/app/imports/api/tabletop/methods/removeCreatureFromTabletop.ts @@ -16,14 +16,14 @@ const removeCreatureFromTabletop = new ValidatedMethod({ validate: new SimpleSchema({ tabletopId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, 'creatureIds': { type: Array, }, 'creatureIds.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), diff --git a/app/imports/api/tabletop/methods/removeTabletop.js b/app/imports/api/tabletop/methods/removeTabletop.js index c828651f..cc08ec39 100644 --- a/app/imports/api/tabletop/methods/removeTabletop.js +++ b/app/imports/api/tabletop/methods/removeTabletop.js @@ -13,7 +13,7 @@ const removeTabletop = new ValidatedMethod({ validate: new SimpleSchema({ tabletopId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), diff --git a/app/imports/api/users/Invites.js b/app/imports/api/users/Invites.js index 19799b92..adbc228c 100644 --- a/app/imports/api/users/Invites.js +++ b/app/imports/api/users/Invites.js @@ -8,12 +8,12 @@ let Invites = new Mongo.Collection('invites'); let InviteSchema = new SimpleSchema({ inviter: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, index: 1, }, invitee: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, optional: true, index: 1, }, @@ -89,7 +89,7 @@ const getInviteToken = new ValidatedMethod({ validate: new SimpleSchema({ inviteId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], @@ -160,7 +160,7 @@ const revokeInvite = new ValidatedMethod({ validate: new SimpleSchema({ inviteId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validator(), mixins: [RateLimiterMixin], diff --git a/app/imports/api/users/Users.js b/app/imports/api/users/Users.js index b219eeba..f631ed4b 100644 --- a/app/imports/api/users/Users.js +++ b/app/imports/api/users/Users.js @@ -76,7 +76,7 @@ const userSchema = new SimpleSchema({ }, 'subscribedLibraries.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, subscribedLibraryCollections: { type: Array, @@ -85,7 +85,7 @@ const userSchema = new SimpleSchema({ }, 'subscribedLibraryCollections.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, subscribedCharacters: { type: Array, @@ -94,7 +94,7 @@ const userSchema = new SimpleSchema({ }, 'subscribedCharacters.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, fileStorageUsed: { type: Number, @@ -280,7 +280,7 @@ Meteor.users.subscribeToLibrary = new ValidatedMethod({ validate: new SimpleSchema({ libraryId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, subscribe: { type: Boolean, @@ -312,7 +312,7 @@ Meteor.users.subscribeToLibraryCollection = new ValidatedMethod({ validate: new SimpleSchema({ libraryCollectionId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, subscribe: { type: Boolean, diff --git a/app/imports/api/utility/TypedSimpleSchema.ts b/app/imports/api/utility/TypedSimpleSchema.ts index d0c7e540..93fafe53 100644 --- a/app/imports/api/utility/TypedSimpleSchema.ts +++ b/app/imports/api/utility/TypedSimpleSchema.ts @@ -18,6 +18,9 @@ export class TypedSimpleSchema extends SimpleSchema { static from(definition: D): TypedSimpleSchema> { return new TypedSimpleSchema(definition); } + clean(...args: Parameters): unknown { + return super.clean(...args); + } // Extending the schema with another schema &'s their definitions // In some cases, this is not strictly accurate, use with caution extend(otherSchema: TypedSimpleSchema): TypedSimpleSchema> { @@ -25,11 +28,17 @@ export class TypedSimpleSchema extends SimpleSchema { } } -// It cannot be a method due to https://github.com/microsoft/TypeScript/issues/36931. -export function validate(schema: TypedSimpleSchema, value: unknown): asserts value is T { +// Assertions cannot be methods due to https://github.com/microsoft/TypeScript/issues/36931. +export function validate(schema: TypedSimpleSchema, value: unknown): asserts value is T { schema.validate(value); } +export function cleanAndValidate(schema: TypedSimpleSchema, doc: Partial): T { + const cleanDoc = schema.clean(doc); + validate(schema, cleanDoc); + return cleanDoc; +} + // If this type emerges anywhere in calculations, congratulations! // You've just hit an unimplemented corner case :D type NotImplementedMarker = { readonly NotImplementedMarker: unique symbol }; @@ -62,7 +71,7 @@ export type InferField = ? ArrayMarker extends InferTypeInner ? Array> : ObjectMarker extends InferTypeInner - ? { [L in keyof Def as L extends `${Key}.${infer SubKey}` ? SubKey extends `${string}.${string}` ? never : SubKey : never]: InferOptional> } + ? MakeUndefinedOptional<{ [L in keyof Def as L extends `${Key}.${infer SubKey}` ? SubKey extends `${string}.${string}` ? never : SubKey : never]: InferOptional> }> : Def[Key] extends { allowedValues: infer Allowed extends string[] } ? InferOptional> : Def[Key] extends { type: 'fieldToCompute' } ? FieldToCalculate : Def[Key] extends { type: 'computedOnlyField' } ? CalculatedOnlyField diff --git a/app/imports/server/publications/experiences.js b/app/imports/server/publications/experiences.js index b1165d25..0ec24f12 100644 --- a/app/imports/server/publications/experiences.js +++ b/app/imports/server/publications/experiences.js @@ -6,7 +6,7 @@ import { assertViewPermission } from '/imports/api/creature/creatures/creaturePe let schema = new SimpleSchema({ creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }); diff --git a/app/imports/server/publications/library.js b/app/imports/server/publications/library.js index cddd9feb..5ccd3e42 100644 --- a/app/imports/server/publications/library.js +++ b/app/imports/server/publications/library.js @@ -206,7 +206,7 @@ Meteor.publish('library', function (libraryId) { let libraryIdSchema = new SimpleSchema({ libraryId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }); @@ -254,7 +254,7 @@ Meteor.publish('libraryNodes', function (libraryId, extraFields) { const nodeIdSchema = new SimpleSchema({ libraryNodeId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }); diff --git a/app/imports/server/publications/singleCharacter.js b/app/imports/server/publications/singleCharacter.js index 4511c3cb..c6c0581b 100644 --- a/app/imports/server/publications/singleCharacter.js +++ b/app/imports/server/publications/singleCharacter.js @@ -13,7 +13,7 @@ import EngineActions from '/imports/api/engine/action/EngineActions'; let schema = new SimpleSchema({ creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }); diff --git a/app/imports/server/publications/users.js b/app/imports/server/publications/users.js index 1598f60d..71a4fbee 100644 --- a/app/imports/server/publications/users.js +++ b/app/imports/server/publications/users.js @@ -45,7 +45,7 @@ let userIdsSchema = new SimpleSchema({ }, 'ids.$': { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, } }) diff --git a/app/imports/server/rest/apiPublications/creature.js b/app/imports/server/rest/apiPublications/creature.js index 9c283c5f..ed4060ba 100644 --- a/app/imports/server/rest/apiPublications/creature.js +++ b/app/imports/server/rest/apiPublications/creature.js @@ -14,7 +14,7 @@ JsonRoutes.add('get', 'api/creature/:id', function (req, res) { new SimpleSchema({ creatureId: { type: String, - regEx: SimpleSchema.RegEx.Id, + max: 32, }, }).validate({ creatureId }); } catch (e) {