@babylonjs/loaders 9.20.0 → 9.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/SPLAT/gaussianSplattingStream.d.ts +170 -1
  2. package/SPLAT/gaussianSplattingStream.js +516 -40
  3. package/SPLAT/gaussianSplattingStream.js.map +1 -1
  4. package/SPLAT/gaussianSplattingWorkBuffer.d.ts +163 -4
  5. package/SPLAT/gaussianSplattingWorkBuffer.js +683 -35
  6. package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -1
  7. package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +70 -2
  8. package/SPLAT/gaussianSplattingWorkBufferShaders.js +465 -4
  9. package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -1
  10. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +16 -1
  11. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +232 -25
  12. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
  13. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +52 -2
  14. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +108 -7
  15. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
  16. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +37 -0
  17. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +69 -0
  18. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -0
  19. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.d.ts +44 -0
  20. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js +51 -0
  21. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js.map +1 -0
  22. package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +1 -0
  23. package/glTF/2.0/Extensions/KHR_interactivity.pure.js +143 -12
  24. package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
  25. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +6 -0
  26. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
  27. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +4 -0
  28. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
  29. package/glTF/2.0/Extensions/KHR_node_visibility.pure.js +11 -0
  30. package/glTF/2.0/Extensions/KHR_node_visibility.pure.js.map +1 -1
  31. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.d.ts +126 -0
  32. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js +251 -0
  33. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js.map +1 -0
  34. package/glTF/2.0/Extensions/compositePathToObjectConverter.d.ts +51 -0
  35. package/glTF/2.0/Extensions/compositePathToObjectConverter.js +51 -0
  36. package/glTF/2.0/Extensions/compositePathToObjectConverter.js.map +1 -0
  37. package/glTF/2.0/Extensions/gltfPathToObjectConverter.js +69 -7
  38. package/glTF/2.0/Extensions/gltfPathToObjectConverter.js.map +1 -1
  39. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.d.ts +41 -0
  40. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js +108 -0
  41. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js.map +1 -0
  42. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.d.ts +28 -0
  43. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +71 -0
  44. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -0
  45. package/glTF/2.0/Extensions/objectModelMapping.d.ts +118 -30
  46. package/glTF/2.0/Extensions/objectModelMapping.js +472 -70
  47. package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
  48. package/glTF/2.0/glTFLoader.pure.js +2 -1
  49. package/glTF/2.0/glTFLoader.pure.js.map +1 -1
  50. package/package.json +3 -3
@@ -8,6 +8,24 @@ export const OptionalPathExceptionsList = [
8
8
  // get the node as object when reading an extension
9
9
  regex: new RegExp(`^/nodes/\\d+/extensions/`),
10
10
  },
11
+ {
12
+ // KHR_interactivity animation pointers (e.g. /animations/{}/extensions/KHR_interactivity/maxTime)
13
+ // are virtual: they are computed from the Babylon animation group and are not stored in the
14
+ // glTF JSON, so the animation object has no `extensions` member to traverse into.
15
+ regex: new RegExp(`^/animations/\\d+/extensions/`),
16
+ },
17
+ {
18
+ // weights may be undefined on nodes without morph targets
19
+ regex: new RegExp(`^/nodes/\\d+/weights`),
20
+ },
21
+ {
22
+ // weights may be undefined on meshes without morph targets
23
+ regex: new RegExp(`^/meshes/\\d+/weights`),
24
+ },
25
+ {
26
+ // KHR_texture_transform may not be present on texture info objects
27
+ regex: new RegExp(`/extensions/KHR_texture_transform/`),
28
+ },
11
29
  ];
