Added some railguards to the API

This commit is contained in:
Aria Minaei 2021-09-03 21:20:05 +02:00
parent 9955730876
commit a3bec04088
6 changed files with 52 additions and 20 deletions

View file

@ -10,12 +10,44 @@ import * as types from '@theatre/core/propTypes'
import {InvalidArgumentError} from '@theatre/shared/utils/errors'
import {validateName} from '@theatre/shared/utils/sanitizers'
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
import deepEqual from 'fast-deep-equal'
export {types}
/**
* Returns a project of the given id, or creates one if it doesn't already exist.
*
* If @theatre/studio is also loaded, then the state of the project will be managed by the studio.
*
* Usage:
* ```ts
* import {getProject} from '@theatre/core'
* const config = {} // the config can be empty when starting a new project
* const project = getProject("a-unique-id", config)
* ```
*
* Usage with an explicit state:
* ```ts
* import {getProject} from '@theatre/core'
* import state from './saved-state.json'
* const config = {state} // here the config contains our saved state
* const project = getProject("a-unique-id", config)
* ```
*/
export function getProject(id: string, config: IProjectConfig = {}): IProject {
const {...restOfConfig} = config
if (projectsSingleton.has(id)) {
return projectsSingleton.get(id)!.publicApi
const existingProject = projectsSingleton.get(id)
if (existingProject) {
if (process.env.NODE_ENV !== 'production') {
if (!deepEqual(config, existingProject.config)) {
throw new Error(
`You seem to have called Theatre.getProject("${id}", config) twice, with different config objects. ` +
`This is disallowed because changing the config of a project on the fly can lead to hard-to-debug issues.\n\n` +
`You can fix this by either calling Theatre.getProject() once per project-id,` +
` or calling it multiple times but with the exact same config.`,
)
}
}
return existingProject.publicApi
}
if (process.env.NODE_ENV !== 'production') {

View file

@ -91,7 +91,7 @@ describe(`SheetObject`, () => {
},
})
const seq = sheet.publicApi.sequence()
const seq = sheet.publicApi.sequence
const objValues = iterateOver(
prism(() => {

View file

@ -1,6 +1,5 @@
import trackValueAtTime from '@theatre/core/sequences/trackValueAtTime'
import type Sheet from '@theatre/core/sheets/Sheet'
import type {SheetObjectConfig} from '@theatre/core/sheets/TheatreSheet'
import type {SheetObjectAddress} from '@theatre/shared/utils/addresses'
import deepMergeWithCache from '@theatre/shared/utils/deepMergeWithCache'
import type {SequenceTrackId} from '@theatre/shared/utils/ids'
@ -53,17 +52,6 @@ export default class SheetObject implements IdentityDerivationProvider {
this.publicApi = new TheatreSheetObject(this)
}
overrideConfig(
nativeObject: unknown,
config: SheetObjectConfig<$IntentionalAny>,
) {
if (nativeObject !== this.nativeObject) {
// @todo
}
this.template.overrideConfig(nativeObject, config)
}
getValues(): IDerivation<Pointer<SerializableMap>> {
return this._cache.get('getValues()', () =>
prism(() => {

View file

@ -10,6 +10,7 @@ import {InvalidArgumentError} from '@theatre/shared/utils/errors'
import {validateAndSanitiseSlashedPathOrThrow} from '@theatre/shared/utils/slashedPaths'
import type {$IntentionalAny} from '@theatre/shared/utils/types'
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
import deepEqual from 'fast-deep-equal'
export type SheetObjectConfig<
Props extends PropTypeConfig_Compound<$IntentionalAny>,
@ -25,7 +26,7 @@ export interface ISheet {
config: SheetObjectConfig<Props>,
): ISheetObject<Props>
sequence(): ISequence
readonly sequence: ISequence
}
export default class TheatreSheet implements ISheet {
@ -49,14 +50,21 @@ export default class TheatreSheet implements ISheet {
`sheet.object("${key}", ...)`,
)
// @todo sanitize config
const existingObject = internal.getObject(sanitizedPath)
const nativeObject = null
if (existingObject) {
existingObject.overrideConfig(nativeObject, config)
if (process.env.NODE_ENV !== 'production') {
if (!deepEqual(config, existingObject.template.config)) {
throw new Error(
`You seem to have called sheet.object("${key}", config) twice, with different values for \`config\`. ` +
`This is disallowed because changing the config of an object on the fly would make it difficult to reason about.\n\n` +
`You can fix this by either re-using the existing object, or calling sheet.object("${key}", config) with the same config.`,
)
}
}
return existingObject.publicApi as $IntentionalAny
} else {
const object = internal.createObject(sanitizedPath, nativeObject, config)
@ -64,7 +72,7 @@ export default class TheatreSheet implements ISheet {
}
}
sequence(): TheatreSequence {
get sequence(): TheatreSequence {
return privateAPI(this).getSequence().publicApi
}

View file

@ -87,5 +87,8 @@
"typescript": "^4.4.2",
"url-loader": "^4.1.1",
"uuid": "^8.3.2"
},
"dependencies": {
"fast-deep-equal": "^3.1.3"
}
}

View file

@ -22697,6 +22697,7 @@ fsevents@^1.2.7:
esbuild-loader: ^2.13.1
esbuild-register: ^2.5.0
exec-loader: ^4.0.0
fast-deep-equal: ^3.1.3
file-loader: ^6.2.0
fs-extra: ^10.0.0
html-loader: ^2.1.2