UNPKG

wle-uuidify

Version:

Switch Wonderland Engine project incremental number IDs to UUID

305 lines 17.6 kB
// #CREDITS https://github.com/playkostudios/wle-cleaner import { ArrayToken, JSONTokenType, ObjectToken, StringToken } from "@playkostudios/jsonc-ast"; import { Type } from "@wonderlandengine/api"; import crypto from "crypto"; import { format as formatPath, parse as parsePath, resolve as resolvePath } from 'node:path'; import { customPhysxMeshOptsType } from "../common/bundle/component_utils.js"; import { ParentChildTokenPair, getJSONTokensHierarchy, replaceParentTokenKey } from "../common/project/jsonast_utils.js"; export async function switchToUUID(project, projectComponentsDefinitions, commanderOptions, processReport) { processReport.myDuplicatedIDs.push(...getDuplicateIDs(project)); if (processReport.myDuplicatedIDs.length == 0) { const idTokens = getIDTokens(project, projectComponentsDefinitions, _isIncrementalNumberID, commanderOptions, processReport); _switchTokenToUUID(project.getAllObjectTokens(), idTokens, processReport); const duplicatedIDsAfterSwitch = getDuplicateIDs(project); if (duplicatedIDsAfterSwitch.length == 0 || commanderOptions.writeOnFail != null) { if (commanderOptions.replace != null) { await project.save(); } else { if (commanderOptions.output != null) { await project.save(resolvePath(commanderOptions.output)); } else { const uudifiedPath = parsePath(project.myPath); uudifiedPath.base = "uuidified-" + uudifiedPath.base; await project.save(formatPath(uudifiedPath)); } } processReport.myProcessCompleted = duplicatedIDsAfterSwitch.length == 0; } else { processReport.myDuplicatedIDAfterSwitch = true; } } } export function getDuplicateIDs(project) { const duplicatedIDs = []; const idsAlreadyFound = []; for (const objectToken of project.getAllObjectTokens()) { for (const [id, __tokenToCheck] of objectToken.getTokenEntries()) { if (idsAlreadyFound.indexOf(id) == -1) { idsAlreadyFound.push(id); } else { if (duplicatedIDs.indexOf(id) == -1) { duplicatedIDs.push(id); } } } } return duplicatedIDs; } export function getIDTokens(project, projectComponentsDefinitions, isIDCallback, commanderOptions, processReport) { const idTokens = []; idTokens.push(..._getIDTokensFromObjects(project, projectComponentsDefinitions, isIDCallback, commanderOptions, processReport)); idTokens.push(..._getIDTokensFromMaterials(project, isIDCallback, commanderOptions, processReport)); idTokens.push(..._getIDTokensFromSkins(project, isIDCallback, commanderOptions)); idTokens.push(..._getIDTokensFromPipelines(project, isIDCallback, commanderOptions)); idTokens.push(..._getIDTokensFromSettings(project, isIDCallback, commanderOptions)); return idTokens; } // PRIVATE function _getIDTokensFromMaterials(project, isIDCallback, commanderOptions, processReport) { const idTokens = []; for (const [__materialID, materialTokenToCheck] of project.myMaterials.getTokenEntries()) { const materialToken = ObjectToken.assert(materialTokenToCheck); const pipelineTokenToCheck = materialToken.maybeGetValueTokenOfKey("pipeline"); if (pipelineTokenToCheck) { if (pipelineTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(pipelineTokenToCheck).evaluate())) { idTokens.push(new ParentChildTokenPair(materialToken, StringToken.assert(pipelineTokenToCheck))); } } for (const [materialPropertyID, materialPropertyTokenToCheck] of materialToken.getTokenEntries()) { if (materialPropertyTokenToCheck.type == JSONTokenType.Object) { const materialPropertyToken = ObjectToken.assert(materialPropertyTokenToCheck); for (const [materialPropertyPropertyID, materialPropertyPropertyTokenToCheck] of materialPropertyToken.getTokenEntries()) { if (materialPropertyPropertyTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(materialPropertyPropertyTokenToCheck).evaluate())) { let pipelineShaderPropertiesAsID = processReport.myPipelineShaderPropertiesAsID.get(materialPropertyID); if (pipelineShaderPropertiesAsID == null) { processReport.myPipelineShaderPropertiesAsID.set(materialPropertyID, []); pipelineShaderPropertiesAsID = processReport.myPipelineShaderPropertiesAsID.get(materialPropertyID); } if (pipelineShaderPropertiesAsID?.indexOf(materialPropertyPropertyID) == -1) { pipelineShaderPropertiesAsID?.push(materialPropertyPropertyID); } idTokens.push(new ParentChildTokenPair(materialPropertyToken, StringToken.assert(materialPropertyPropertyTokenToCheck))); } } } } } return idTokens; } function _getIDTokensFromSettings(project, isIDCallback, commanderOptions) { const idTokens = []; idTokens.push(...getJSONTokensHierarchy(function (tokenKey, tokenToCheck) { return tokenKey == "viewObject" && tokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(tokenToCheck).evaluate()); }, project.mySettings)); idTokens.push(...getJSONTokensHierarchy(function (tokenKey, tokenToCheck) { return tokenKey == "leftEyeObject" && tokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(tokenToCheck).evaluate()); }, project.mySettings)); idTokens.push(...getJSONTokensHierarchy(function (tokenKey, tokenToCheck) { return tokenKey == "rightEyeObject" && tokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(tokenToCheck).evaluate()); }, project.mySettings)); idTokens.push(...getJSONTokensHierarchy(function (tokenKey, tokenToCheck) { return tokenKey == "appIcon" && tokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(tokenToCheck).evaluate()); }, project.mySettings)); idTokens.push(...getJSONTokensHierarchy(function (tokenKey, tokenToCheck) { return tokenKey == "material" && tokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(tokenToCheck).evaluate()); }, project.mySettings)); return idTokens; } function _getIDTokensFromSkins(project, isIDCallback, commanderOptions) { const idTokens = []; for (const [__skinID, skinTokenToCheck] of project.mySkins.getTokenEntries()) { const skinToken = ObjectToken.assert(skinTokenToCheck); const jointsTokenToCheck = skinToken.maybeGetValueTokenOfKey("joints"); if (jointsTokenToCheck) { if (jointsTokenToCheck.type === JSONTokenType.Array) { const jointsToken = ArrayToken.assert(jointsTokenToCheck); const jointIDTokensToCheck = jointsToken.getTokenEntries(); for (const jointIDTokenToCheck of jointIDTokensToCheck) { if (jointIDTokenToCheck.type == JSONTokenType.String && isIDCallback(StringToken.assert(jointIDTokenToCheck).evaluate())) { idTokens.push(new ParentChildTokenPair(jointsToken, StringToken.assert(jointIDTokenToCheck))); } } } } } return idTokens; } function _getIDTokensFromPipelines(project, isIDCallback, commanderOptions) { const idTokens = []; for (const [__pipelineID, pipelineTokenToCheck] of project.myPipelines.getTokenEntries()) { const pipelineToken = ObjectToken.assert(pipelineTokenToCheck); const shaderTokenToCheck = pipelineToken.maybeGetValueTokenOfKey("shader"); if (shaderTokenToCheck) { if (shaderTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(shaderTokenToCheck).evaluate())) { idTokens.push(new ParentChildTokenPair(pipelineToken, StringToken.assert(shaderTokenToCheck))); } } } return idTokens; } function _getIDTokensFromObjects(project, projectComponentsDefinitions, isIDCallback, commanderOptions, processReport) { const idTokens = []; for (const [__objectID, objectTokenToCheck] of project.myObjects.getTokenEntries()) { const objectToken = ObjectToken.assert(objectTokenToCheck); const parentTokenToCheck = objectToken.maybeGetValueTokenOfKey("parent"); if (parentTokenToCheck) { if (parentTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(parentTokenToCheck).evaluate())) { idTokens.push(new ParentChildTokenPair(objectToken, StringToken.assert(parentTokenToCheck))); } } const skinTokenToCheck = objectToken.maybeGetValueTokenOfKey("skin"); if (skinTokenToCheck) { if (skinTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(skinTokenToCheck).evaluate())) { idTokens.push(new ParentChildTokenPair(objectToken, StringToken.assert(skinTokenToCheck))); } } const componentsTokenToCheck = objectToken.maybeGetValueTokenOfKey("components"); if (componentsTokenToCheck) { const componentsToken = ArrayToken.assert(componentsTokenToCheck); const components = componentsToken.getTokenEntries(); for (const componentTokenToCheck of components) { if (componentTokenToCheck.type !== JSONTokenType.Object) continue; const componentToken = ObjectToken.assert(componentTokenToCheck); for (const [componentType, componentPropertiesTokenToCheck] of componentToken.getTokenEntries()) { if (componentPropertiesTokenToCheck.type == JSONTokenType.Object) { const projectComponentDefinitions = projectComponentsDefinitions.get(componentType); const componentPropertiesToken = ObjectToken.assert(componentPropertiesTokenToCheck); for (const [propertyKey, propertyValueTokenToCheck] of componentPropertiesToken.getTokenEntries()) { if (_isPropertyValueTokenID(propertyKey, propertyValueTokenToCheck, componentType, projectComponentDefinitions, isIDCallback, commanderOptions, processReport)) { idTokens.push(new ParentChildTokenPair(componentPropertiesToken, propertyValueTokenToCheck)); } else if (_isPhysXMeshToken(componentType, propertyKey, propertyValueTokenToCheck, projectComponentDefinitions, isIDCallback, commanderOptions, processReport)) { const objectPropertyValue = ObjectToken.assert(propertyValueTokenToCheck); const meshPropertyValueTokenToCheck = objectPropertyValue.maybeGetValueTokenOfKey("mesh"); if (meshPropertyValueTokenToCheck) { idTokens.push(new ParentChildTokenPair(objectPropertyValue, StringToken.assert(meshPropertyValueTokenToCheck))); } } } } } } } } return idTokens; } const _isPropertyValueTokenID = function () { const idTypes = [Type.Mesh, Type.Texture, Type.Animation, Type.Material, Type.Object, Type.Skin]; return function (propertyKey, propertyValueTokenToCheck, componentType, projectComponentDefinitions, isIDCallback, commanderOptions, processReport) { let isID = false; let propertyDefinition = null; if (projectComponentDefinitions) { propertyDefinition = projectComponentDefinitions[propertyKey]; } if (!propertyDefinition) { const isUnsafe = commanderOptions.unsafe != null; isID = propertyKey != "name" && propertyValueTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(propertyValueTokenToCheck).evaluate()); if (isID) { let componentPropertiesAsIDUnsafe = processReport.myComponentsPropertiesAsIDUnsafe.get(componentType); if (componentPropertiesAsIDUnsafe == null) { processReport.myComponentsPropertiesAsIDUnsafe.set(componentType, []); componentPropertiesAsIDUnsafe = processReport.myComponentsPropertiesAsIDUnsafe.get(componentType); } if (componentPropertiesAsIDUnsafe?.indexOf(propertyKey) == -1) { componentPropertiesAsIDUnsafe?.push(propertyKey); } } // If the unsafe flag is set and there is no definition, consider it as an ID return isID && isUnsafe; } if (idTypes.indexOf(propertyDefinition.type) >= 0) { isID = propertyValueTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(propertyValueTokenToCheck).evaluate()); } return isID; }; }(); function _isPhysXMeshToken(componentTypeToken, propertyKey, propertyValueTokenToCheck, projectComponentDefinitions, isIDCallback, commanderOptions, processReport) { let isPhysXMesh = false; let propertyDefinition = null; if (projectComponentDefinitions) { propertyDefinition = projectComponentDefinitions[propertyKey]; } if (!propertyDefinition) { if (componentTypeToken == "physx") { if (propertyKey == "convexMesh" || propertyKey == "triangleMesh") { if (propertyValueTokenToCheck.type == JSONTokenType.Object) { const objectPropertyValue = propertyValueTokenToCheck; const meshPropertyValueTokenToCheck = objectPropertyValue.maybeGetValueTokenOfKey("mesh"); if (meshPropertyValueTokenToCheck != null) { const isUnsafe = commanderOptions.unsafe != null; const isID = meshPropertyValueTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(meshPropertyValueTokenToCheck).evaluate()); if (isID) { let physxPropertiesAsIDUnsafe = processReport.myComponentsPropertiesAsIDUnsafe.get("physx"); if (physxPropertiesAsIDUnsafe == null) { processReport.myComponentsPropertiesAsIDUnsafe.set("physx", []); physxPropertiesAsIDUnsafe = processReport.myComponentsPropertiesAsIDUnsafe.get("physx"); } if (physxPropertiesAsIDUnsafe?.indexOf(propertyKey) == -1) { physxPropertiesAsIDUnsafe?.push(propertyKey); } } return isID && isUnsafe; } } } return false; } else { return false; } } if (propertyDefinition.type == customPhysxMeshOptsType) { if (propertyValueTokenToCheck.type == JSONTokenType.Object) { const objectPropertyValue = propertyValueTokenToCheck; const meshPropertyValueTokenToCheck = objectPropertyValue.maybeGetValueTokenOfKey("mesh"); if (meshPropertyValueTokenToCheck != null) { isPhysXMesh = meshPropertyValueTokenToCheck.type === JSONTokenType.String && isIDCallback(StringToken.assert(meshPropertyValueTokenToCheck).evaluate()); } } } return isPhysXMesh; } function _isIncrementalNumberID(id) { return parseInt(id).toFixed(0) == id; } const _randomUUID = function () { const uuidRandomValues = new Uint8Array(1); const uuidSkeleton = (1e7 + "-" + 1e3 + "-" + 4e3 + "-" + 8e3 + "-" + 1e11); const replaceUUIDSkeletonRegex = new RegExp("[018]", "g"); const replaceUUIDSkeletonCallback = function (charString) { const digit = parseInt(charString.charAt(0)); return (digit ^ ((crypto.getRandomValues(uuidRandomValues)[0] & 15)) >> (digit / 4)).toString(16); }; return function _randomUUID() { let uuid = ""; if (crypto.randomUUID != null) { uuid = crypto.randomUUID(); } else { uuid = uuidSkeleton.replace(replaceUUIDSkeletonRegex, replaceUUIDSkeletonCallback); } return uuid; }; }(); function _switchTokenToUUID(objectTokens, idTokens, processReport) { for (const objectToken of objectTokens) { for (const [id, __tokenToCheck] of objectToken.getTokenEntries()) { if (_isIncrementalNumberID(id)) { const uuid = _randomUUID(); replaceParentTokenKey(id, uuid, objectToken); for (const idTokenToReplace of idTokens) { const childID = StringToken.assert(idTokenToReplace.child).evaluate(); if (childID == id) { idTokenToReplace.parent.replaceChild(idTokenToReplace.child, StringToken.fromString(uuid)); } } } } } } //# sourceMappingURL=switch_to_uuid.js.map