12
30
  /**
13
31
  * A converter that takes a glTF Object Model JSON Pointer
@@ -61,13 +79,29 @@ export class GLTFPathToObjectConverter {
61
79
  let ignoreObjectTree = false;
62
80
  for (const part of parts) {
63
81
  const isLength = part === "length";
64
- if (isLength && !infoTree.__array__) {
65
- throw new Error(`Path ${path} is invalid`);
82
+ if (isLength) {
83
+ // For .length, check if the current level has a 'length' accessor
84
+ if (infoTree.length) {
85
+ infoTree = infoTree.length;
86
+ }
87
+ else if (infoTree.__array__) {
88
+ // Fallback: length of an array that doesn't have explicit length accessor
89
+ throw new Error(`Path ${path} is invalid - no length accessor`);
90
+ }
91
+ else {
92
+ throw new Error(`Path ${path} is invalid`);
93
+ }
94
+ // Set target to the current object tree (the array itself)
95
+ // Only update target if objectTree is defined, otherwise keep the last valid target
96
+ if (objectTree !== undefined) {
97
+ target = objectTree;
98
+ }
99
+ continue;
66
100
  }
67
101
  if (infoTree.__ignoreObjectTree__) {
68
102
  ignoreObjectTree = true;
69
103
  }
70
- if (infoTree.__array__ && !isLength) {
104
+ if (infoTree.__array__) {
71
105
  infoTree = infoTree.__array__;
72
106
  }
73
107
  else {
@@ -76,7 +110,13 @@ export class GLTFPathToObjectConverter {
76
110
  throw new Error(`Path ${path} is invalid`);
77
111
  }
78
112
  }
79
- if (!ignoreObjectTree) {
113
+ // __passThroughTarget__: skip objectTree traversal for this property.
114
+ // The accessor functions will receive the parent target (e.g., the INode)
115
+ // instead of the child property (e.g., node.weights which may be undefined).
116
+ if (infoTree.__passThroughTarget__) {
117
+ ignoreObjectTree = true;
118
+ }
119
+ else if (!ignoreObjectTree) {
80
120
  if (objectTree === undefined) {
81
121
  // check if the path is in the exception list. If it is, break and return the last object that was found
82
122
  const exception = OptionalPathExceptionsList.find((e) => e.regex.test(path));
@@ -84,12 +124,34 @@ export class GLTFPathToObjectConverter {
84
124
  throw new Error(`Path ${path} is invalid`);
85
125
  }
86
126
  }
87
- else if (!isLength) {
127
+ else {
88
128
  objectTree = objectTree?.[part];
89
129
  }
90
130
  }
91
- if (infoTree.__target__ || isLength) {
92
- target = objectTree;
131
+ else {
132
+ // When ignoring object tree traversal and encountering a numeric array index,
133
+ // wrap the accessor functions to pass the index through as the second argument.
134
+ // The remaining arguments are forwarded unchanged so context-aware accessors, which
135
+ // receive the runtime context as their payload, keep working. Require an all-digits
136
+ // segment: parseInt would otherwise accept "1/foo" as 1 and bind to the wrong index.
137
+ const numericIndex = /^\d+$/.test(part) ? parseInt(part, 10) : NaN;
138
+ if (!isNaN(numericIndex) && typeof infoTree.get === "function") {
139
+ const orig = infoTree;
140
+ infoTree = { ...orig };
141
+ infoTree.get = (target, _index, ...rest) => orig.get(target, numericIndex, ...rest);
142
+ if (typeof orig.set === "function") {
143
+ infoTree.set = (value, target, _index, ...rest) => orig.set(value, target, numericIndex, ...rest);
144
+ }
145
+ if (typeof orig.getTarget === "function") {
146
+ infoTree.getTarget = (target, _index, ...rest) => orig.getTarget(target, numericIndex, ...rest);
147
+ }
148
+ }
149
+ }
150
+ if (infoTree.__target__) {
151
+ // Only update target if objectTree is defined, otherwise keep the last valid target
152
+ if (objectTree !== undefined) {
153
+ target = objectTree;
154
+ }
93
155
  }
94
156
  }
95
157
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"gltfPathToObjectConverter.js","sourceRoot":"","sources":["../../../../../../dev/loaders/src/glTF/2.0/Extensions/gltfPathToObjectConverter.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IObjectInfo, type IPathToObjectConverter } from \"core/ObjectModel/objectModelInterfaces\";\r\nimport { type IGLTF } from \"../glTFLoaderInterfaces\";\r\nimport { type IObjectAccessor } from \"core/FlowGraph/typeDefinitions\";\r\n\r\n/**\r\n * Adding an exception here will break traversing through the glTF object tree.\r\n * This is used for properties that might not be in the glTF object model, but are optional and have a default value.\r\n * For example, the path /nodes/\\{\\}/extensions/KHR_node_visibility/visible is optional - the object can be deferred without the object fully existing.\r\n */\r\nexport const OptionalPathExceptionsList: {\r\n regex: RegExp;\r\n}[] = [\r\n {\r\n // get the node as object when reading an extension\r\n regex: new RegExp(`^/nodes/\\\\d+/extensions/`),\r\n },\r\n];\r\n\r\n/**\r\n * A converter that takes a glTF Object Model JSON Pointer\r\n * and transforms it into an ObjectAccessorContainer, allowing\r\n * objects referenced in the glTF to be associated with their\r\n * respective Babylon.js objects.\r\n */\r\nexport class GLTFPathToObjectConverter<T, BabylonType, BabylonValue> implements IPathToObjectConverter<IObjectAccessor<T, BabylonType, BabylonValue>> {\r\n public constructor(\r\n private _gltf: IGLTF,\r\n private _infoTree: any\r\n ) {}\r\n\r\n /**\r\n * The pointer string is represented by a [JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901).\r\n * See also https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/ObjectModel.adoc#core-pointers\r\n * <animationPointer> := /<rootNode>/<assetIndex>/<propertyPath>\r\n * <rootNode> := \"nodes\" | \"materials\" | \"meshes\" | \"cameras\" | \"extensions\"\r\n * <assetIndex> := <digit> | <name>\r\n * <propertyPath> := <extensionPath> | <standardPath>\r\n * <extensionPath> := \"extensions\"/<name>/<standardPath>\r\n * <standardPath> := <name> | <name>/<standardPath>\r\n * <name> := W+\r\n * <digit> := D+\r\n *\r\n * Examples:\r\n * - \"/nodes/0/rotation\"\r\n * - \"/nodes.length\"\r\n * - \"/materials/2/emissiveFactor\"\r\n * - \"/materials/2/pbrMetallicRoughness/baseColorFactor\"\r\n * - \"/materials/2/extensions/KHR_materials_emissive_strength/emissiveStrength\"\r\n *\r\n * @param path The path to convert\r\n * @returns The object and info associated with the path\r\n */\r\n public convert(path: string): IObjectInfo<IObjectAccessor<T, BabylonType, BabylonValue>> {\r\n let objectTree: any = this._gltf;\r\n let infoTree: any = this._infoTree;\r\n let target: any = undefined;\r\n\r\n if (!path.startsWith(\"/\")) {\r\n throw new Error(\"Path must start with a /\");\r\n }\r\n const parts = path.split(\"/\");\r\n parts.shift();\r\n\r\n //if the last part has \".length\" in it, separate that as an extra part\r\n if (parts[parts.length - 1].includes(\".length\")) {\r\n const lastPart = parts[parts.length - 1];\r\n const split = lastPart.split(\".\");\r\n parts.pop();\r\n parts.push(...split);\r\n }\r\n\r\n let ignoreObjectTree = false;\r\n\r\n for (const part of parts) {\r\n const isLength = part === \"length\";\r\n if (isLength && !infoTree.__array__) {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n if (infoTree.__ignoreObjectTree__) {\r\n ignoreObjectTree = true;\r\n }\r\n if (infoTree.__array__ && !isLength) {\r\n infoTree = infoTree.__array__;\r\n } else {\r\n infoTree = infoTree[part];\r\n if (!infoTree) {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n }\r\n if (!ignoreObjectTree) {\r\n if (objectTree === undefined) {\r\n // check if the path is in the exception list. If it is, break and return the last object that was found\r\n const exception = OptionalPathExceptionsList.find((e) => e.regex.test(path));\r\n if (!exception) {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n } else if (!isLength) {\r\n objectTree = objectTree?.[part];\r\n }\r\n }\r\n\r\n if (infoTree.__target__ || isLength) {\r\n target = objectTree;\r\n }\r\n }\r\n\r\n return {\r\n object: target,\r\n info: infoTree,\r\n };\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"gltfPathToObjectConverter.js","sourceRoot":"","sources":["../../../../../../dev/loaders/src/glTF/2.0/Extensions/gltfPathToObjectConverter.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IObjectInfo, type IPathToObjectConverter } from \"core/ObjectModel/objectModelInterfaces\";\r\nimport { type IGLTF } from \"../glTFLoaderInterfaces\";\r\nimport { type IObjectAccessor } from \"core/FlowGraph/typeDefinitions\";\r\n\r\n/**\r\n * Adding an exception here will break traversing through the glTF object tree.\r\n * This is used for properties that might not be in the glTF object model, but are optional and have a default value.\r\n * For example, the path /nodes/\\{\\}/extensions/KHR_node_visibility/visible is optional - the object can be deferred without the object fully existing.\r\n */\r\nexport const OptionalPathExceptionsList: {\r\n regex: RegExp;\r\n}[] = [\r\n {\r\n // get the node as object when reading an extension\r\n regex: new RegExp(`^/nodes/\\\\d+/extensions/`),\r\n },\r\n {\r\n // KHR_interactivity animation pointers (e.g. /animations/{}/extensions/KHR_interactivity/maxTime)\r\n // are virtual: they are computed from the Babylon animation group and are not stored in the\r\n // glTF JSON, so the animation object has no `extensions` member to traverse into.\r\n regex: new RegExp(`^/animations/\\\\d+/extensions/`),\r\n },\r\n {\r\n // weights may be undefined on nodes without morph targets\r\n regex: new RegExp(`^/nodes/\\\\d+/weights`),\r\n },\r\n {\r\n // weights may be undefined on meshes without morph targets\r\n regex: new RegExp(`^/meshes/\\\\d+/weights`),\r\n },\r\n {\r\n // KHR_texture_transform may not be present on texture info objects\r\n regex: new RegExp(`/extensions/KHR_texture_transform/`),\r\n },\r\n];\r\n\r\n/**\r\n * A converter that takes a glTF Object Model JSON Pointer\r\n * and transforms it into an ObjectAccessorContainer, allowing\r\n * objects referenced in the glTF to be associated with their\r\n * respective Babylon.js objects.\r\n */\r\nexport class GLTFPathToObjectConverter<T, BabylonType, BabylonValue> implements IPathToObjectConverter<IObjectAccessor<T, BabylonType, BabylonValue>> {\r\n public constructor(\r\n private _gltf: IGLTF,\r\n private _infoTree: any\r\n ) {}\r\n\r\n /**\r\n * The pointer string is represented by a [JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901).\r\n * See also https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/ObjectModel.adoc#core-pointers\r\n * <animationPointer> := /<rootNode>/<assetIndex>/<propertyPath>\r\n * <rootNode> := \"nodes\" | \"materials\" | \"meshes\" | \"cameras\" | \"extensions\"\r\n * <assetIndex> := <digit> | <name>\r\n * <propertyPath> := <extensionPath> | <standardPath>\r\n * <extensionPath> := \"extensions\"/<name>/<standardPath>\r\n * <standardPath> := <name> | <name>/<standardPath>\r\n * <name> := W+\r\n * <digit> := D+\r\n *\r\n * Examples:\r\n * - \"/nodes/0/rotation\"\r\n * - \"/nodes.length\"\r\n * - \"/materials/2/emissiveFactor\"\r\n * - \"/materials/2/pbrMetallicRoughness/baseColorFactor\"\r\n * - \"/materials/2/extensions/KHR_materials_emissive_strength/emissiveStrength\"\r\n *\r\n * @param path The path to convert\r\n * @returns The object and info associated with the path\r\n */\r\n public convert(path: string): IObjectInfo<IObjectAccessor<T, BabylonType, BabylonValue>> {\r\n let objectTree: any = this._gltf;\r\n let infoTree: any = this._infoTree;\r\n let target: any = undefined;\r\n\r\n if (!path.startsWith(\"/\")) {\r\n throw new Error(\"Path must start with a /\");\r\n }\r\n const parts = path.split(\"/\");\r\n parts.shift();\r\n\r\n //if the last part has \".length\" in it, separate that as an extra part\r\n if (parts[parts.length - 1].includes(\".length\")) {\r\n const lastPart = parts[parts.length - 1];\r\n const split = lastPart.split(\".\");\r\n parts.pop();\r\n parts.push(...split);\r\n }\r\n\r\n let ignoreObjectTree = false;\r\n\r\n for (const part of parts) {\r\n const isLength = part === \"length\";\r\n if (isLength) {\r\n // For .length, check if the current level has a 'length' accessor\r\n if (infoTree.length) {\r\n infoTree = infoTree.length;\r\n } else if (infoTree.__array__) {\r\n // Fallback: length of an array that doesn't have explicit length accessor\r\n throw new Error(`Path ${path} is invalid - no length accessor`);\r\n } else {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n // Set target to the current object tree (the array itself)\r\n // Only update target if objectTree is defined, otherwise keep the last valid target\r\n if (objectTree !== undefined) {\r\n target = objectTree;\r\n }\r\n continue;\r\n }\r\n if (infoTree.__ignoreObjectTree__) {\r\n ignoreObjectTree = true;\r\n }\r\n if (infoTree.__array__) {\r\n infoTree = infoTree.__array__;\r\n } else {\r\n infoTree = infoTree[part];\r\n if (!infoTree) {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n }\r\n // __passThroughTarget__: skip objectTree traversal for this property.\r\n // The accessor functions will receive the parent target (e.g., the INode)\r\n // instead of the child property (e.g., node.weights which may be undefined).\r\n if (infoTree.__passThroughTarget__) {\r\n ignoreObjectTree = true;\r\n } else if (!ignoreObjectTree) {\r\n if (objectTree === undefined) {\r\n // check if the path is in the exception list. If it is, break and return the last object that was found\r\n const exception = OptionalPathExceptionsList.find((e) => e.regex.test(path));\r\n if (!exception) {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n } else {\r\n objectTree = objectTree?.[part];\r\n }\r\n } else {\r\n // When ignoring object tree traversal and encountering a numeric array index,\r\n // wrap the accessor functions to pass the index through as the second argument.\r\n // The remaining arguments are forwarded unchanged so context-aware accessors, which\r\n // receive the runtime context as their payload, keep working. Require an all-digits\r\n // segment: parseInt would otherwise accept \"1/foo\" as 1 and bind to the wrong index.\r\n const numericIndex = /^\\d+$/.test(part) ? parseInt(part, 10) : NaN;\r\n if (!isNaN(numericIndex) && typeof infoTree.get === \"function\") {\r\n const orig = infoTree;\r\n infoTree = { ...orig };\r\n infoTree.get = (target: any, _index?: number, ...rest: any[]) => orig.get(target, numericIndex, ...rest);\r\n if (typeof orig.set === \"function\") {\r\n infoTree.set = (value: any, target: any, _index?: number, ...rest: any[]) => orig.set(value, target, numericIndex, ...rest);\r\n }\r\n if (typeof orig.getTarget === \"function\") {\r\n infoTree.getTarget = (target: any, _index?: number, ...rest: any[]) => orig.getTarget(target, numericIndex, ...rest);\r\n }\r\n }\r\n }\r\n\r\n if (infoTree.__target__) {\r\n // Only update target if objectTree is defined, otherwise keep the last valid target\r\n if (objectTree !== undefined) {\r\n target = objectTree;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n object: target,\r\n info: infoTree,\r\n };\r\n }\r\n}\r\n"]}
@@ -0,0 +1,41 @@
1
+ import { type IObjectInfo, type IPathToObjectConverter } from "@babylonjs/core/ObjectModel/objectModelInterfaces.js";
2
+ import { type IObjectAccessor } from "@babylonjs/core/FlowGraph/typeDefinitions.js";
3
+ import { type IGLTF } from "../glTFLoaderInterfaces.js";
4
+ /**
5
+ * Path prefix of the KHR_interactivity asset-capability pointers (spec §4.1 Asset Capabilities).
6
+ */
7
+ export declare const InteractivityAssetCapabilitiesPrefix = "/extensions/KHR_interactivity/asset/";
8
+ /**
9
+ * Path prefix of the KHR_interactivity runtime-limit pointers (spec §4.2 Implementation-Specific Runtime Limits).
10
+ */
11
+ export declare const InteractivityLimitsPrefix = "/extensions/KHR_interactivity/limits/";
12
+ /**
13
+ * Path-to-object converter that resolves the virtual KHR_interactivity pointers describing the capabilities of the
14
+ * asset and of the implementation running it:
15
+ *
16
+ * - `/extensions/KHR_interactivity/asset/majorVersion` and `.../minorVersion` — the glTF version the asset is
17
+ * presented with.
18
+ * - `/extensions/KHR_interactivity/asset/extensions/<EXTENSION_NAME>/enabled` — whether the extension is both
19
+ * listed in `extensionsUsed` and supported by this loader. Reading an extension that is not used or not
20
+ * supported resolves successfully and yields `false`, so a behavior graph can branch on extension support.
21
+ * - `/extensions/KHR_interactivity/limits/<LIMIT_NAME>` — the implementation-specific runtime limits.
22
+ *
23
+ * All of these are read-only.
24
+ */
25
+ export declare class InteractivityAssetPathToObjectConverter implements IPathToObjectConverter<IObjectAccessor> {
26
+ private _gltf;
27
+ private _isExtensionEnabled;
28
+ /**
29
+ * @param _gltf the loaded glTF, used to read the asset version
30
+ * @param _isExtensionEnabled predicate telling whether a glTF extension is both used by the asset and supported
31
+ * by this loader
32
+ */
33
+ constructor(_gltf: IGLTF, _isExtensionEnabled: (name: string) => boolean);
34
+ /**
35
+ * @param path the JSON Pointer to resolve
36
+ * @returns an object accessor for the addressed capability
37
+ * @throws if the path does not address a known capability, which `pointer/get` surfaces as `isValid = false`
38
+ */
39
+ convert(path: string): IObjectInfo<IObjectAccessor>;
40
+ private _createAccessor;
41
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Path prefix of the KHR_interactivity asset-capability pointers (spec §4.1 Asset Capabilities).
3
+ */
4
+ export const InteractivityAssetCapabilitiesPrefix = "/extensions/KHR_interactivity/asset/";
5
+ /**
6
+ * Path prefix of the KHR_interactivity runtime-limit pointers (spec §4.2 Implementation-Specific Runtime Limits).
7
+ */
8
+ export const InteractivityLimitsPrefix = "/extensions/KHR_interactivity/limits/";
9
+ /**
10
+ * Highest glTF version this loader can present an asset with.
11
+ */
12
+ const MaxSupportedGltfVersion = { major: 2, minor: 0 };
13
+ /**
14
+ * The spec allows an implementation to report the maximum `int` value for a runtime limit it does not enforce or
15
+ * does not want to disclose. Babylon imposes no hard cap on any of these features.
16
+ */
17
+ const UndisclosedRuntimeLimit = 2147483647;
18
+ const RuntimeLimits = {
19
+ maxActiveAnimations: UndisclosedRuntimeLimit,
20
+ maxActiveDelays: UndisclosedRuntimeLimit,
21
+ maxActivePropertyInterpolations: UndisclosedRuntimeLimit,
22
+ maxActiveVariableInterpolations: UndisclosedRuntimeLimit,
23
+ };
24
+ /**
25
+ * Sentinel target returned by the asset-capability accessors. These pointers are virtual and are not backed by a
26
+ * glTF object, so the accessor uses a non-null sentinel to satisfy callers that expect a truthy target.
27
+ */
28
+ const AssetCapabilityTarget = { isKhrInteractivityAssetCapability: true };
29
+ /**
30
+ * Resolves the glTF version the asset is presented with: the minimum of the version declared in the glTF JSON and
31
+ * the maximum version this implementation supports.
32
+ * @param version the `asset.version` string from the glTF JSON
33
+ * @returns the effective major and minor version components
34
+ */
35
+ function GetEffectiveGltfVersion(version) {
36
+ const [rawMajor, rawMinor] = (version ?? "").split(".");
37
+ const major = parseInt(rawMajor, 10);
38
+ const minor = parseInt(rawMinor, 10);
39
+ if (isNaN(major)) {
40
+ return MaxSupportedGltfVersion;
41
+ }
42
+ if (major !== MaxSupportedGltfVersion.major) {
43
+ return major < MaxSupportedGltfVersion.major ? { major, minor: isNaN(minor) ? 0 : minor } : MaxSupportedGltfVersion;
44
+ }
45
+ return { major, minor: Math.min(isNaN(minor) ? 0 : minor, MaxSupportedGltfVersion.minor) };
46
+ }
47
+ /**
48
+ * Path-to-object converter that resolves the virtual KHR_interactivity pointers describing the capabilities of the
49
+ * asset and of the implementation running it:
50
+ *
51
+ * - `/extensions/KHR_interactivity/asset/majorVersion` and `.../minorVersion` — the glTF version the asset is
52
+ * presented with.
53
+ * - `/extensions/KHR_interactivity/asset/extensions/<EXTENSION_NAME>/enabled` — whether the extension is both
54
+ * listed in `extensionsUsed` and supported by this loader. Reading an extension that is not used or not
55
+ * supported resolves successfully and yields `false`, so a behavior graph can branch on extension support.
56
+ * - `/extensions/KHR_interactivity/limits/<LIMIT_NAME>` — the implementation-specific runtime limits.
57
+ *
58
+ * All of these are read-only.
59
+ */
60
+ export class InteractivityAssetPathToObjectConverter {
61
+ /**
62
+ * @param _gltf the loaded glTF, used to read the asset version
63
+ * @param _isExtensionEnabled predicate telling whether a glTF extension is both used by the asset and supported
64
+ * by this loader
65
+ */
66
+ constructor(_gltf, _isExtensionEnabled) {
67
+ this._gltf = _gltf;
68
+ this._isExtensionEnabled = _isExtensionEnabled;
69
+ }
70
+ /**
71
+ * @param path the JSON Pointer to resolve
72
+ * @returns an object accessor for the addressed capability
73
+ * @throws if the path does not address a known capability, which `pointer/get` surfaces as `isValid = false`
74
+ */
75
+ convert(path) {
76
+ const normalized = path.endsWith("/") ? path.slice(0, -1) : path;
77
+ if (normalized.startsWith(InteractivityLimitsPrefix)) {
78
+ const limit = RuntimeLimits[normalized.substring(InteractivityLimitsPrefix.length)];
79
+ if (limit === undefined) {
80
+ throw new Error(`Path ${path} is invalid`);
81
+ }
82
+ return this._createAccessor("number", () => limit);
83
+ }
84
+ const capability = normalized.substring(InteractivityAssetCapabilitiesPrefix.length);
85
+ if (capability === "majorVersion" || capability === "minorVersion") {
86
+ return this._createAccessor("number", () => GetEffectiveGltfVersion(this._gltf.asset?.version)[capability === "majorVersion" ? "major" : "minor"]);
87
+ }
88
+ // `extensions/<EXTENSION_NAME>/enabled`. The extension name itself may not contain a slash.
89
+ const segments = capability.split("/");
90
+ if (segments.length === 3 && segments[0] === "extensions" && segments[2] === "enabled") {
91
+ const extensionName = segments[1];
92
+ return this._createAccessor("boolean", () => this._isExtensionEnabled(extensionName));
93
+ }
94
+ throw new Error(`Path ${path} is invalid`);
95
+ }
96
+ _createAccessor(type, get) {
97
+ return {
98
+ object: AssetCapabilityTarget,
99
+ info: {
100
+ type,
101
+ isReadOnly: true,
102
+ get,
103
+ getTarget: () => AssetCapabilityTarget,
104
+ },
105
+ };
106
+ }
107
+ }
108
+ //# sourceMappingURL=interactivityAssetPathToObjectConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactivityAssetPathToObjectConverter.js","sourceRoot":"","sources":["../../../../../../dev/loaders/src/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IObjectInfo, type IPathToObjectConverter } from \"core/ObjectModel/objectModelInterfaces\";\r\nimport { type IObjectAccessor } from \"core/FlowGraph/typeDefinitions\";\r\nimport { type IGLTF } from \"../glTFLoaderInterfaces\";\r\n\r\n/**\r\n * Path prefix of the KHR_interactivity asset-capability pointers (spec §4.1 Asset Capabilities).\r\n */\r\nexport const InteractivityAssetCapabilitiesPrefix = \"/extensions/KHR_interactivity/asset/\";\r\n\r\n/**\r\n * Path prefix of the KHR_interactivity runtime-limit pointers (spec §4.2 Implementation-Specific Runtime Limits).\r\n */\r\nexport const InteractivityLimitsPrefix = \"/extensions/KHR_interactivity/limits/\";\r\n\r\n/**\r\n * Highest glTF version this loader can present an asset with.\r\n */\r\nconst MaxSupportedGltfVersion = { major: 2, minor: 0 };\r\n\r\n/**\r\n * The spec allows an implementation to report the maximum `int` value for a runtime limit it does not enforce or\r\n * does not want to disclose. Babylon imposes no hard cap on any of these features.\r\n */\r\nconst UndisclosedRuntimeLimit = 2147483647;\r\n\r\nconst RuntimeLimits: Record<string, number> = {\r\n maxActiveAnimations: UndisclosedRuntimeLimit,\r\n maxActiveDelays: UndisclosedRuntimeLimit,\r\n maxActivePropertyInterpolations: UndisclosedRuntimeLimit,\r\n maxActiveVariableInterpolations: UndisclosedRuntimeLimit,\r\n};\r\n\r\n/**\r\n * Sentinel target returned by the asset-capability accessors. These pointers are virtual and are not backed by a\r\n * glTF object, so the accessor uses a non-null sentinel to satisfy callers that expect a truthy target.\r\n */\r\nconst AssetCapabilityTarget = { isKhrInteractivityAssetCapability: true };\r\n\r\n/**\r\n * Resolves the glTF version the asset is presented with: the minimum of the version declared in the glTF JSON and\r\n * the maximum version this implementation supports.\r\n * @param version the `asset.version` string from the glTF JSON\r\n * @returns the effective major and minor version components\r\n */\r\nfunction GetEffectiveGltfVersion(version: string | undefined): { major: number; minor: number } {\r\n const [rawMajor, rawMinor] = (version ?? \"\").split(\".\");\r\n const major = parseInt(rawMajor, 10);\r\n const minor = parseInt(rawMinor, 10);\r\n if (isNaN(major)) {\r\n return MaxSupportedGltfVersion;\r\n }\r\n if (major !== MaxSupportedGltfVersion.major) {\r\n return major < MaxSupportedGltfVersion.major ? { major, minor: isNaN(minor) ? 0 : minor } : MaxSupportedGltfVersion;\r\n }\r\n return { major, minor: Math.min(isNaN(minor) ? 0 : minor, MaxSupportedGltfVersion.minor) };\r\n}\r\n\r\n/**\r\n * Path-to-object converter that resolves the virtual KHR_interactivity pointers describing the capabilities of the\r\n * asset and of the implementation running it:\r\n *\r\n * - `/extensions/KHR_interactivity/asset/majorVersion` and `.../minorVersion` — the glTF version the asset is\r\n * presented with.\r\n * - `/extensions/KHR_interactivity/asset/extensions/<EXTENSION_NAME>/enabled` — whether the extension is both\r\n * listed in `extensionsUsed` and supported by this loader. Reading an extension that is not used or not\r\n * supported resolves successfully and yields `false`, so a behavior graph can branch on extension support.\r\n * - `/extensions/KHR_interactivity/limits/<LIMIT_NAME>` — the implementation-specific runtime limits.\r\n *\r\n * All of these are read-only.\r\n */\r\nexport class InteractivityAssetPathToObjectConverter implements IPathToObjectConverter<IObjectAccessor> {\r\n /**\r\n * @param _gltf the loaded glTF, used to read the asset version\r\n * @param _isExtensionEnabled predicate telling whether a glTF extension is both used by the asset and supported\r\n * by this loader\r\n */\r\n public constructor(\r\n private _gltf: IGLTF,\r\n private _isExtensionEnabled: (name: string) => boolean\r\n ) {}\r\n\r\n /**\r\n * @param path the JSON Pointer to resolve\r\n * @returns an object accessor for the addressed capability\r\n * @throws if the path does not address a known capability, which `pointer/get` surfaces as `isValid = false`\r\n */\r\n public convert(path: string): IObjectInfo<IObjectAccessor> {\r\n const normalized = path.endsWith(\"/\") ? path.slice(0, -1) : path;\r\n\r\n if (normalized.startsWith(InteractivityLimitsPrefix)) {\r\n const limit = RuntimeLimits[normalized.substring(InteractivityLimitsPrefix.length)];\r\n if (limit === undefined) {\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n return this._createAccessor(\"number\", () => limit);\r\n }\r\n\r\n const capability = normalized.substring(InteractivityAssetCapabilitiesPrefix.length);\r\n if (capability === \"majorVersion\" || capability === \"minorVersion\") {\r\n return this._createAccessor(\"number\", () => GetEffectiveGltfVersion(this._gltf.asset?.version)[capability === \"majorVersion\" ? \"major\" : \"minor\"]);\r\n }\r\n\r\n // `extensions/<EXTENSION_NAME>/enabled`. The extension name itself may not contain a slash.\r\n const segments = capability.split(\"/\");\r\n if (segments.length === 3 && segments[0] === \"extensions\" && segments[2] === \"enabled\") {\r\n const extensionName = segments[1];\r\n return this._createAccessor(\"boolean\", () => this._isExtensionEnabled(extensionName));\r\n }\r\n\r\n throw new Error(`Path ${path} is invalid`);\r\n }\r\n\r\n private _createAccessor(type: string, get: () => number | boolean): IObjectInfo<IObjectAccessor> {\r\n return {\r\n object: AssetCapabilityTarget,\r\n info: {\r\n type,\r\n isReadOnly: true,\r\n get,\r\n getTarget: () => AssetCapabilityTarget,\r\n },\r\n };\r\n }\r\n}\r\n"]}
@@ -0,0 +1,28 @@
1
+ import { type IObjectInfo, type IPathToObjectConverter } from "@babylonjs/core/ObjectModel/objectModelInterfaces.js";
2
+ import { type IObjectAccessor } from "@babylonjs/core/FlowGraph/typeDefinitions.js";
3
+ /**
4
+ * Path-to-object converter that resolves the KHR_interactivity ref-validity
5
+ * pointers `pointer/get` can query (KHR_interactivity spec §4.2.3 Event
6
+ * References and §4.2.4 Delay References):
7
+ *
8
+ * - `/extensions/KHR_interactivity/events/{}` — valid when the input reference
9
+ * was produced by an event operation (an event reference). Stateless: any
10
+ * event-reference path that reaches this converter is valid; a null ref is
11
+ * rejected earlier by the path-template substitution.
12
+ * - `/extensions/KHR_interactivity/delays/{}` — valid only while the referenced
13
+ * delay index is in the runtime active-delay set (i.e. the delay is scheduled
14
+ * and has not yet fired or been cancelled). This requires the runtime
15
+ * {@link FlowGraphContext}, which is supplied to the accessor `get` as its
16
+ * payload argument by `FlowGraphJsonPointerParserBlock`.
17
+ *
18
+ * On success `get` returns the input reference value (matching the spec, which
19
+ * sets the `value` output to the input reference); on failure it returns
20
+ * `undefined`, which the `pointer/get` block surfaces as `isValid = false`.
21
+ */
22
+ export declare class InteractivityRefPathToObjectConverter implements IPathToObjectConverter<IObjectAccessor> {
23
+ /**
24
+ * @param path the (template-substituted) JSON Pointer to resolve
25
+ * @returns an object accessor whose `get` validates the reference
26
+ */
27
+ convert(path: string): IObjectInfo<IObjectAccessor>;
28
+ }
@@ -0,0 +1,71 @@
1
+ import { FlowGraphInteger } from "@babylonjs/core/FlowGraph/CustomTypes/flowGraphInteger.js";
2
+ import { EventReferencePrefix, DelayReferencePrefix } from "./KHR_interactivity/interactivityReferences.js";
3
+ import { IsDelayActive } from "@babylonjs/core/FlowGraph/flowGraphDelayRegistry.js";
4
+ /**
5
+ * Sentinel target returned by the validity accessors. The KHR_interactivity
6
+ * ref-validity pointers are not backed by a glTF object, so the accessor uses a
7
+ * non-null sentinel to satisfy callers that expect a truthy target.
8
+ */
9
+ const RefValidityTarget = { isKhrInteractivityRef: true };
10
+ /**
11
+ * Path-to-object converter that resolves the KHR_interactivity ref-validity
12
+ * pointers `pointer/get` can query (KHR_interactivity spec §4.2.3 Event
13
+ * References and §4.2.4 Delay References):
14
+ *
15
+ * - `/extensions/KHR_interactivity/events/{}` — valid when the input reference
16
+ * was produced by an event operation (an event reference). Stateless: any
17
+ * event-reference path that reaches this converter is valid; a null ref is
18
+ * rejected earlier by the path-template substitution.
19
+ * - `/extensions/KHR_interactivity/delays/{}` — valid only while the referenced
20
+ * delay index is in the runtime active-delay set (i.e. the delay is scheduled
21
+ * and has not yet fired or been cancelled). This requires the runtime
22
+ * {@link FlowGraphContext}, which is supplied to the accessor `get` as its
23
+ * payload argument by `FlowGraphJsonPointerParserBlock`.
24
+ *
25
+ * On success `get` returns the input reference value (matching the spec, which
26
+ * sets the `value` output to the input reference); on failure it returns
27
+ * `undefined`, which the `pointer/get` block surfaces as `isValid = false`.
28
+ */
29
+ export class InteractivityRefPathToObjectConverter {
30
+ /**
31
+ * @param path the (template-substituted) JSON Pointer to resolve
32
+ * @returns an object accessor whose `get` validates the reference
33
+ */
34
+ convert(path) {
35
+ const normalized = path.endsWith("/") ? path.slice(0, -1) : path;
36
+ if (normalized.startsWith(EventReferencePrefix)) {
37
+ const key = normalized.substring(EventReferencePrefix.length);
38
+ return {
39
+ object: RefValidityTarget,
40
+ info: {
41
+ type: "object",
42
+ isReadOnly: true,
43
+ // A non-empty key means a real event reference was supplied (the
44
+ // template substitution rejects null refs before we get here).
45
+ get: () => (key.length > 0 ? normalized : undefined),
46
+ getTarget: () => RefValidityTarget,
47
+ },
48
+ };
49
+ }
50
+ // Delay reference: the substituted segment is the integer delay index. parseInt is too lenient
51
+ // (it would accept "1abc" as 1), so require an all-digits segment before converting.
52
+ const rawIndex = normalized.substring(DelayReferencePrefix.length);
53
+ const index = /^\d+$/.test(rawIndex) ? parseInt(rawIndex, 10) : NaN;
54
+ return {
55
+ object: RefValidityTarget,
56
+ info: {
57
+ type: "object",
58
+ isReadOnly: true,
59
+ get: (_target, _index, payload) => {
60
+ const context = payload;
61
+ if (!context || isNaN(index) || index < 0) {
62
+ return undefined;
63
+ }
64
+ return IsDelayActive(context, index) ? new FlowGraphInteger(index) : undefined;
65
+ },
66
+ getTarget: () => RefValidityTarget,
67
+ },
68
+ };
69
+ }
70
+ }
71
+ //# sourceMappingURL=interactivityRefPathToObjectConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactivityRefPathToObjectConverter.js","sourceRoot":"","sources":["../../../../../../dev/loaders/src/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AACzG,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAEtE;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;AAE1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,qCAAqC;IAC9C;;;OAGG;IACI,OAAO,CAAC,IAAY;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEjE,IAAI,UAAU,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC9C,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAC9D,OAAO;gBACH,MAAM,EAAE,iBAAiB;gBACzB,IAAI,EAAE;oBACF,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,IAAI;oBAChB,iEAAiE;oBACjE,+DAA+D;oBAC/D,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;oBACpD,SAAS,EAAE,GAAG,EAAE,CAAC,iBAAiB;iBACrC;aACJ,CAAC;QACN,CAAC;QAED,+FAA+F;QAC/F,qFAAqF;QACrF,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACpE,OAAO;YACH,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE;gBACF,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,IAAI;gBAChB,GAAG,EAAE,CAAC,OAAgB,EAAE,MAAe,EAAE,OAAiB,EAAE,EAAE;oBAC1D,MAAM,OAAO,GAAG,OAAuC,CAAC;oBACxD,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;wBACxC,OAAO,SAAS,CAAC;oBACrB,CAAC;oBACD,OAAO,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACnF,CAAC;gBACD,SAAS,EAAE,GAAG,EAAE,CAAC,iBAAiB;aACrC;SACJ,CAAC;IACN,CAAC;CACJ","sourcesContent":["import { type IObjectInfo, type IPathToObjectConverter } from \"core/ObjectModel/objectModelInterfaces\";\r\nimport { type IObjectAccessor } from \"core/FlowGraph/typeDefinitions\";\r\nimport { type FlowGraphContext } from \"core/FlowGraph/flowGraphContext\";\r\nimport { FlowGraphInteger } from \"core/FlowGraph/CustomTypes/flowGraphInteger\";\r\nimport { EventReferencePrefix, DelayReferencePrefix } from \"./KHR_interactivity/interactivityReferences\";\r\nimport { IsDelayActive } from \"core/FlowGraph/flowGraphDelayRegistry\";\r\n\r\n/**\r\n * Sentinel target returned by the validity accessors. The KHR_interactivity\r\n * ref-validity pointers are not backed by a glTF object, so the accessor uses a\r\n * non-null sentinel to satisfy callers that expect a truthy target.\r\n */\r\nconst RefValidityTarget = { isKhrInteractivityRef: true };\r\n\r\n/**\r\n * Path-to-object converter that resolves the KHR_interactivity ref-validity\r\n * pointers `pointer/get` can query (KHR_interactivity spec §4.2.3 Event\r\n * References and §4.2.4 Delay References):\r\n *\r\n * - `/extensions/KHR_interactivity/events/{}` — valid when the input reference\r\n * was produced by an event operation (an event reference). Stateless: any\r\n * event-reference path that reaches this converter is valid; a null ref is\r\n * rejected earlier by the path-template substitution.\r\n * - `/extensions/KHR_interactivity/delays/{}` — valid only while the referenced\r\n * delay index is in the runtime active-delay set (i.e. the delay is scheduled\r\n * and has not yet fired or been cancelled). This requires the runtime\r\n * {@link FlowGraphContext}, which is supplied to the accessor `get` as its\r\n * payload argument by `FlowGraphJsonPointerParserBlock`.\r\n *\r\n * On success `get` returns the input reference value (matching the spec, which\r\n * sets the `value` output to the input reference); on failure it returns\r\n * `undefined`, which the `pointer/get` block surfaces as `isValid = false`.\r\n */\r\nexport class InteractivityRefPathToObjectConverter implements IPathToObjectConverter<IObjectAccessor> {\r\n /**\r\n * @param path the (template-substituted) JSON Pointer to resolve\r\n * @returns an object accessor whose `get` validates the reference\r\n */\r\n public convert(path: string): IObjectInfo<IObjectAccessor> {\r\n const normalized = path.endsWith(\"/\") ? path.slice(0, -1) : path;\r\n\r\n if (normalized.startsWith(EventReferencePrefix)) {\r\n const key = normalized.substring(EventReferencePrefix.length);\r\n return {\r\n object: RefValidityTarget,\r\n info: {\r\n type: \"object\",\r\n isReadOnly: true,\r\n // A non-empty key means a real event reference was supplied (the\r\n // template substitution rejects null refs before we get here).\r\n get: () => (key.length > 0 ? normalized : undefined),\r\n getTarget: () => RefValidityTarget,\r\n },\r\n };\r\n }\r\n\r\n // Delay reference: the substituted segment is the integer delay index. parseInt is too lenient\r\n // (it would accept \"1abc\" as 1), so require an all-digits segment before converting.\r\n const rawIndex = normalized.substring(DelayReferencePrefix.length);\r\n const index = /^\\d+$/.test(rawIndex) ? parseInt(rawIndex, 10) : NaN;\r\n return {\r\n object: RefValidityTarget,\r\n info: {\r\n type: \"object\",\r\n isReadOnly: true,\r\n get: (_target: unknown, _index?: number, payload?: unknown) => {\r\n const context = payload as FlowGraphContext | undefined;\r\n if (!context || isNaN(index) || index < 0) {\r\n return undefined;\r\n }\r\n return IsDelayActive(context, index) ? new FlowGraphInteger(index) : undefined;\r\n },\r\n getTarget: () => RefValidityTarget,\r\n },\r\n };\r\n }\r\n}\r\n"]}