Take the cross-cutting queries out of the model's base module
findPropertyUsages walks override sites, so Project.ts imported instance.ts while instance.ts imported Project.ts – the repo's only value-level import cycle. The queries now sit in usages.ts and Project.ts is a base type module again. requireScene has had no caller since holderId replaced sceneId. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b13b130da7
commit
a2f2f8465c
7 files changed
+70
-76
No files matched your search
@@ -1,7 +1,4 @@
|
||||
import { schemaForAsset } from '../properties/PropertySchema';
|
||||
import { type Asset, type ContainerAsset, isSceneAsset, type SceneAsset } from './Asset';
|
||||
import { overrideSites } from './instance';
|
||||
import type { SceneObject } from './SceneObject';
|
||||
|
||||
/**
|
||||
* 2 since a placed container stopped copying its template into the scene. Old files are not
|
||||
@@ -62,55 +59,3 @@ export function findObjectHolder(project: Project, holderId: string): ObjectHold
|
||||
export function listContainers(project: Project): ContainerAsset[] {
|
||||
return project.assets.filter((a): a is ContainerAsset => a.type === 'container');
|
||||
}
|
||||
|
||||
export interface SceneObjectRef {
|
||||
holder: ObjectHolder;
|
||||
object: SceneObject;
|
||||
}
|
||||
|
||||
export function objectsWhere(
|
||||
project: Project,
|
||||
predicate: (object: SceneObject) => boolean,
|
||||
): SceneObjectRef[] {
|
||||
const result: SceneObjectRef[] = [];
|
||||
for (const holder of objectHolders(project)) {
|
||||
for (const object of holder.objects) if (predicate(object)) result.push({ holder, object });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Every placed instance of an asset, in scenes and in container templates alike. */
|
||||
export function findUsages(project: Project, assetId: string): SceneObjectRef[] {
|
||||
return objectsWhere(project, (o) => o.assetId === assetId);
|
||||
}
|
||||
|
||||
export type PropertyUsage =
|
||||
| { on: 'asset'; asset: Asset; key: string }
|
||||
/** `path` is empty for a placed object's own override, set for one a container instance keeps. */
|
||||
| { on: 'object'; holder: ObjectHolder; object: SceneObject; path: string; key: string };
|
||||
|
||||
/**
|
||||
* The other half of "where is this asset used": a texture is never placed, it is worn through a
|
||||
* sprite's `texture` property, so counting uses needs this as well as `findUsages`. Several ids
|
||||
* because every frame cut from a texture is a reference to the same picture (see `textureRefIds`).
|
||||
*/
|
||||
export function findPropertyUsages(project: Project, ids: string | readonly string[]): PropertyUsage[] {
|
||||
const wanted = new Set((typeof ids === 'string' ? [ids] : ids).filter(Boolean));
|
||||
if (wanted.size === 0) return [];
|
||||
const result: PropertyUsage[] = [];
|
||||
const refKeys = new Map<string, string[]>();
|
||||
const matches = (value: unknown): boolean => typeof value === 'string' && wanted.has(value);
|
||||
for (const asset of project.assets) {
|
||||
const keys = schemaForAsset(asset)
|
||||
.filter((def) => def.kind === 'asset' || def.kind === 'texture')
|
||||
.map((def) => def.key);
|
||||
refKeys.set(asset.id, keys);
|
||||
for (const key of keys) if (matches(asset.props[key])) result.push({ on: 'asset', asset, key });
|
||||
}
|
||||
for (const site of overrideSites(project, () => true)) {
|
||||
for (const key of refKeys.get(site.assetId) ?? [])
|
||||
if (matches(site.bag[key]))
|
||||
result.push({ on: 'object', holder: site.holder, object: site.object, path: site.path, key });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -256,8 +256,6 @@ export function instanceTargetOf(
|
||||
};
|
||||
}
|
||||
|
||||
// --- writing -----------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Read/write access to a placed object, whether it is stored in the holder or resolved from a
|
||||
* container template. `object` is the current state either way; the setters keep an instance edit
|
||||
@@ -421,8 +419,6 @@ export function overrideSites(project: Project, wanted: (assetId: string) => boo
|
||||
return sites;
|
||||
}
|
||||
|
||||
// --- unpacking ---------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The resolved content of an instance as objects that can be stored. The derived ids are kept:
|
||||
* they are unique already, and anything pointing at one – the selection, a running game, a check
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* "Where is this asset used" – across scenes and container templates alike. Kept out of
|
||||
* `Project.ts` so that module stays free of the property schema and of container instancing:
|
||||
* both of those already import it, and answering this question needs both.
|
||||
*/
|
||||
import { schemaForAsset } from '../properties/PropertySchema';
|
||||
import type { Asset } from './Asset';
|
||||
import { overrideSites } from './instance';
|
||||
import { type ObjectHolder, objectHolders, type Project } from './Project';
|
||||
import type { SceneObject } from './SceneObject';
|
||||
|
||||
export interface SceneObjectRef {
|
||||
holder: ObjectHolder;
|
||||
object: SceneObject;
|
||||
}
|
||||
|
||||
export function objectsWhere(
|
||||
project: Project,
|
||||
predicate: (object: SceneObject) => boolean,
|
||||
): SceneObjectRef[] {
|
||||
const result: SceneObjectRef[] = [];
|
||||
for (const holder of objectHolders(project)) {
|
||||
for (const object of holder.objects) if (predicate(object)) result.push({ holder, object });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Every placed instance of an asset, in scenes and in container templates alike. */
|
||||
export function findUsages(project: Project, assetId: string): SceneObjectRef[] {
|
||||
return objectsWhere(project, (o) => o.assetId === assetId);
|
||||
}
|
||||
|
||||
export type PropertyUsage =
|
||||
| { on: 'asset'; asset: Asset; key: string }
|
||||
/** `path` is empty for a placed object's own override, set for one a container instance keeps. */
|
||||
| { on: 'object'; holder: ObjectHolder; object: SceneObject; path: string; key: string };
|
||||
|
||||
/**
|
||||
* The other half of "where is this asset used": a texture is never placed, it is worn through a
|
||||
* sprite's `texture` property, so counting uses needs this as well as `findUsages`. Several ids
|
||||
* because every frame cut from a texture is a reference to the same picture (see `textureRefIds`).
|
||||
*/
|
||||
export function findPropertyUsages(project: Project, ids: string | readonly string[]): PropertyUsage[] {
|
||||
const wanted = new Set((typeof ids === 'string' ? [ids] : ids).filter(Boolean));
|
||||
if (wanted.size === 0) return [];
|
||||
const result: PropertyUsage[] = [];
|
||||
const refKeys = new Map<string, string[]>();
|
||||
const matches = (value: unknown): boolean => typeof value === 'string' && wanted.has(value);
|
||||
for (const asset of project.assets) {
|
||||
const keys = schemaForAsset(asset)
|
||||
.filter((def) => def.kind === 'asset' || def.kind === 'texture')
|
||||
.map((def) => def.key);
|
||||
refKeys.set(asset.id, keys);
|
||||
for (const key of keys) if (matches(asset.props[key])) result.push({ on: 'asset', asset, key });
|
||||
}
|
||||
for (const site of overrideSites(project, () => true)) {
|
||||
for (const key of refKeys.get(site.assetId) ?? [])
|
||||
if (matches(site.bag[key]))
|
||||
result.push({ on: 'object', holder: site.holder, object: site.object, path: site.path, key });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user