@babylonjs/smart-filters 0.2.0-alpha → 0.3.1-alpha

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 (108) hide show
  1. package/dist/blocks/baseBlock.d.ts +1 -1
  2. package/dist/blocks/baseBlock.d.ts.map +1 -1
  3. package/dist/blocks/baseBlock.js +1 -1
  4. package/dist/blocks/baseBlock.js.map +1 -1
  5. package/dist/blocks/copyBlock.d.ts +2 -3
  6. package/dist/blocks/copyBlock.d.ts.map +1 -1
  7. package/dist/blocks/copyBlock.js +4 -24
  8. package/dist/blocks/copyBlock.js.map +1 -1
  9. package/dist/blocks/copyBlock.shader.d.ts +13 -0
  10. package/dist/blocks/copyBlock.shader.d.ts.map +1 -0
  11. package/dist/blocks/copyBlock.shader.js +34 -0
  12. package/dist/blocks/copyBlock.shader.js.map +1 -0
  13. package/dist/blocks/inputBlock.d.ts +41 -5
  14. package/dist/blocks/inputBlock.d.ts.map +1 -1
  15. package/dist/blocks/inputBlock.deserializer.d.ts +14 -0
  16. package/dist/blocks/inputBlock.deserializer.d.ts.map +1 -0
  17. package/dist/blocks/inputBlock.deserializer.js +46 -0
  18. package/dist/blocks/inputBlock.deserializer.js.map +1 -0
  19. package/dist/blocks/inputBlock.js +16 -6
  20. package/dist/blocks/inputBlock.js.map +1 -1
  21. package/dist/blocks/inputBlock.serialization.types.d.ts +74 -0
  22. package/dist/blocks/inputBlock.serialization.types.d.ts.map +1 -0
  23. package/dist/blocks/inputBlock.serialization.types.js +2 -0
  24. package/dist/blocks/inputBlock.serialization.types.js.map +1 -0
  25. package/dist/blocks/inputBlock.serializer.d.ts +6 -0
  26. package/dist/blocks/inputBlock.serializer.d.ts.map +1 -0
  27. package/dist/blocks/inputBlock.serializer.js +115 -0
  28. package/dist/blocks/inputBlock.serializer.js.map +1 -0
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/serialization/index.d.ts +5 -0
  34. package/dist/serialization/index.d.ts.map +1 -0
  35. package/dist/serialization/index.js +5 -0
  36. package/dist/serialization/index.js.map +1 -0
  37. package/dist/serialization/serializedSmartFilter.d.ts +6 -0
  38. package/dist/serialization/serializedSmartFilter.d.ts.map +1 -0
  39. package/dist/serialization/serializedSmartFilter.js +2 -0
  40. package/dist/serialization/serializedSmartFilter.js.map +1 -0
  41. package/dist/serialization/smartFilterDeserializer.d.ts +25 -0
  42. package/dist/serialization/smartFilterDeserializer.d.ts.map +1 -0
  43. package/dist/serialization/smartFilterDeserializer.js +90 -0
  44. package/dist/serialization/smartFilterDeserializer.js.map +1 -0
  45. package/dist/serialization/smartFilterSerializer.d.ts +23 -0
  46. package/dist/serialization/smartFilterSerializer.d.ts.map +1 -0
  47. package/dist/serialization/smartFilterSerializer.js +91 -0
  48. package/dist/serialization/smartFilterSerializer.js.map +1 -0
  49. package/dist/serialization/v1/defaultBlockSerializer.d.ts +9 -0
  50. package/dist/serialization/v1/defaultBlockSerializer.d.ts.map +1 -0
  51. package/dist/serialization/v1/defaultBlockSerializer.js +16 -0
  52. package/dist/serialization/v1/defaultBlockSerializer.js.map +1 -0
  53. package/dist/serialization/v1/index.d.ts +3 -0
  54. package/dist/serialization/v1/index.d.ts.map +1 -0
  55. package/dist/serialization/v1/index.js +3 -0
  56. package/dist/serialization/v1/index.js.map +1 -0
  57. package/dist/serialization/v1/serialization.types.d.ts +83 -0
  58. package/dist/serialization/v1/serialization.types.d.ts.map +1 -0
  59. package/dist/serialization/v1/serialization.types.js +2 -0
  60. package/dist/serialization/v1/serialization.types.js.map +1 -0
  61. package/dist/smartFilter.d.ts +2 -2
  62. package/dist/smartFilter.d.ts.map +1 -1
  63. package/dist/smartFilter.js +9 -6
  64. package/dist/smartFilter.js.map +1 -1
  65. package/dist/utils/buildTools/determineVersion.d.ts +36 -0
  66. package/dist/utils/buildTools/determineVersion.d.ts.map +1 -0
  67. package/dist/utils/buildTools/determineVersion.js +109 -0
  68. package/dist/utils/buildTools/determineVersion.js.map +1 -0
  69. package/dist/utils/buildTools/shaderConverter.d.ts +2 -0
  70. package/dist/utils/buildTools/shaderConverter.d.ts.map +1 -0
  71. package/dist/utils/buildTools/shaderConverter.js +277 -0
  72. package/dist/utils/buildTools/shaderConverter.js.map +1 -0
  73. package/dist/utils/buildTools/versionUp.d.ts +2 -0
  74. package/dist/utils/buildTools/versionUp.d.ts.map +1 -0
  75. package/dist/utils/buildTools/versionUp.js +45 -0
  76. package/dist/utils/buildTools/versionUp.js.map +1 -0
  77. package/dist/utils/textureLoaders.d.ts +3 -1
  78. package/dist/utils/textureLoaders.d.ts.map +1 -1
  79. package/dist/utils/textureLoaders.js +3 -2
  80. package/dist/utils/textureLoaders.js.map +1 -1
  81. package/dist/utils/uniqueIdGenerator.d.ts +19 -0
  82. package/dist/utils/uniqueIdGenerator.d.ts.map +1 -0
  83. package/dist/utils/uniqueIdGenerator.js +27 -0
  84. package/dist/utils/uniqueIdGenerator.js.map +1 -0
  85. package/package.json +11 -6
  86. package/readme.md +12 -0
  87. package/src/blocks/baseBlock.ts +2 -3
  88. package/src/blocks/copyBlock.fragment.glsl +5 -0
  89. package/src/blocks/copyBlock.shader.ts +36 -0
  90. package/src/blocks/copyBlock.ts +4 -29
  91. package/src/blocks/inputBlock.deserializer.ts +60 -0
  92. package/src/blocks/inputBlock.serialization.types.ts +95 -0
  93. package/src/blocks/inputBlock.serializer.ts +132 -0
  94. package/src/blocks/inputBlock.ts +51 -7
  95. package/src/index.ts +2 -1
  96. package/src/serialization/index.ts +4 -0
  97. package/src/serialization/serializedSmartFilter.ts +6 -0
  98. package/src/serialization/smartFilterDeserializer.ts +127 -0
  99. package/src/serialization/smartFilterSerializer.ts +113 -0
  100. package/src/serialization/v1/defaultBlockSerializer.ts +18 -0
  101. package/src/serialization/v1/index.ts +2 -0
  102. package/src/serialization/v1/serialization.types.ts +108 -0
  103. package/src/smartFilter.ts +10 -8
  104. package/src/utils/buildTools/determineVersion.ts +127 -0
  105. package/src/utils/buildTools/shaderConverter.ts +399 -0
  106. package/src/utils/buildTools/versionUp.ts +52 -0
  107. package/src/utils/textureLoaders.ts +18 -3
  108. package/src/utils/uniqueIdGenerator.ts +28 -0
