Added some railguards to the API
This commit is contained in:
parent
9955730876
commit
a3bec04088
6 changed files with 52 additions and 20 deletions
|
@ -10,12 +10,44 @@ import * as types from '@theatre/core/propTypes'
|
||||||
import {InvalidArgumentError} from '@theatre/shared/utils/errors'
|
import {InvalidArgumentError} from '@theatre/shared/utils/errors'
|
||||||
import {validateName} from '@theatre/shared/utils/sanitizers'
|
import {validateName} from '@theatre/shared/utils/sanitizers'
|
||||||
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
|
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
|
||||||
|
import deepEqual from 'fast-deep-equal'
|
||||||
export {types}
|
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 {
|
export function getProject(id: string, config: IProjectConfig = {}): IProject {
|
||||||
const {...restOfConfig} = config
|
const {...restOfConfig} = config
|
||||||
if (projectsSingleton.has(id)) {
|
const existingProject = projectsSingleton.get(id)
|
||||||
return projectsSingleton.get(id)!.publicApi
|
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') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
|
|
@ -91,7 +91,7 @@ describe(`SheetObject`, () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const seq = sheet.publicApi.sequence()
|
const seq = sheet.publicApi.sequence
|
||||||
|
|
||||||
const objValues = iterateOver(
|
const objValues = iterateOver(
|
||||||
prism(() => {
|
prism(() => {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import trackValueAtTime from '@theatre/core/sequences/trackValueAtTime'
|
import trackValueAtTime from '@theatre/core/sequences/trackValueAtTime'
|
||||||
import type Sheet from '@theatre/core/sheets/Sheet'
|
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 type {SheetObjectAddress} from '@theatre/shared/utils/addresses'
|
||||||
import deepMergeWithCache from '@theatre/shared/utils/deepMergeWithCache'
|
import deepMergeWithCache from '@theatre/shared/utils/deepMergeWithCache'
|
||||||
import type {SequenceTrackId} from '@theatre/shared/utils/ids'
|
import type {SequenceTrackId} from '@theatre/shared/utils/ids'
|
||||||
|
@ -53,17 +52,6 @@ export default class SheetObject implements IdentityDerivationProvider {
|
||||||
this.publicApi = new TheatreSheetObject(this)
|
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>> {
|
getValues(): IDerivation<Pointer<SerializableMap>> {
|
||||||
return this._cache.get('getValues()', () =>
|
return this._cache.get('getValues()', () =>
|
||||||
prism(() => {
|
prism(() => {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {InvalidArgumentError} from '@theatre/shared/utils/errors'
|
||||||
import {validateAndSanitiseSlashedPathOrThrow} from '@theatre/shared/utils/slashedPaths'
|
import {validateAndSanitiseSlashedPathOrThrow} from '@theatre/shared/utils/slashedPaths'
|
||||||
import type {$IntentionalAny} from '@theatre/shared/utils/types'
|
import type {$IntentionalAny} from '@theatre/shared/utils/types'
|
||||||
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
|
import userReadableTypeOfValue from '@theatre/shared/utils/userReadableTypeOfValue'
|
||||||
|
import deepEqual from 'fast-deep-equal'
|
||||||
|
|
||||||
export type SheetObjectConfig<
|
export type SheetObjectConfig<
|
||||||
Props extends PropTypeConfig_Compound<$IntentionalAny>,
|
Props extends PropTypeConfig_Compound<$IntentionalAny>,
|
||||||
|
@ -25,7 +26,7 @@ export interface ISheet {
|
||||||
config: SheetObjectConfig<Props>,
|
config: SheetObjectConfig<Props>,
|
||||||
): ISheetObject<Props>
|
): ISheetObject<Props>
|
||||||
|
|
||||||
sequence(): ISequence
|
readonly sequence: ISequence
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class TheatreSheet implements ISheet {
|
export default class TheatreSheet implements ISheet {
|
||||||
|
@ -49,14 +50,21 @@ export default class TheatreSheet implements ISheet {
|
||||||
`sheet.object("${key}", ...)`,
|
`sheet.object("${key}", ...)`,
|
||||||
)
|
)
|
||||||
|
|
||||||
// @todo sanitize config
|
|
||||||
|
|
||||||
const existingObject = internal.getObject(sanitizedPath)
|
const existingObject = internal.getObject(sanitizedPath)
|
||||||
|
|
||||||
const nativeObject = null
|
const nativeObject = null
|
||||||
|
|
||||||
if (existingObject) {
|
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
|
return existingObject.publicApi as $IntentionalAny
|
||||||
} else {
|
} else {
|
||||||
const object = internal.createObject(sanitizedPath, nativeObject, config)
|
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
|
return privateAPI(this).getSequence().publicApi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,5 +87,8 @@
|
||||||
"typescript": "^4.4.2",
|
"typescript": "^4.4.2",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22697,6 +22697,7 @@ fsevents@^1.2.7:
|
||||||
esbuild-loader: ^2.13.1
|
esbuild-loader: ^2.13.1
|
||||||
esbuild-register: ^2.5.0
|
esbuild-register: ^2.5.0
|
||||||
exec-loader: ^4.0.0
|
exec-loader: ^4.0.0
|
||||||
|
fast-deep-equal: ^3.1.3
|
||||||
file-loader: ^6.2.0
|
file-loader: ^6.2.0
|
||||||
fs-extra: ^10.0.0
|
fs-extra: ^10.0.0
|
||||||
html-loader: ^2.1.2
|
html-loader: ^2.1.2
|
||||||
|
|
Loading…
Reference in a new issue