diff --git a/.gitignore b/.gitignore index 6efaab0b80..c0718fd944 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .gradle/ +**/bin/ **/build /*/ignite/ .DS_Store diff --git a/model-api/src/jsMain/kotlin/org/modelix/model/api/NodeAdapterJS.kt b/model-api/src/jsMain/kotlin/org/modelix/model/api/NodeAdapterJS.kt index f130b6be44..665e695950 100644 --- a/model-api/src/jsMain/kotlin/org/modelix/model/api/NodeAdapterJS.kt +++ b/model-api/src/jsMain/kotlin/org/modelix/model/api/NodeAdapterJS.kt @@ -68,7 +68,10 @@ class NodeAdapterJS(val node: INode) : INodeJS_ { return node.reference.serialize() } - override fun getRoleInParent(): ChildRole? = node.roleInParent + override fun getRoleInParent(): ChildRole? { + val role = node.roleInParent ?: return null + return IChildLinkReference.fromLegacyApi(role).getIdOrName() + } override fun getParent(): INodeJS? = node.parent?.let { NodeAdapterJS(it) } @@ -102,7 +105,7 @@ class NodeAdapterJS(val node: INode) : INodeJS_ { } override fun getReferenceRoles(): Array { - return node.getReferenceRoles().toTypedArray() + return node.getReferenceRoles().map { IReferenceLinkReference.fromLegacyApi(it).getIdOrName() as ReferenceRole }.toTypedArray() } override fun getReferenceTargetNode(role: ReferenceRole): INodeJS? { @@ -127,7 +130,7 @@ class NodeAdapterJS(val node: INode) : INodeJS_ { } override fun getPropertyRoles(): Array { - return node.getPropertyRoles().toTypedArray() + return node.getPropertyRoles().map { IPropertyReference.fromLegacyApi(it).getIdOrName() as PropertyRole }.toTypedArray() } override fun getPropertyValue(role: PropertyRole): String? { diff --git a/ts-model-api/package.json b/ts-model-api/package.json index 11b64e9779..6ffcdca4be 100644 --- a/ts-model-api/package.json +++ b/ts-model-api/package.json @@ -21,6 +21,7 @@ ], "type": "commonjs", "main": "dist/index", + "module": "dist/index.js", "typings": "dist/index.d.ts", "types": "dist/index.d.ts", "scripts": { diff --git a/ts-model-api/src/LanguageRegistry.ts b/ts-model-api/src/LanguageRegistry.ts index addee3ee38..6d3cb6403a 100644 --- a/ts-model-api/src/LanguageRegistry.ts +++ b/ts-model-api/src/LanguageRegistry.ts @@ -4,8 +4,19 @@ import type {ITypedNode} from "./TypedNode.js"; import { TypedNode, UnknownTypedNode} from "./TypedNode.js"; import type {IConceptJS} from "./IConceptJS.js"; +const GLOBAL_INSTANCE_KEY = "__modelix_LanguageRegistry_INSTANCE__"; + export class LanguageRegistry { - public static INSTANCE: LanguageRegistry = new LanguageRegistry(); + public static readonly INSTANCE: LanguageRegistry = (() => { + const g = globalThis as unknown as Record; + let instance = g[GLOBAL_INSTANCE_KEY]; + if (!instance) { + instance = new LanguageRegistry(); + g[GLOBAL_INSTANCE_KEY] = instance; + } + return instance; + })(); + private languages: Map = new Map(); private nodeWrappers: Map TypedNode> | undefined = undefined private concepts: Map | undefined = undefined diff --git a/ts-model-api/src/index.ts b/ts-model-api/src/index.ts index 8e269ec572..c62b0add50 100644 --- a/ts-model-api/src/index.ts +++ b/ts-model-api/src/index.ts @@ -1,10 +1,9 @@ - -export * from "./ChildrenAccessor.js" -export * from "./GeneratedConcept.js" -export * from "./GeneratedLanguage.js" -export * from "./IConceptJS.js" -export * from "./ILanguage.js" -export * from "./INodeJS.js" -export * from "./LanguageRegistry.js" -export * from "./TSModelClient.js" -export * from "./TypedNode.js" +export { ChildrenAccessor, ChildListAccessor, SingleChildAccessor } from "./ChildrenAccessor.js" +export { GeneratedConcept } from "./GeneratedConcept.js" +export { GeneratedLanguage } from "./GeneratedLanguage.js" +export { IConceptJS } from "./IConceptJS.js" +export { ILanguage } from "./ILanguage.js" +export { ChildRole, ReferenceRole, PropertyRole, toRoleJS, INodeJS } from "./INodeJS.js" +export { LanguageRegistry } from "./LanguageRegistry.js" +export { NodeId, IModelServerConnection, ModelService } from "./TSModelClient.js" +export { TypedNode, ITypedNode, UnknownTypedNode } from "./TypedNode.js" diff --git a/ts-model-api/tsconfig.json b/ts-model-api/tsconfig.json index a8bbad75be..7511be7a3a 100644 --- a/ts-model-api/tsconfig.json +++ b/ts-model-api/tsconfig.json @@ -28,7 +28,7 @@ "outDir": "dist", "declarationDir": "dist", "noUnusedLocals": false, - "module": "CommonJS", + "module": "ESNext", "resolveJsonModule": false, "target": "ES2020" }, diff --git a/vue-model-api/jest.config.js b/vue-model-api/jest.config.js index 3f12319470..2ab4ff78c3 100644 --- a/vue-model-api/jest.config.js +++ b/vue-model-api/jest.config.js @@ -1,6 +1,15 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { - preset: "ts-jest", + transform: { + "^.+\\.(t|j)sx?$": ["ts-jest", { tsconfig: { allowJs: true } }], + }, + moduleNameMapper: { + "^@modelix/ts-model-api$": "/../ts-model-api/src/index.ts", + "^@modelix/ts-model-api/(.*)\\.js$": "/../ts-model-api/src/$1", + "^@modelix/ts-model-api/(.*)$": "/../ts-model-api/src/$1", + "^(\\..*)\\.js$": "$1", + }, modulePathIgnorePatterns: ["/dist/"], testEnvironment: "node", + transformIgnorePatterns: ["node_modules/(?!(@modelix)/)"], }; diff --git a/vue-model-api/package.json b/vue-model-api/package.json index 6e5ee86945..f65e717c42 100644 --- a/vue-model-api/package.json +++ b/vue-model-api/package.json @@ -9,6 +9,7 @@ "directory": "vue-model-api" }, "main": "dist/index.js", + "module": "dist/index.js", "files": [ "dist/" ], diff --git a/vue-model-api/src/internal/RoleStandardization.test.ts b/vue-model-api/src/internal/RoleStandardization.test.ts new file mode 100644 index 0000000000..098a0db30c --- /dev/null +++ b/vue-model-api/src/internal/RoleStandardization.test.ts @@ -0,0 +1,46 @@ +import { expect, test } from "@jest/globals"; +import { useModelsFromJson } from "../useModelsFromJson"; +import { toRoleJS } from "@modelix/ts-model-api"; + +const root = { + root: { + children: [ + { + role: "children1", + properties: { + name: "child0", + }, + }, + ], + }, +}; + +test("role in parent is standardized", () => { + const rootNode = useModelsFromJson([JSON.stringify(root)]); + // Use a combined format role that should be standardized + const roleJS = toRoleJS(":UID_123:newChildRole"); + const child = rootNode.addNewChild(roleJS, -1, undefined); + + const role = child.getRoleInParent(); + console.log("DEBUG: role =", JSON.stringify(role)); + + // We expect the role to be either the UID or the name, but NEVER the combined format starting with ":" + expect(role).not.toMatch(/^:/); + + // Further, since we use getIdOrName() or getNameOrId(), it should be one of the two parts. + const possibleValues = ["UID_123", "newChildRole"]; + expect(possibleValues).toContain(role); +}); + +test("property roles are standardized", () => { + const rootNode = useModelsFromJson([JSON.stringify(root)]); + const child = rootNode.getChildren(toRoleJS("children1"))[0]; + + const properties = child.getPropertyRoles(); + + expect(properties).toContain("name"); + // Ensure no combined formats are present + properties.forEach((p) => { + expect(p as unknown as string).not.toMatch(/^:/); + }); +}); diff --git a/vue-model-api/tsconfig.json b/vue-model-api/tsconfig.json index db83b45422..656c47a893 100644 --- a/vue-model-api/tsconfig.json +++ b/vue-model-api/tsconfig.json @@ -7,6 +7,8 @@ "rootDir": "src", "outDir": "dist", // 2021 is needed for FinalizationRegistry + "module": "ESNext", + "moduleResolution": "Node", "target": "es2021" } }