diff --git a/.gitignore b/.gitignore index b293576..7332115 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ dist/ .DS_Store +.idea ## Rocket ignore files docs/_merged_data/ @@ -7,4 +8,4 @@ docs/_merged_assets/ docs/_merged_includes/ _site-dev _site -/node_modules \ No newline at end of file +/node_modules diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/fixture/custom-elements.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/fixture/custom-elements.json new file mode 100644 index 0000000..0f584cb --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/fixture/custom-elements.json @@ -0,0 +1,188 @@ +{ + "schemaVersion": "1.0.0", + "readme": "", + "modules": [ + { + "kind": "javascript-module", + "path": "my-element.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyElement", + "members": [ + { + "kind": "field", + "name": "extClassProp", + "type": { + "text": "string" + }, + "default": "'otherValueThanProp'" + }, + { + "kind": "field", + "name": "extMixinProp", + "type": { + "text": "string" + }, + "default": "'prop'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "extScoped", + "type": { + "text": "boolean" + }, + "default": "true", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ], + "superclass": { + "name": "MyClass", + "package": "@ext-scoped/same-path/MyClass.js" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "MyElement", + "declaration": { + "name": "MyElement", + "module": "my-element.js" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "my-element2.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyElement2", + "members": [ + { + "kind": "field", + "name": "extClassProp", + "type": { + "text": "string" + }, + "default": "'otherValueThanProp'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "ThirdClassProp", + "type": { + "text": "string" + }, + "default": "'three'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ], + "superclass": { + "name": "MyClass", + "package": "ext-pkg-without-export-map" + }, + "attributes": [ + { + "name": "ext-class-attr", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "MyElement2", + "declaration": { + "name": "MyElement2", + "module": "my-element2.js" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "my-element3.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyElement3", + "superclass": { + "name": "MyClass", + "package": "@other-package/same-path/MyClass.js" + }, + "members": [ + { + "kind": "field", + "name": "extMixinProp", + "type": { + "text": "string" + }, + "default": "'prop'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "shouldNotApear", + "type": { + "text": "string" + }, + "default": "'no'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "otherPackage", + "type": { + "text": "boolean" + }, + "default": "true", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "MyElement3", + "declaration": { + "name": "MyElement3", + "module": "my-element3.js" + } + } + ] + } + ] +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/output.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/output.json new file mode 100644 index 0000000..6c8392b --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/output.json @@ -0,0 +1,188 @@ +{ + "schemaVersion": "1.0.0", + "readme": "", + "modules": [ + { + "kind": "javascript-module", + "path": "my-element.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyElement", + "members": [ + { + "kind": "field", + "name": "extClassProp", + "type": { + "text": "string" + }, + "default": "'otherValueThanProp'" + }, + { + "kind": "field", + "name": "extMixinProp", + "type": { + "text": "string" + }, + "default": "'prop'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "extScoped", + "type": { + "text": "boolean" + }, + "default": "true", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ], + "superclass": { + "name": "MyClass", + "package": "@ext-scoped/same-path/MyClass.js" + } + } + ], + "exports": [ + { + "kind": "js", + "name": "MyElement", + "declaration": { + "name": "MyElement", + "module": "my-element.js" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "my-element2.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyElement2", + "members": [ + { + "kind": "field", + "name": "extClassProp", + "type": { + "text": "string" + }, + "default": "'otherValueThanProp'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "ThirdClassProp", + "type": { + "text": "string" + }, + "default": "'three'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ], + "superclass": { + "name": "MyClass", + "package": "ext-pkg-without-export-map" + }, + "attributes": [ + { + "name": "ext-class-attr", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "MyElement2", + "declaration": { + "name": "MyElement2", + "module": "my-element2.js" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "my-element3.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyElement3", + "superclass": { + "name": "MyClass", + "package": "@other-package/same-path/MyClass.js" + }, + "members": [ + { + "kind": "field", + "name": "extMixinProp", + "type": { + "text": "string" + }, + "default": "'prop'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "shouldNotApear", + "type": { + "text": "string" + }, + "default": "'no'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "otherPackage", + "type": { + "text": "boolean" + }, + "default": "true", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "MyElement3", + "declaration": { + "name": "MyElement3", + "module": "my-element3.js" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/.gitignore b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/.gitignore new file mode 100644 index 0000000..9bfb325 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/.gitignore @@ -0,0 +1 @@ +!node_modules/ \ No newline at end of file diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element.js new file mode 100644 index 0000000..efdadb8 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element.js @@ -0,0 +1,10 @@ +import { MyClass } from '@ext-scoped/same-path/MyClass.js'; + +export class MyElement extends MyClass { + constructor() { + super(); + + this.extClassProp = 'otherValueThanProp'; + } +} + diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element2.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element2.js new file mode 100644 index 0000000..1632135 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element2.js @@ -0,0 +1,11 @@ + +import { MyClass } from 'ext-pkg-without-export-map'; + + +export class MyElement2 extends MyClass { + constructor() { + super(); + + this.extClassProp = 'otherValueThanProp'; + } +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element3.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element3.js new file mode 100644 index 0000000..8810f3e --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/my-element3.js @@ -0,0 +1,5 @@ +import { MyClass } from '@other-package/same-path/MyClass.js'; + +export class MyElement3 extends MyClass { + +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/MyClass.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/MyClass.js new file mode 100644 index 0000000..4995f15 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/MyClass.js @@ -0,0 +1,10 @@ +export class MyClass extends HTMLElement { + + + constructor() { + super(); + this.dispatchEvent(new Event('ext-mixin-event')); + this.extMixinProp = 'prop'; + this.extScoped = true; + } +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/custom-elements.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/custom-elements.json new file mode 100644 index 0000000..18cd427 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/custom-elements.json @@ -0,0 +1,49 @@ +{ + "schemaVersion": "1.0.0", + "readme": "", + "modules": [ + { + "kind": "javascript-module", + "path": "MyClass.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyClass", + "members": [ + { + "kind": "field", + "name": "extMixinProp", + "type": { + "text": "string" + }, + "default": "'prop'" + }, + { + "kind": "field", + "name": "extScoped", + "type": { + "text": "boolean" + }, + "default": "true" + } + ], + "superclass": { + "name": "HTMLElement" + }, + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "MyClass", + "declaration": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + } + ] +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/package.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/package.json new file mode 100644 index 0000000..35fcb1c --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@ext-scoped/same-path/package.json @@ -0,0 +1,7 @@ +{ + "name": "@ext-scoped/same-path", + "version": "0.2.0", + "type": "module", + + "customElements": "custom-elements.json" +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/MyClass.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/MyClass.js new file mode 100644 index 0000000..54615f0 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/MyClass.js @@ -0,0 +1,12 @@ +export class MyClass extends HTMLElement { + + + + constructor() { + super(); + this.dispatchEvent(new Event('ext-mixin-event')); + this.extMixinProp = 'prop'; + this.shouldNotApear = 'no'; + this.otherPackage = true; + } +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/OtherElement.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/OtherElement.js new file mode 100644 index 0000000..ddf7b75 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/OtherElement.js @@ -0,0 +1,13 @@ + +export class OtherElement extends HTMLElement { + superClassField; + static observedAttributes = [...super.observedAttributes, 'superClass-attr']; + superClassMethod() { + this.dispatchEvent(new Event('superClass-event')) + } + + constructor() { + super(); + this.overriddenField = 'hello'; + } +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/custom-elements.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/custom-elements.json new file mode 100644 index 0000000..14ff7eb --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/custom-elements.json @@ -0,0 +1,113 @@ +{ + "schemaVersion": "1.0.0", + "readme": "", + "modules": [ + { + "kind": "javascript-module", + "path": "MyClass.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyClass", + "members": [ + { + "kind": "field", + "name": "extMixinProp", + "type": { + "text": "string" + }, + "default": "'prop'" + }, + { + "kind": "field", + "name": "shouldNotApear", + "type": { + "text": "string" + }, + "default": "'no'" + }, + { + "kind": "field", + "name": "otherPackage", + "type": { + "text": "boolean" + }, + "default": "true" + } + ], + "superclass": { + "name": "HTMLElement" + }, + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "MyClass", + "declaration": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "OtherElement.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "OtherElement", + "members": [ + { + "kind": "field", + "name": "superClassField" + }, + { + "kind": "method", + "name": "superClassMethod" + }, + { + "kind": "field", + "name": "overriddenField", + "type": { + "text": "string" + }, + "default": "'hello'" + } + ], + "events": [ + { + "name": "superClass-event", + "type": { + "text": "Event" + } + } + ], + "attributes": [ + { + "name": "superClass-attr" + } + ], + "superclass": { + "name": "HTMLElement" + }, + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "OtherElement", + "declaration": { + "name": "OtherElement", + "module": "OtherElement.js" + } + } + ] + } + ] +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/package.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/package.json new file mode 100644 index 0000000..ea3274a --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/@other-package/same-path/package.json @@ -0,0 +1,6 @@ +{ + "name": "@other-package/same-path", + "version": "0.2.0", + "type": "module", + "customElements": "custom-elements.json" +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/MyClass.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/MyClass.js new file mode 100644 index 0000000..d3cebac --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/MyClass.js @@ -0,0 +1,13 @@ +export class MyClass extends HTMLElement { + static get observedAttributes() { + return ['ext-class-attr']; + } + + constructor() { + super(); + this.dispatchEvent(new Event('ext-class-event')); + + this.extClassProp = 'prop'; + this.ThirdClassProp = 'three'; + } +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/MyClassWithMyMixin.js b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/MyClassWithMyMixin.js new file mode 100644 index 0000000..73f5cf1 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/MyClassWithMyMixin.js @@ -0,0 +1,4 @@ +import {MyMixin} from '@ext-scoped/with-export-map'; +import {MyClass} from './MyClass.js'; + +export class MyClassWithMyMixin extends MyMixin(MyClass) {} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/custom-elements.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/custom-elements.json new file mode 100644 index 0000000..8ae1fb3 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/custom-elements.json @@ -0,0 +1,120 @@ +{ + "schemaVersion": "1.0.0", + "readme": "", + "modules": [ + { + "kind": "javascript-module", + "path": "MyClass.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyClass", + "members": [ + { + "kind": "field", + "name": "extClassProp", + "type": { + "text": "string" + }, + "default": "'prop'" + }, + { + "kind": "field", + "name": "ThirdClassProp", + "type": { + "text": "string" + }, + "default": "'three'" + } + ], + "attributes": [ + { + "name": "ext-class-attr" + } + ], + "superclass": { + "name": "HTMLElement" + }, + "customElement": true + } + ], + "exports": [ + { + "kind": "js", + "name": "MyClass", + "declaration": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + }, + { + "kind": "javascript-module", + "path": "MyClassWithMyMixin.js", + "declarations": [ + { + "kind": "class", + "description": "", + "name": "MyClassWithMyMixin", + "mixins": [ + { + "name": "MyMixin", + "package": "@ext-scoped/with-export-map" + } + ], + "superclass": { + "name": "MyClass", + "module": "/MyClass.js" + }, + "attributes": [ + { + "name": "ext-class-attr", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ], + "members": [ + { + "kind": "field", + "name": "extClassProp", + "type": { + "text": "string" + }, + "default": "'prop'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + }, + { + "kind": "field", + "name": "ThirdClassProp", + "type": { + "text": "string" + }, + "default": "'three'", + "inheritedFrom": { + "name": "MyClass", + "module": "MyClass.js" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "MyClassWithMyMixin", + "declaration": { + "name": "MyClassWithMyMixin", + "module": "MyClassWithMyMixin.js" + } + } + ] + } + ] +} diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/package.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/package.json new file mode 100644 index 0000000..8c8ee65 --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/node_modules/ext-pkg-without-export-map/package.json @@ -0,0 +1,7 @@ +{ + "name": "ext-pkg-without-export-map", + "version": "0.1.0", + "type": "module", + "main": "MyClass.js", + "customElements": "custom-elements.json" +} \ No newline at end of file diff --git a/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/package.json b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/package.json new file mode 100644 index 0000000..581d8cd --- /dev/null +++ b/packages/analyzer/fixtures/02-inheritance/06-multiple-packages/package/package.json @@ -0,0 +1,10 @@ +{ + "name": "local-pkg", + "type": "module", + "main": "my-element.js", + "dependencies": { + "ext-pkg-without-export-map": "0.1.0", + "@ext-scoped/same-path": "0.2.0", + "@other-package/same-path": "0.2.0" + } +} diff --git a/packages/analyzer/src/features/post-processing/apply-inheritance.js b/packages/analyzer/src/features/post-processing/apply-inheritance.js index bd4e9b1..75613f0 100644 --- a/packages/analyzer/src/features/post-processing/apply-inheritance.js +++ b/packages/analyzer/src/features/post-processing/apply-inheritance.js @@ -1,5 +1,11 @@ -import { getAllDeclarationsOfKind, getModuleForClassLike, getModuleFromManifests, getInheritanceTree } from '../../utils/manifest-helpers.js'; -import { resolveModuleOrPackageSpecifier } from '../../utils/index.js'; +import { + getAllDeclarationsOfKind, + getInheritanceTree, + getModuleForClassLike, + getModuleFromManifests, + getPackageName +} from '../../utils/manifest-helpers.js'; +import {resolveModuleOrPackageSpecifier} from '../../utils/index.js'; /** * APPLY-INHERITANCE-PLUGIN @@ -9,18 +15,22 @@ import { resolveModuleOrPackageSpecifier } from '../../utils/index.js'; export function applyInheritancePlugin() { return { name: 'CORE - APPLY-INHERITANCE', - packageLinkPhase({customElementsManifest, context}){ + packageLinkPhase({customElementsManifest, context}) { + // set package name for cem of this project + customElementsManifest.packageName = getPackageName(); + const allManifests = [customElementsManifest, ...(context.thirdPartyCEMs || [])]; const classLikes = []; allManifests.forEach((manifest) => { - const classes = getAllDeclarationsOfKind(manifest, 'class'); - const mixins = getAllDeclarationsOfKind(manifest, 'mixin'); + const classes = getAllDeclarationsOfKind(manifest, 'class'); + const mixins = getAllDeclarationsOfKind(manifest, 'mixin'); classLikes.push(...[...classes, ...mixins]); }); classLikes.forEach((customElement) => { - const inheritanceChain = getInheritanceTree(allManifests, customElement.name); + + const inheritanceChain = getInheritanceTree(allManifests, customElement.name, customElement.packageName); inheritanceChain?.forEach(klass => { // ignore the current class itself @@ -33,13 +43,13 @@ export function applyInheritancePlugin() { const containingModulePath = getModuleForClassLike(allManifests, klass.name); const containingModule = getModuleFromManifests(allManifests, containingModulePath); - const newItem = { ...currItem }; + const newItem = {...currItem}; /** - * If an attr or member is already present in the base class, but we encounter it here, - * it means that the base has overridden that method from the super class - * So we either add the data to the overridden method, or we add it to the array as a new item - */ + * If an attr or member is already present in the base class, but we encounter it here, + * it means that the base has overridden that method from the super class + * So we either add the data to the overridden method, or we add it to the array as a new item + */ const existing = customElement?.[type]?.find(item => newItem.name === item.name); if (existing) { @@ -50,15 +60,15 @@ export function applyInheritancePlugin() { } customElement[type] = customElement?.[type]?.map(item => item.name === existing.name - ? { + ? { ...newItem, ...existing, ...{ - ...(newItem.type ? { type: newItem.type } : {}), - ...(newItem.privacy ? { privacy: newItem.privacy } : {}) + ...(newItem.type ? {type: newItem.type} : {}), + ...(newItem.privacy ? {privacy: newItem.privacy} : {}) } } - : item); + : item); } else { newItem.inheritedFrom = { name: klass.name, @@ -66,11 +76,20 @@ export function applyInheritancePlugin() { } customElement[type] = [...(customElement[type] || []), newItem]; - }; + } }); }); }); }); + + // clean up the manifest (remove the added packageName entries from the declaration) + delete customElementsManifest.packageName + customElementsManifest.modules.forEach(module => { + module.declarations.forEach((declaration) => { + delete declaration.packageName; + }) + + }) } } } diff --git a/packages/analyzer/src/utils/find-external-manifests.js b/packages/analyzer/src/utils/find-external-manifests.js index e034c1e..6684ffb 100644 --- a/packages/analyzer/src/utils/find-external-manifests.js +++ b/packages/analyzer/src/utils/find-external-manifests.js @@ -1,6 +1,6 @@ import fs from 'fs'; import path from 'path'; -import { findDependencies, splitPath } from '@custom-elements-manifest/find-dependencies'; +import {findDependencies, splitPath} from '@custom-elements-manifest/find-dependencies'; /** * @typedef {import('custom-elements-manifest/schema').Package} Package @@ -27,36 +27,38 @@ export async function findExternalManifests(paths, {basePath = process.cwd(), no return; } - const { packageRoot, packageName } = splitPath(dependencyPath); + const {packageRoot, packageName} = splitPath(dependencyPath); - if(visited.has(packageName)) return; + if (visited.has(packageName)) return; visited.add(packageName); const packageJsonPath = `${packageRoot}${path.sep}package.json`; const cemPath = `${packageRoot}${path.sep}custom-elements.json`; /** Try to find `custom-elements.json` at `node_modules/specifier/custom-elements.json` */ - if(fs.existsSync(cemPath)) { + if (fs.existsSync(cemPath)) { try { const cem = JSON.parse(fs.readFileSync(cemPath).toString()); + cem.packageName = packageName; cemsToMerge.push(cem); return; - } catch(e) { + } catch (e) { throw new Error(`Failed to read custom-elements.json at path "${cemPath}". \n\n${e.stack}`); } } /** See if the `package.json` has a `customElements` field or if it has listed `./customElements` in its export map */ - if(fs.existsSync(packageJsonPath)) { + if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()); const cemLocation = packageJson?.customElements || packageJson?.exports?.['./customElements']; - if(cemLocation) { + if (cemLocation) { try { const cemPath = path.resolve(packageRoot, cemLocation); const cem = JSON.parse(fs.readFileSync(cemPath).toString()); + cem.packageName = packageJson.name; cemsToMerge.push(cem); - } catch(e) { + } catch (e) { throw new Error(`Failed to read custom-elements.json at path "${cemPath}". \n\n${e.stack}`); } } diff --git a/packages/analyzer/src/utils/manifest-helpers.js b/packages/analyzer/src/utils/manifest-helpers.js index fcb5f94..fd4ec40 100644 --- a/packages/analyzer/src/utils/manifest-helpers.js +++ b/packages/analyzer/src/utils/manifest-helpers.js @@ -2,7 +2,11 @@ * UTILITIES RELATED TO GETTING INFORMATION OUT OF A MANIFEST OR DOC */ -import { has } from "./index.js"; +import {has} from "./index.js"; + +import path from 'path'; +import fs from 'fs'; + /** * @typedef {import('custom-elements-manifest/schema').Package} Package @@ -29,13 +33,25 @@ function loopThroughExports(manifest, predicate) { export function getAllExportsOfKind(manifest, kind) { const result = []; loopThroughExports(manifest, (_export) => { - if(_export.kind === kind) { + if (_export.kind === kind) { result.push(_export); } }); return result; } +/** + * Returns the package name from current projects package.json + * @returns {*} + */ +export function getPackageName() { + const pkgPath = path.join(process.cwd(), 'package.json'); + + if (fs.existsSync(pkgPath)) { + let pkg = JSON.parse(fs.readFileSync(pkgPath)); + return pkg.name; + } +} /** * Loops through all modules' declarations, and returns the kind provided by the users @@ -46,7 +62,9 @@ export function getAllExportsOfKind(manifest, kind) { export function getAllDeclarationsOfKind(manifest, kind) { const result = []; loopThroughDeclarations(manifest, (declaration) => { - if(declaration.kind === kind) { + if (declaration.kind === kind) { + // add package name + declaration.packageName = manifest.packageName; result.push(declaration); } }); @@ -59,8 +77,9 @@ export function getAllDeclarationsOfKind(manifest, kind) { * * @param {Package[]} manifests * @param {string} className + * @param {string} packageName */ -export function getInheritanceTree(manifests, className) { +export function getInheritanceTree(manifests, className, packageName) { const tree = []; const allClassLikes = new Map(); const _classes = []; @@ -72,23 +91,23 @@ export function getInheritanceTree(manifests, className) { }); [..._mixins, ..._classes].forEach((klass) => { - allClassLikes.set(klass.name, klass); + allClassLikes.set(klass.packageName + "/" + klass.name, klass); }); - let klass = allClassLikes.get(className) + let klass = allClassLikes.get(packageName + "/" + className); - if(klass) { + if (klass) { tree.push(klass) klass?.mixins?.forEach(mixin => { let foundMixin = _mixins.find(m => m.name === mixin.name); - if(foundMixin) { + if (foundMixin) { tree.push(foundMixin); - while(has(foundMixin?.mixins)) { + while (has(foundMixin?.mixins)) { foundMixin?.mixins?.forEach(mixin => { - foundMixin = _mixins.find(m => m.name === mixin.name); - if(foundMixin) { + foundMixin = _mixins.find(m => m.name === mixin.name); + if (foundMixin) { tree.push(foundMixin); } }); @@ -96,8 +115,26 @@ export function getInheritanceTree(manifests, className) { } }); - while(allClassLikes.has(klass.superclass?.name)) { - const newKlass = allClassLikes.get(klass.superclass.name); + /** + * https://github.com/webcomponents/custom-elements-manifest/blob/d2f79f0d22c4d48a68628cf867c2319576ffc5d2/schema.d.ts#L179 + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + */ + function evalKlassPath(klass) { + if (klass.superclass?.package === undefined) { + // if there is no package name defined, the imported class must be in the same package as the current class + return klass.packageName + "/" + klass.superclass?.name; + }else{ + // Sometimes CEM places the full path in to `klass.superclass.package` during the analyzing phase, therefore we use the regex to be sure. + const matches = klass.superclass.package.match(/^(@[^\/]*\/[^\/]*|[^\/]*)/); + return matches[0] + "/" + klass.superclass?.name; + } + } + + while (allClassLikes.has(evalKlassPath(klass))) { + + const newKlass = allClassLikes.get(evalKlassPath(klass)); let allMixins = []; if (klass?.mixins) { allMixins = [...klass.mixins]; @@ -108,13 +145,13 @@ export function getInheritanceTree(manifests, className) { allMixins.forEach(mixin => { let foundMixin = _mixins.find(m => m.name === mixin.name); - if(foundMixin) { + if (foundMixin) { tree.push(foundMixin); - while(has(foundMixin?.mixins)) { + while (has(foundMixin?.mixins)) { foundMixin?.mixins?.forEach(mixin => { - foundMixin = _mixins.find(m => m.name === mixin.name); - if(foundMixin) { + foundMixin = _mixins.find(m => m.name === mixin.name); + if (foundMixin) { tree.push(foundMixin); } }); @@ -124,6 +161,7 @@ export function getInheritanceTree(manifests, className) { tree.push(newKlass); klass = newKlass; + } return tree; } @@ -134,10 +172,10 @@ export function getInheritanceTree(manifests, className) { * @param {Package[]} manifests * @param {string} modulePath */ - export function getModuleFromManifests(manifests, modulePath) { - let result = undefined; +export function getModuleFromManifests(manifests, modulePath) { + let result = undefined; - manifests.forEach((cem) => { + manifests.forEach((cem) => { cem?.modules?.forEach((_module) => { if (_module.path === modulePath) { result = _module; @@ -152,13 +190,13 @@ export function getInheritanceTree(manifests, className) { * @param {Package[]} manifests * @param {string} className */ - export function getModuleForClassLike(manifests, className) { +export function getModuleForClassLike(manifests, className) { let result = undefined; manifests.forEach((cem) => { cem?.modules?.forEach(_module => { _module?.declarations?.forEach(declaration => { - if((declaration.kind === 'class' || declaration.kind === 'mixin') && declaration.name === className) { + if ((declaration.kind === 'class' || declaration.kind === 'mixin') && declaration.name === className) { result = _module.path; } }); @@ -186,8 +224,8 @@ export function getClassMemberDoc(moduleDoc, className, memberName, isStatic = f return; const memberDoc = classDoc.members.find(x => - x.name === memberName && - (x.static ?? false) === isStatic + x.name === memberName && + (x.static ?? false) === isStatic ); return memberDoc;