@@ -0,0 +1,127 @@
1
+ import type { BaseBlock } from "../blocks/baseBlock";
2
+ import type { SerializedSmartFilter } from "./serializedSmartFilter.js";
3
+ import { SmartFilter } from "../smartFilter.js";
4
+ import { inputBlockDeserializer } from "../blocks/inputBlock.deserializer.js";
5
+ import { OutputBlock } from "../blocks/outputBlock.js";
6
+ import type { ThinEngine } from "@babylonjs/core/Engines/thinEngine";
7
+ import { InputBlock } from "../blocks/inputBlock.js";
8
+ import type {
9
+ DeserializeBlockV1,
10
+ ISerializedBlockV1,
11
+ ISerializedConnectionV1,
12
+ SerializedSmartFilterV1,
13
+ } from "./v1/serialization.types";
14
+ import { UniqueIdGenerator } from "../utils/uniqueIdGenerator.js";
15
+
16
+ /**
17
+ * Deserializes serialized SmartFilters. The caller passes in a map of block deserializers it wants to use,
18
+ * which allows the caller to provide custom deserializers for blocks beyond the core blocks.
19
+ * The deserializer supports versioned serialized SmartFilters.
20
+ */
21
+ export class SmartFilterDeserializer {
22
+ private readonly _blockDeserializersV1: Map<string, DeserializeBlockV1> = new Map();
23
+
24
+ /**
25
+ * Creates a new SmartFilterDeserializer
26
+ * @param blockDeserializers - The map of block serializers to use, beyond those for the core blocks
27
+ */
28
+ public constructor(blockDeserializers: Map<string, DeserializeBlockV1>) {
29
+ this._blockDeserializersV1 = blockDeserializers;
30
+
31
+ // Add in the core block deserializers - they are not delay loaded, so they are wrapped in Promise.resolve()
32
+ this._blockDeserializersV1.set(
33
+ InputBlock.ClassName,
34
+ (smartFilter: SmartFilter, serializedBlock: ISerializedBlockV1, engine: ThinEngine) =>
35
+ Promise.resolve(inputBlockDeserializer(smartFilter, serializedBlock, engine))
36
+ );
37
+
38
+ this._blockDeserializersV1.set(OutputBlock.ClassName, (smartFilter: SmartFilter) =>
39
+ Promise.resolve(smartFilter.output.ownerBlock)
40
+ );
41
+ }
42
+
43
+ /**
44
+ * Deserializes a SmartFilter from a JSON object - can be safely called multiple times and has no side effects within the class.
45
+ * @param engine - The ThinEngine to pass to the new SmartFilter
46
+ * @param smartFilterJson - The JSON object to deserialize
47
+ * @returns A promise that resolves to the deserialized SmartFilter
48
+ */
49
+ public async deserialize(engine: ThinEngine, smartFilterJson: any): Promise<SmartFilter> {
50
+ const serializedSmartFilter: SerializedSmartFilter = smartFilterJson;
51
+ switch (serializedSmartFilter.version) {
52
+ case 1:
53
+ return await this._deserializeV1(engine, serializedSmartFilter);
54
+ }
55
+ }
56
+
57
+ private async _deserializeV1(
58
+ engine: ThinEngine,
59
+ serializedSmartFilter: SerializedSmartFilterV1
60
+ ): Promise<SmartFilter> {
61
+ const smartFilter = new SmartFilter(serializedSmartFilter.name);
62
+ const blockMap = new Map<string, BaseBlock>();
63
+
64
+ // Deserialize the SmartFilter level data
65
+ smartFilter.comments = serializedSmartFilter.comments;
66
+ smartFilter.editorData = serializedSmartFilter.editorData;
67
+
68
+ // Deserialize the blocks
69
+ const blockDeserializationWork: Promise<void>[] = [];
70
+ serializedSmartFilter.blocks.forEach((serializedBlock: ISerializedBlockV1) => {
71
+ const blockDeserializer = this._blockDeserializersV1.get(serializedBlock.className);
72
+ if (!blockDeserializer) {
73
+ throw new Error(`No deserializer found for block type ${serializedBlock.className}`);
74
+ }
75
+ blockDeserializationWork.push(
76
+ blockDeserializer(smartFilter, serializedBlock, engine).then((newBlock) => {
77
+ // Deserializers are not responsible for setting the uniqueId or comments.
78
+ // This is so they don't have to be passed into the constructors when programmatically creating
79
+ // blocks, and so each deserializer doesn't have to remember to do it.
80
+ newBlock.uniqueId = serializedBlock.uniqueId;
81
+ newBlock.comments = serializedBlock.comments;
82
+
83
+ // We need to ensure any uniqueIds generated in the future (e.g. a new block is added to the SmartFilter)
84
+ // are higher than this one.
85
+ UniqueIdGenerator.EnsureIdsGreaterThan(newBlock.uniqueId);
86
+
87
+ // Save in the map
88
+ blockMap.set(newBlock.name, newBlock);
89
+ })
90
+ );
91
+ });
92
+ await Promise.all(blockDeserializationWork);
93
+
94
+ // Deserialize the connections
95
+ serializedSmartFilter.connections.forEach((connection: ISerializedConnectionV1) => {
96
+ // Find the source block and its connection point's connectTo function
97
+ const sourceBlock = blockMap.get(connection.outputBlock);
98
+ if (!sourceBlock) {
99
+ throw new Error(`Source block ${connection.outputBlock} not found`);
100
+ }
101
+ const sourceConnectionPoint = (sourceBlock as any)[connection.outputConnectionPoint];
102
+ if (!sourceConnectionPoint || typeof sourceConnectionPoint.connectTo !== "function") {
103
+ throw new Error(
104
+ `Block ${connection.outputBlock} does not have an connection point named ${connection.outputConnectionPoint}`
105
+ );
106
+ }
107
+ const sourceConnectToFunction = sourceConnectionPoint.connectTo.bind(sourceConnectionPoint);
108
+
109
+ // Find the target block and its connection point
110
+ const targetBlock = blockMap.get(connection.inputBlock);
111
+ if (!targetBlock) {
112
+ throw new Error(`Target block ${connection.inputBlock} not found`);
113
+ }
114
+ const targetConnectionPoint = (targetBlock as any)[connection.inputConnectionPoint];
115
+ if (!targetConnectionPoint || typeof targetConnectionPoint !== "object") {
116
+ throw new Error(
117
+ `Block ${connection.inputBlock} does not have a connection point named ${connection.inputConnectionPoint}`
118
+ );
119
+ }
120
+
121
+ // Create the connection
122
+ sourceConnectToFunction.call(sourceBlock, targetConnectionPoint);
123
+ });
124
+
125
+ return smartFilter;
126
+ }
127
+ }
@@ -0,0 +1,113 @@
1
+ import type { SmartFilter } from "../smartFilter";
2
+ import type { BaseBlock } from "../blocks/baseBlock";
3
+ import { inputBlockSerializer } from "../blocks/inputBlock.serializer.js";
4
+ import type { ConnectionPoint } from "../connection/connectionPoint";
5
+ import { defaultBlockSerializer } from "./v1/defaultBlockSerializer.js";
6
+ import { OutputBlock } from "../blocks/outputBlock.js";
7
+ import type {
8
+ IBlockSerializerV1,
9
+ ISerializedBlockV1,
10
+ ISerializedConnectionV1,
11
+ SerializeBlockV1,
12
+ SerializedSmartFilterV1,
13
+ } from "./v1/serialization.types";
14
+
15
+ /**
16
+ * Determines if two serialized connection points are equivalent to each other
17
+ * @param a - The first connection point to compare
18
+ * @param b - The second connection point to compare
19
+ * @returns True if the connection points are equivalent, false otherwise
20
+ */
21
+ function serializedConnectionPointsEqual(a: ISerializedConnectionV1, b: ISerializedConnectionV1): boolean {
22
+ return (
23
+ a.inputBlock === b.inputBlock &&
24
+ a.inputConnectionPoint === b.inputConnectionPoint &&
25
+ a.outputBlock === b.outputBlock &&
26
+ a.outputConnectionPoint === b.outputConnectionPoint
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Serializes SmartFilters using the latest SmartFilter serialization version.
32
+ * The caller passes in information necessary to serialize the blocks in the SmartFilter.
33
+ * This allows the caller to provide custom serializers for blocks beyond the core blocks.
34
+ */
35
+ export class SmartFilterSerializer {
36
+ private readonly _blockSerializers: Map<string, SerializeBlockV1> = new Map();
37
+
38
+ /**
39
+ * Creates a new SmartFilterSerializer
40
+ * @param blocksUsingDefaultSerialization - A list of the classNames of blocks which can use default serialization (they only have ConnectionPoint properties and no constructor parameters)
41
+ * @param additionalBlockSerializers - An array of block serializers to use, beyond those for the core blocks
42
+ */
43
+ public constructor(blocksUsingDefaultSerialization: string[], additionalBlockSerializers: IBlockSerializerV1[]) {
44
+ this._blockSerializers.set(inputBlockSerializer.className, inputBlockSerializer.serialize);
45
+ this._blockSerializers.set(OutputBlock.ClassName, defaultBlockSerializer);
46
+ blocksUsingDefaultSerialization.forEach((block) => {
47
+ this._blockSerializers.set(block, defaultBlockSerializer);
48
+ });
49
+ additionalBlockSerializers.forEach((serializer) =>
50
+ this._blockSerializers.set(serializer.className, serializer.serialize)
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Serializes a SmartFilter to a JSON object of the latest version
56
+ * @param smartFilter - The SmartFilter to serialize
57
+ * @returns The serialized SmartFilter
58
+ */
59
+ public serialize(smartFilter: SmartFilter): SerializedSmartFilterV1 {
60
+ const connections: ISerializedConnectionV1[] = [];
61
+
62
+ const blocks = smartFilter.attachedBlocks.map((block: BaseBlock) => {
63
+ // Serialize the block itself
64
+ const serializeFn = this._blockSerializers.get(block.getClassName());
65
+ if (!serializeFn) {
66
+ throw new Error(`No serializer was provided for a block of type ${block.getClassName()}`);
67
+ }
68
+ const serializedBlock: ISerializedBlockV1 = serializeFn(block);
69
+
70
+ // Serialize the connections to the inputs
71
+ block.inputs.forEach((input: ConnectionPoint) => {
72
+ const connectedTo = input.connectedTo;
73
+ if (connectedTo) {
74
+ const newConnection: ISerializedConnectionV1 = {
75
+ inputBlock: block.name,
76
+ inputConnectionPoint: input.name,
77
+ outputBlock: connectedTo.ownerBlock.name,
78
+ outputConnectionPoint: connectedTo.name,
79
+ };
80
+ if (!connections.find((other) => serializedConnectionPointsEqual(newConnection, other))) {
81
+ connections.push(newConnection);
82
+ }
83
+ }
84
+ });
85
+
86
+ // Serialize the connections to the outputs
87
+ block.outputs.forEach((output: ConnectionPoint) => {
88
+ output.endpoints.forEach((input: ConnectionPoint) => {
89
+ const newConnection: ISerializedConnectionV1 = {
90
+ inputBlock: input.ownerBlock.name,
91
+ inputConnectionPoint: input.name,
92
+ outputBlock: block.name,
93
+ outputConnectionPoint: output.name,
94
+ };
95
+ if (!connections.find((other) => serializedConnectionPointsEqual(newConnection, other))) {
96
+ connections.push(newConnection);
97
+ }
98
+ });
99
+ });
100
+
101
+ return serializedBlock;
102
+ });
103
+
104
+ return {
105
+ version: 1,
106
+ name: smartFilter.name,
107
+ comments: smartFilter.comments,
108
+ editorData: smartFilter.editorData,
109
+ blocks,
110
+ connections,
111
+ };
112
+ }
113
+ }
@@ -0,0 +1,18 @@
1
+ import type { BaseBlock } from "../../blocks/baseBlock";
2
+ import type { ISerializedBlockV1, SerializeBlockV1 } from "./serialization.types";
3
+
4
+ /**
5
+ * The default V1 block serializer which can be used for any block that relies only on ConnectionPoints
6
+ * and does not have any constructor parameters or class properties that need to be serialized.
7
+ * @param block - The block to serialize
8
+ * @returns The serialized block
9
+ */
10
+ export const defaultBlockSerializer: SerializeBlockV1 = (block: BaseBlock): ISerializedBlockV1 => {
11
+ return {
12
+ name: block.name,
13
+ uniqueId: block.uniqueId,
14
+ className: block.getClassName(),
15
+ comments: block.comments,
16
+ data: undefined,
17
+ };
18
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./defaultBlockSerializer.js";
2
+ export * from "./serialization.types.js";
@@ -0,0 +1,108 @@
1
+ import type { Nullable } from "@babylonjs/core/types.js";
2
+ import type { BaseBlock } from "../../blocks/baseBlock.js";
3
+ import type { SmartFilter } from "../../smartFilter.js";
4
+ import type { ThinEngine } from "@babylonjs/core/Engines/thinEngine";
5
+ import type { IEditorData } from "@babylonjs/shared-ui-components/nodeGraphSystem/interfaces/nodeLocationInfo.js";
6
+
7
+ /**
8
+ * ----------------------------------------------------------------------------
9
+ * Serialized Data Types
10
+ * ----------------------------------------------------------------------------
11
+ */
12
+
13
+ /**
14
+ * V1 Serialized Smart Filter
15
+ */
16
+ export type SerializedSmartFilterV1 = {
17
+ /** The version of the serialized data */
18
+ version: 1;
19
+
20
+ /** The SmartFilter name */
21
+ name: string;
22
+
23
+ /** The SmartFilter comments */
24
+ comments: Nullable<string>;
25
+
26
+ /** The editor data for the SmartFilter */
27
+ editorData: Nullable<IEditorData>;
28
+
29
+ /** The serialized blocks */
30
+ blocks: ISerializedBlockV1[];
31
+
32
+ /** The serialized connections */
33
+ connections: ISerializedConnectionV1[];
34
+ };
35
+
36
+ /**
37
+ * V1 Serialized Block
38
+ */
39
+ export interface ISerializedBlockV1 {
40
+ /** The name of the block */
41
+ name: string;
42
+
43
+ /** The unique ID of the block - correlates with the ID in the editorData for block position, etc. */
44
+ uniqueId: number;
45
+
46
+ /** The class name of the block */
47
+ className: string;
48
+
49
+ /** The comments for the block */
50
+ comments: Nullable<string>;
51
+
52
+ /** Block specific serialized data */
53
+ data: any;
54
+ }
55
+
56
+ /**
57
+ * V1 Serialized Connection
58
+ */
59
+ export interface ISerializedConnectionV1 {
60
+ /** The name of the block that the connection is to */
61
+ outputBlock: string;
62
+
63
+ /** The name of the connectionPoint on the outputBlock */
64
+ outputConnectionPoint: string;
65
+
66
+ /** The name of the block that the connection is from */
67
+ inputBlock: string;
68
+
69
+ /** The name of the connectionPoint on the inputBlock */
70
+ inputConnectionPoint: string;
71
+ }
72
+
73
+ /**
74
+ * ----------------------------------------------------------------------------
75
+ * Serializer Types
76
+ * ----------------------------------------------------------------------------
77
+ */
78
+
79
+ /**
80
+ * A function that serializes a block to a V1 serialized block object
81
+ */
82
+ export type SerializeBlockV1 = (block: BaseBlock) => ISerializedBlockV1;
83
+
84
+ /**
85
+ * A V1 block serializer
86
+ */
87
+ export interface IBlockSerializerV1 {
88
+ /** The className of the block that this serializer can serialize */
89
+ className: string;
90
+
91
+ /** The function that serializes the block */
92
+ serialize: SerializeBlockV1;
93
+ }
94
+
95
+ /**
96
+ * ----------------------------------------------------------------------------
97
+ * Deserializer Types
98
+ * ----------------------------------------------------------------------------
99
+ */
100
+
101
+ /**
102
+ * A function that deserializes a block from a V1 serialized block object
103
+ */
104
+ export type DeserializeBlockV1 = (
105
+ smartFilter: SmartFilter,
106
+ serializedBlock: ISerializedBlockV1,
107
+ engine: ThinEngine
108
+ ) => Promise<BaseBlock>;
@@ -8,6 +8,7 @@ import { OutputBlock } from "./blocks/outputBlock.js";
8
8
  import { InternalSmartFilterRuntime } from "./runtime/smartFilterRuntime.js";
9
9
  import { RenderTargetGenerator } from "./runtime/renderTargetGenerator.js";
10
10
  import { AggregateBlock } from "./blocks/aggregateBlock.js";
11
+ import type { IEditorData } from "@babylonjs/shared-ui-components/nodeGraphSystem/interfaces/nodeLocationInfo";
11
12
 
12
13
  /**
13
14
  * How long to wait for shader compilation and texture loading to complete before erroring out.
@@ -61,9 +62,8 @@ export class SmartFilter {
61
62
 
62
63
  /**
63
64
  * Data used by the smart filter editor.
64
- * TODO. strong type and hide this.
65
65
  */
66
- public editorData: any = null;
66
+ public editorData: Nullable<IEditorData> = null;
67
67
 
68
68
  private readonly _attachedBlocks: Array<BaseBlock>;
69
69
  private readonly _outputBlock: OutputBlock;
@@ -216,12 +216,14 @@ export class SmartFilter {
216
216
  }
217
217
  });
218
218
 
219
- // Do the passed in work
220
- work();
221
-
222
- // Restore all aggregate blocks
223
- for (const block of mergedAggregateBlocks) {
224
- block._unmergeFromSmartFilter();
219
+ try {
220
+ // Do the passed in work
221
+ work();
222
+ } finally {
223
+ // Restore all aggregate blocks, even if work throws
224
+ for (const block of mergedAggregateBlocks) {
225
+ block._unmergeFromSmartFilter();
226
+ }
225
227
  }
226
228
  }
227
229
  }
@@ -0,0 +1,127 @@
1
+ import type { Nullable } from "@babylonjs/core/types";
2
+ import type { ExecException } from "child_process";
3
+
4
+ /**
5
+ * Determines if the major and minor versions of two semver strings match
6
+ * @param version1 - The first semver string
7
+ * @param version2 - The second semver string
8
+ * @returns True if the major and minor versions match, false otherwise
9
+ */
10
+ function majorAndMinorVersionsMatch(version1: string, version2: string): boolean {
11
+ const version1split = version1.split(".");
12
+ const version2split = version2.split(".");
13
+ return version1split[0] === version2split[0] && version1split[1] === version2split[1];
14
+ }
15
+
16
+ /**
17
+ * Takes in a semver string (e.g. "0.1.0") and increments the patch version.
18
+ * Note: it does not preserve any prerelease flags in the patch version.
19
+ * @param version - The semver string to operate on
20
+ * @returns The incremented version string
21
+ */
22
+ function incrementPatchVersion(version: string): string {
23
+ const spl = version.split(".");
24
+ if (spl.length < 3) {
25
+ throw new Error("version string must have at least 3 parts");
26
+ }
27
+ spl[spl.length - 1] = (Number.parseInt(spl[spl.length - 1]!) + 1).toString();
28
+ return spl.join(".");
29
+ }
30
+
31
+ /**
32
+ * Takes in a semver string (e.g. "0.1.0" or "0.1.0-alpha") and removes any prerelease flag.
33
+ * @param version - The semver string to operate on
34
+ * @returns The version string with the prerelease flag removed
35
+ */
36
+ export function removePrereleaseFlags(version: string): string {
37
+ const spl = version.split(".");
38
+ if (spl.length < 3) {
39
+ throw new Error("version string must have at least 3 parts");
40
+ }
41
+ spl[spl.length - 1] = Number.parseInt(spl[spl.length - 1]!).toString();
42
+ return spl.join(".");
43
+ }
44
+
45
+ /**
46
+ * Given the npmVersion, packageJSONVersion, and alpha flag, determines the version to use
47
+ * @param npmVersion - The version from the NPM registry
48
+ * @param packageJSONVersion - The version from the package.json file
49
+ * @param alpha - A flag to indicate if the version should have an alpha prerelease flag
50
+ * @returns The version to use
51
+ */
52
+ export function determineVersion(npmVersion: Nullable<string>, packageJSONVersion: string, alpha: boolean): string {
53
+ packageJSONVersion = removePrereleaseFlags(packageJSONVersion);
54
+ npmVersion = npmVersion === null ? null : removePrereleaseFlags(npmVersion);
55
+
56
+ let versionToUse;
57
+ if (npmVersion === null || !majorAndMinorVersionsMatch(npmVersion, packageJSONVersion)) {
58
+ console.log("Major & minor versions do not match: using the current package.json version");
59
+ versionToUse = packageJSONVersion;
60
+ } else {
61
+ console.log("Major & minor versions match: using the NPM registry version with an incremented patch version.");
62
+ versionToUse = incrementPatchVersion(npmVersion);
63
+ }
64
+
65
+ if (alpha) {
66
+ console.log("Ensuring -alpha prerelease flag is present");
67
+ versionToUse += "-alpha";
68
+ }
69
+
70
+ return versionToUse;
71
+ }
72
+
73
+ /**
74
+ * The supported version types
75
+ */
76
+ export type VersionType = "preview" | "latest";
77
+
78
+ /**
79
+ * Handles error cases and returns the JSON of the package versions
80
+ * @param versionType - The type of version to get
81
+ * @param err - The error object
82
+ * @param stdout - The stdout string
83
+ * @returns The JSON of the package versions
84
+ */
85
+ export function getNpmVersion(
86
+ versionType: VersionType,
87
+ err: Nullable<ExecException>,
88
+ stdout: string
89
+ ): Nullable<string> {
90
+ let npmVersion = null;
91
+ if (err?.message && err.message.indexOf("E404") !== -1) {
92
+ console.warn(`NPM registry does not have any ${versionType} version`);
93
+ } else if (err) {
94
+ console.error(err);
95
+ throw err;
96
+ } else {
97
+ npmVersion = stdout;
98
+ }
99
+ return npmVersion;
100
+ }
101
+
102
+ /**
103
+ * Compares two semver strings, returning -1 if version1 is less than version2, 1 if version1 is greater than version2, and 0 if they are equal
104
+ * @param version1 - The first semver string
105
+ * @param version2 - The second semver string
106
+ * @returns -1 if version1 is less than version2, 1 if version1 is greater than version2, and 0 if they are equal
107
+ */
108
+ export function compareVersions(version1: string, version2: string): number {
109
+ const version1split = removePrereleaseFlags(version1).split(".");
110
+ const version2split = removePrereleaseFlags(version2).split(".");
111
+
112
+ if (version1split.length !== 3 || version2split.length !== 3) {
113
+ throw new Error("version strings must have 3 parts");
114
+ }
115
+
116
+ for (let i = 0; i < 3; i++) {
117
+ const v1 = Number.parseInt(version1split[i]!);
118
+ const v2 = Number.parseInt(version2split[i]!);
119
+
120
+ if (v1 < v2) {
121
+ return -1;
122
+ } else if (v1 > v2) {
123
+ return 1;
124
+ }
125
+ }
126
+ return 0;
127
+ }