⚠️ Very experimental and very unfinished
Custom-elements.json is a file format that describes custom elements. This format will allow tooling and IDEs to give rich information about the custom elements in a given project. It is, however, very experimental and things are subject to change. Follow the discussion here.
This library aims to ship some helpers to ease working with the custom-elements.json format.
// Node
import { CustomElementsJson } from '@custom-elements-json/helpers';
const foo = JSON.parse(fs.readFileSync('./custom-elements.json', 'utf-8'))
const customElementsJson = new CustomElementsJson(json);
// Browser
import { CustomElementsJson } from 'https://unpkg.com/@custom-elements-json/helpers/dist/esm/index.js';
const json = await (await fetch('./custom-elements.json')).json();
const customElementsJson = new CustomElementsJson(json);
Returns all information for element <my-element>
.
customElementsJson.getByTagName('my-element');
custom-elements.json
{
"version": "experimental",
"modules": [
{
"path": "./src/MyMixinB.js",
"exports": [
{
"kind": "variable",
"name": "MyMixinB",
"type": "(klass: any) => typeof MyMixinB"
}
]
},
{
"path": "./src/MySuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MySuperClass",
"mixins": [
{
"name": "MyMixinB",
"module": "./src/MyMixinB.js"
}
],
"members": [
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\""
}
]
}
]
},
{
"path": "./src/AnotherSuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
},
"name": "AnotherSuperClass",
"members": [
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\""
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
]
}
]
},
{
"path": "./src/my-element.js",
"exports": [
{
"kind": "definition",
"name": "my-element",
"declaration": {
"name": "MyElement",
"module": "./src/my-element.js"
}
},
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MyElement",
"members": [
{
"kind": "field",
"name": "foo",
"type": "string",
"default": "\"bar\""
}
],
"tagName": "my-element"
}
]
},
{
"path": "./src/another-component.js",
"exports": [
{
"kind": "definition",
"name": "another-component",
"declaration": {
"name": "AnotherComponent",
"module": "./src/another-component.js"
}
},
{
"kind": "class",
"superclass": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
},
"name": "AnotherComponent",
"members": [
{
"kind": "field",
"name": "baz",
"type": "string",
"default": "\"bar\""
},
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\"",
"inheritedFrom": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
}
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
],
"tagName": "another-component"
}
]
}
]
}
Result
{
kind: 'class',
superclass: { name: 'HTMLElement' },
name: 'MyElement',
members: [ { kind: 'field', name: 'foo', type: 'string', default: '"bar"' } ],
tagName: 'my-element'
}
Returns all information for class MyElement
.
customElementsJson.getByClassName('MyElement');
custom-elements.json
{
"version": "experimental",
"modules": [
{
"path": "./src/MyMixinB.js",
"exports": [
{
"kind": "variable",
"name": "MyMixinB",
"type": "(klass: any) => typeof MyMixinB"
}
]
},
{
"path": "./src/MySuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MySuperClass",
"mixins": [
{
"name": "MyMixinB",
"module": "./src/MyMixinB.js"
}
],
"members": [
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\""
}
]
}
]
},
{
"path": "./src/AnotherSuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
},
"name": "AnotherSuperClass",
"members": [
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\""
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
]
}
]
},
{
"path": "./src/my-element.js",
"exports": [
{
"kind": "definition",
"name": "my-element",
"declaration": {
"name": "MyElement",
"module": "./src/my-element.js"
}
},
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MyElement",
"members": [
{
"kind": "field",
"name": "foo",
"type": "string",
"default": "\"bar\""
}
],
"tagName": "my-element"
}
]
},
{
"path": "./src/another-component.js",
"exports": [
{
"kind": "definition",
"name": "another-component",
"declaration": {
"name": "AnotherComponent",
"module": "./src/another-component.js"
}
},
{
"kind": "class",
"superclass": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
},
"name": "AnotherComponent",
"members": [
{
"kind": "field",
"name": "baz",
"type": "string",
"default": "\"bar\""
},
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\"",
"inheritedFrom": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
}
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
],
"tagName": "another-component"
}
]
}
]
}
Result
{
kind: 'class',
superclass: { name: 'HTMLElement' },
name: 'MyElement',
members: [ { kind: 'field', name: 'foo', type: 'string', default: '"bar"' } ],
tagName: 'my-element'
}
Returns all classes in a custom-elements.json
customElementsJson.getClasses();
custom-elements.json
{
"version": "experimental",
"modules": [
{
"path": "./src/MyMixinB.js",
"exports": [
{
"kind": "variable",
"name": "MyMixinB",
"type": "(klass: any) => typeof MyMixinB"
}
]
},
{
"path": "./src/MySuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MySuperClass",
"mixins": [
{
"name": "MyMixinB",
"module": "./src/MyMixinB.js"
}
],
"members": [
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\""
}
]
}
]
},
{
"path": "./src/AnotherSuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
},
"name": "AnotherSuperClass",
"members": [
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\""
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
]
}
]
},
{
"path": "./src/my-element.js",
"exports": [
{
"kind": "definition",
"name": "my-element",
"declaration": {
"name": "MyElement",
"module": "./src/my-element.js"
}
},
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MyElement",
"members": [
{
"kind": "field",
"name": "foo",
"type": "string",
"default": "\"bar\""
}
],
"tagName": "my-element"
}
]
},
{
"path": "./src/another-component.js",
"exports": [
{
"kind": "definition",
"name": "another-component",
"declaration": {
"name": "AnotherComponent",
"module": "./src/another-component.js"
}
},
{
"kind": "class",
"superclass": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
},
"name": "AnotherComponent",
"members": [
{
"kind": "field",
"name": "baz",
"type": "string",
"default": "\"bar\""
},
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\"",
"inheritedFrom": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
}
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
],
"tagName": "another-component"
}
]
}
]
}
Result
[
{
kind: 'class',
superclass: { name: 'HTMLElement' },
name: 'MySuperClass',
mixins: [ [Object] ],
members: [ [Object] ]
},
{
kind: 'class',
superclass: { name: 'MySuperClass', module: './src/MySuperClass.js' },
name: 'AnotherSuperClass',
members: [ [Object], [Object] ]
},
{
kind: 'class',
superclass: { name: 'HTMLElement' },
name: 'MyElement',
members: [ [Object] ],
tagName: 'my-element'
},
{
kind: 'class',
superclass: { name: 'AnotherSuperClass', module: './src/AnotherSuperClass.js' },
name: 'AnotherComponent',
members: [ [Object], [Object], [Object] ],
tagName: 'another-component'
}
]
Returns all mixins in a custom-elements.json
customElementsJson.getMixins();
custom-elements.json
{
"version": "experimental",
"modules": [
{
"path": "./src/MyMixinB.js",
"exports": [
{
"kind": "variable",
"name": "MyMixinB",
"type": "(klass: any) => typeof MyMixinB"
}
]
},
{
"path": "./src/MySuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MySuperClass",
"mixins": [
{
"name": "MyMixinB",
"module": "./src/MyMixinB.js"
}
],
"members": [
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\""
}
]
}
]
},
{
"path": "./src/AnotherSuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
},
"name": "AnotherSuperClass",
"members": [
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\""
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
]
}
]
},
{
"path": "./src/my-element.js",
"exports": [
{
"kind": "definition",
"name": "my-element",
"declaration": {
"name": "MyElement",
"module": "./src/my-element.js"
}
},
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MyElement",
"members": [
{
"kind": "field",
"name": "foo",
"type": "string",
"default": "\"bar\""
}
],
"tagName": "my-element"
}
]
},
{
"path": "./src/another-component.js",
"exports": [
{
"kind": "definition",
"name": "another-component",
"declaration": {
"name": "AnotherComponent",
"module": "./src/another-component.js"
}
},
{
"kind": "class",
"superclass": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
},
"name": "AnotherComponent",
"members": [
{
"kind": "field",
"name": "baz",
"type": "string",
"default": "\"bar\""
},
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\"",
"inheritedFrom": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
}
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
],
"tagName": "another-component"
}
]
}
]
}
Result
[
{
name: 'MyMixinB',
module: './src/MyMixinB.js',
kind: 'variable',
type: '(klass: any) => typeof MyMixinB'
}
]
Returns all custom element definitions in a custom-elements.json
customElementsJson.getDefinitions();
custom-elements.json
{
"version": "experimental",
"modules": [
{
"path": "./src/MyMixinB.js",
"exports": [
{
"kind": "variable",
"name": "MyMixinB",
"type": "(klass: any) => typeof MyMixinB"
}
]
},
{
"path": "./src/MySuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MySuperClass",
"mixins": [
{
"name": "MyMixinB",
"module": "./src/MyMixinB.js"
}
],
"members": [
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\""
}
]
}
]
},
{
"path": "./src/AnotherSuperClass.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
},
"name": "AnotherSuperClass",
"members": [
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\""
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
]
}
]
},
{
"path": "./src/my-element.js",
"exports": [
{
"kind": "definition",
"name": "my-element",
"declaration": {
"name": "MyElement",
"module": "./src/my-element.js"
}
},
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "MyElement",
"members": [
{
"kind": "field",
"name": "foo",
"type": "string",
"default": "\"bar\""
}
],
"tagName": "my-element"
}
]
},
{
"path": "./src/another-component.js",
"exports": [
{
"kind": "definition",
"name": "another-component",
"declaration": {
"name": "AnotherComponent",
"module": "./src/another-component.js"
}
},
{
"kind": "class",
"superclass": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
},
"name": "AnotherComponent",
"members": [
{
"kind": "field",
"name": "baz",
"type": "string",
"default": "\"bar\""
},
{
"kind": "field",
"name": "label",
"type": "string",
"default": "\"d\"",
"inheritedFrom": {
"name": "AnotherSuperClass",
"module": "./src/AnotherSuperClass.js"
}
},
{
"kind": "field",
"name": "text",
"type": "string",
"default": "\"b\"",
"inheritedFrom": {
"name": "MySuperClass",
"module": "./src/MySuperClass.js"
}
}
],
"tagName": "another-component"
}
]
}
]
}
Result
[
{
kind: 'definition',
name: 'my-element',
declaration: { name: 'MyElement', module: './src/my-element.js' }
},
{
kind: 'definition',
name: 'another-component',
declaration: { name: 'AnotherComponent', module: './src/another-component.js' }
}
]
Returns inheritance for class MyComponent
.
customElementsJson.getInheritanceTree('MyComponent');
custom-elements.json
{
"version": "experimental",
"modules": [
{
"path": "./dev/src/custom-element/LitElement.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "UpdatingElement",
"module": "./dev/src/custom-element/UpdatingElement.js"
},
"name": "LitElement"
}
]
},
{
"path": "./dev/src/custom-element/MyComponent.js",
"exports": [
{
"kind": "definition",
"name": "my-component",
"declaration": {
"name": "LitElement",
"module": "./dev/src/custom-element/LitElement.js"
}
},
{
"kind": "class",
"superclass": {
"name": "LitElement",
"module": "./dev/src/custom-element/LitElement.js"
},
"mixins": [
{
"name": "TabindexMixin",
"module": "./dev/src/custom-element/MyComponent.js"
},
{
"name": "LocalizeMixin",
"module": "./dev/src/custom-element/MyComponent.js"
}
],
"name": "MyComponent"
},
{
"kind": "class",
"name": "TabindexMixin"
},
{
"kind": "class",
"name": "LocalizeMixin"
},
{
"kind": "variable",
"name": "LocalizeMixin",
"type": "(klass: any) => typeof LocalizeMixin"
},
{
"kind": "variable",
"name": "TabindexMixin",
"type": "(klass: any) => typeof TabindexMixin"
}
]
},
{
"path": "./dev/src/custom-element/UpdatingElement.js",
"exports": [
{
"kind": "class",
"superclass": {
"name": "HTMLElement"
},
"name": "UpdatingElement"
}
]
}
]
}
Result
[
{
kind: 'class',
superclass: {
name: 'LitElement',
module: './dev/src/custom-element/LitElement.js'
},
mixins: [ [Object], [Object] ],
name: 'MyComponent'
},
{
name: 'TabindexMixin',
module: './dev/src/custom-element/MyComponent.js',
kind: 'variable',
type: '(klass: any) => typeof TabindexMixin'
},
{
name: 'LocalizeMixin',
module: './dev/src/custom-element/MyComponent.js',
kind: 'variable',
type: '(klass: any) => typeof LocalizeMixin'
},
{
kind: 'class',
superclass: {
name: 'UpdatingElement',
module: './dev/src/custom-element/UpdatingElement.js'
},
name: 'LitElement'
},
{
kind: 'class',
superclass: { name: 'HTMLElement' },
name: 'UpdatingElement'
}
]
Additionally the following helper functions are available. These functions can help you when developing custom tooling for custom-elements.json
, and make your code more declarative.
Demo:
import * as h from '@custom-elements-json/helpers';
const json = require('./custom-elements.json');
if (h.hasModules(json)) {
json.modules.forEach(_module => {
if (h.hasExports(_module)) {
_module.exports.forEach(_export => {
if (h.isClass(_export) && h.hasAttributes(_export)) {
const attrs = _export.attributes;
// do something with attributes
}
});
}
});
});
hasModules(package: PackageDoc) => boolean
hasExports(module: ModuleDoc) => boolean
isClass(export: ExportDoc) => boolean
isFunction(export: ExportDoc) => boolean
isVariable(export: ExportDoc) => boolean
isDefinition(export: ExportDoc) => boolean
hasAttributes(customElement: CustomElementDoc) => boolean
hasEvents(customElement: CustomElementDoc) => boolean
hasSlots(customElement: CustomElementDoc) => boolean
hasMethods(customElement: CustomElementDoc) => boolean
hasFields(customElement: CustomElementDoc) => boolean
hasMixins(customElement: CustomElementDoc) => boolean
isField(member: ClassMember) => boolean
isMethod(member: ClassMember) => boolean
Developing:
npm run tsc:watch
# in a separate terminal
npm run start
Testing:
npm test
- Get all information for a given class (this should include the information of any superclasses or mixins)
- Get all information for a given tagName (this should include the information of any superclasses or mixins)
- Get all mixins
- Get all classes
- Get all definitions
- Get attributes for a given class or tagName
- Get properties for a given class or tagName
- Get cssProperties for a given class or tagName
- Get cssParts for a given class or tagName
- Get events for a given class or tagName
- Get slots for a given class or tagName
- more? What sort of things would be helpful? Create an issue if you have any ideas
- It'd be nice to have this library be fully isomorphic (runs in node and the browser)