Skip to content

open-wc/custom-elements-json-helpers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@custom-elements-json/helpers

⚠️ 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.

Usage

// 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);

Methods


getByTagName

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'
}

getByClassName

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'
}

getClasses

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'
  }
]

getMixins

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'
  }
]

getDefinitions

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' }
  }
]

getInheritanceTree

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'
  }
]

Helper functions

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
        }
      });
    }
  });
});

Package

  • hasModules(package: PackageDoc) => boolean

Module

  • hasExports(module: ModuleDoc) => boolean

Export

  • isClass(export: ExportDoc) => boolean
  • isFunction(export: ExportDoc) => boolean
  • isVariable(export: ExportDoc) => boolean
  • isDefinition(export: ExportDoc) => boolean

CustomElement

  • hasAttributes(customElement: CustomElementDoc) => boolean
  • hasEvents(customElement: CustomElementDoc) => boolean
  • hasSlots(customElement: CustomElementDoc) => boolean
  • hasMethods(customElement: CustomElementDoc) => boolean
  • hasFields(customElement: CustomElementDoc) => boolean
  • hasMixins(customElement: CustomElementDoc) => boolean

ClassMember

  • isField(member: ClassMember) => boolean
  • isMethod(member: ClassMember) => boolean

Contributing

Developing:

npm run tsc:watch
# in a separate terminal
npm run start

Testing:

npm test

Usecases

  • 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

Goals

  • It'd be nice to have this library be fully isomorphic (runs in node and the browser)

About

Library of helpers for working with custom-elements.json

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published