custom-elements-manifest
Version:
A file format for describing custom elements
767 lines (659 loc) • 19.1 kB
TypeScript
/**
* @license
* Copyright (c) 2019 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
/**
* The top-level interface of a custom elements manifest file.
*
* Because custom elements are JavaScript classes, describing a custom element
* may require describing arbitrary JavaScript concepts like modules, classes,
* functions, etc. So custom elements manifests are capable of documenting
* the elements in a package, as well as those JavaScript concepts.
*
* The modules described in a package should be the public entrypoints that
* other packages may import from. Multiple modules may export the same object
* via re-exports, but in most cases a package should document the single
* canonical export that should be used.
*/
export interface Package {
/**
* The version of the schema used in this file.
*/
schemaVersion: string;
/**
* The Markdown to use for the main readme of this package.
*
* This can be used to override the readme used by Github or npm if that
* file contains information irrelevant to custom element catalogs and
* documentation viewers.
*/
readme?: string;
/**
* An array of the modules this package contains.
*/
modules: Array<Module>;
/**
* Whether the package is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
// This type may expand in the future to include JSON, CSS, or HTML
// modules.
export type Module = JavaScriptModule;
export interface JavaScriptModule {
kind: 'javascript-module';
/**
* Path to the javascript file needed to be imported.
* (not the path for example to a typescript file.)
*/
path: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description of the module.
*/
description?: string;
/**
* The declarations of a module.
*
* For documentation purposes, all declarations that are reachable from
* exports should be described here. Ie, functions and objects that may be
* properties of exported objects, or passed as arguments to functions.
*/
declarations?: Array<Declaration>;
/**
* The exports of a module. This includes JavaScript exports and
* custom element definitions.
*/
exports?: Array<Export>;
/**
* Whether the module is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export type Export = JavaScriptExport | CustomElementExport;
export interface JavaScriptExport {
kind: 'js';
/**
* The name of the exported symbol.
*
* JavaScript has a number of ways to export objects which determine the
* correct name to use.
*
* - Default exports must use the name "default".
* - Named exports use the name that is exported. If the export is renamed
* with the "as" clause, use the exported name.
* - Aggregating exports (`* from`) should use the name `*`
*/
name: string;
/**
* A reference to the exported declaration.
*
* In the case of aggregating exports, the reference's `module` field must be
* defined and the `name` field must be `"*"`.
*/
declaration: Reference;
/**
* Whether the export is deprecated. For example, the name of the export was changed.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
/**
* A global custom element defintion, ie the result of a
* `customElements.define()` call.
*
* This is represented as an export because a definition makes the element
* available outside of the module it's defined it.
*/
export interface CustomElementExport {
kind: 'custom-element-definition';
/**
* The tag name of the custom element.
*/
name: string;
/**
* A reference to the class or other declaration that implements the
* custom element.
*/
declaration: Reference;
/**
* Whether the custom-element export is deprecated.
* For example, a future version will not register the custom element in this file.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export type Declaration =
| ClassDeclaration
| FunctionDeclaration
| MixinDeclaration
| VariableDeclaration
| CustomElementDeclaration
| CustomElementMixinDeclaration;
/**
* A reference to an export of a module.
*
* All references are required to be publically accessible, so the canonical
* representation of a reference is the export it's available from.
*
* `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.
*
* References to global symbols like `Array`, `HTMLElement`, or `Event` should
* use a `package` name of `"global:"`.
*/
export interface Reference {
name: string;
package?: string;
module?: string;
}
/**
* A reference to the source of a declaration or member.
*/
export interface SourceReference {
/**
* An absolute URL to the source (ie. a GitHub URL).
*/
href: string;
}
/**
* A description of a custom element class.
*
* Custom elements are JavaScript classes, so this extends from
* `ClassDeclaration` and adds custom-element-specific features like
* attributes, events, and slots.
*
* Note that `tagName` in this interface is optional. Tag names are not
* neccessarily part of a custom element class, but belong to the definition
* (often called the "registration") or the `customElements.define()` call.
*
* Because classes and tag names can only be registered once, there's a
* one-to-one relationship between classes and tag names. For ease of use,
* we allow the tag name here.
*
* Some packages define and register custom elements in separate modules. In
* these cases one `Module` should contain the `CustomElement` without a
* tagName, and another `Module` should contain the
* `CustomElementExport`.
*/
// Note: this needs to be an interface to be included in the generated JSON
// Schema output.
export interface CustomElementDeclaration
extends ClassDeclaration,
CustomElement {}
/**
* The additional fields that a custom element adds to classes and mixins.
*/
export interface CustomElement extends ClassLike {
/**
* An optional tag name that should be specified if this is a
* self-registering element.
*
* Self-registering elements must also include a CustomElementExport
* in the module's exports.
*/
tagName?: string;
/**
* The attributes that this element is known to understand.
*/
attributes?: Attribute[];
/**
* The events that this element fires.
*/
events?: Event[];
/**
* The shadow dom content slots that this element accepts.
*/
slots?: Slot[];
cssParts?: CssPart[];
cssProperties?: CssCustomProperty[];
cssStates?: CssCustomState[];
demos?: Demo[];
/**
* Distinguishes a regular JavaScript class from a
* custom element class
*/
customElement: true;
}
export interface Attribute {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
inheritedFrom?: Reference;
/**
* The type that the attribute will be serialized/deserialized as.
*/
type?: Type;
/**
* The default value of the attribute, if any.
*
* As attributes are always strings, this is the actual value, not a human
* readable description.
*/
default?: string;
/**
* The name of the field this attribute is associated with, if any.
*/
fieldName?: string;
/**
* Whether the attribute is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export interface Event {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
/**
* The type of the event object that's fired.
*/
type: Type;
inheritedFrom?: Reference;
/**
* Whether the event is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export interface Slot {
/**
* The slot name, or the empty string for an unnamed slot.
*/
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
/**
* Whether the slot is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
/**
* The description of a CSS Part
*/
export interface CssPart {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
/**
* Whether the CSS shadow part is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
/**
* The description of a CSS Custom State
* https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet
*/
export interface CssCustomState {
/**
* The name of the state. Note: Unlike CSS custom properties, custom states
* do not have a leading `--`.
*/
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
/**
* Whether the CSS custom state is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export interface CssCustomProperty {
/**
* The name of the property, including leading `--`.
*/
name: string;
/**
* The expected syntax of the defined property. Defaults to "*".
*
* The syntax must be a valid CSS [syntax string](https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax)
* as defined in the CSS Properties and Values API.
*
* Examples:
*
* "<color>": accepts a color
* "<length> | <percentage>": accepts lengths or percentages but not calc expressions with a combination of the two
* "small | medium | large": accepts one of these values set as custom idents.
* "*": any valid token
*/
syntax?: string;
default?: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
/**
* Whether the CSS custom property is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export interface Type {
/**
* The full string representation of the type, in whatever type syntax is
* used, such as JSDoc, Closure, or TypeScript.
*/
text: string;
/**
* An array of references to the types in the type string.
*
* These references have optional indices into the type string so that tools
* can understand the references in the type string independently of the type
* system and syntax. For example, a documentation viewer could display the
* type `Array<FooElement | BarElement>` with cross-references to `FooElement`
* and `BarElement` without understanding arrays, generics, or union types.
*/
references?: TypeReference[];
source?: SourceReference;
}
/**
* A reference that is associated with a type string and optionally a range
* within the string.
*
* Start and end must both be present or not present. If they're present, they
* are indices into the associated type string. If they are missing, the entire
* type string is the symbol referenced and the name should match the type
* string.
*/
export interface TypeReference extends Reference {
start?: number;
end?: number;
}
/**
* The common interface of classes and mixins.
*/
export interface ClassLike {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description of the class.
*/
description?: string;
/**
* The superclass of this class.
*
* If this class is defined with mixin applications, the prototype chain
* includes the mixin applications and the true superclass is computed
* from them.
*/
superclass?: Reference;
/**
* Any class mixins applied in the extends clause of this class.
*
* If mixins are applied in the class definition, then the true superclass
* of this class is the result of applying mixins in order to the superclass.
*
* Mixins must be listed in order of their application to the superclass or
* previous mixin application. This means that the innermost mixin is listed
* first. This may read backwards from the common order in JavaScript, but
* matches the order of language used to describe mixin application, like
* "S with A, B".
*
* @example
*
* ```javascript
* class T extends B(A(S)) {}
* ```
*
* is described by:
* ```json
* {
* "kind": "class",
* "superclass": {
* "name": "S"
* },
* "mixins": [
* {
* "name": "A"
* },
* {
* "name": "B"
* },
* ]
* }
* ```
*/
mixins?: Array<Reference>;
members?: Array<ClassMember>;
source?: SourceReference;
/**
* Whether the class or mixin is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
}
export interface ClassDeclaration extends ClassLike {
kind: 'class';
}
export type ClassMember = ClassField | ClassMethod;
/**
* The common interface of variables, class fields, and function
* parameters.
*/
export interface PropertyLike {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description of the field.
*/
description?: string;
type?: Type;
default?: string;
/**
* Whether the property is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
/**
* Whether the property is read-only.
*/
readonly?: boolean;
}
export interface ClassField extends PropertyLike {
kind: 'field';
static?: boolean;
privacy?: Privacy;
inheritedFrom?: Reference;
source?: SourceReference;
}
/**
* Additional metadata for fields on custom elements.
*/
export interface CustomElementField extends ClassField {
/**
* The corresponding attribute name if there is one.
*
* If this property is defined, the attribute must be listed in the classes'
* `attributes` array.
*/
attribute?: string;
/**
* If the property reflects to an attribute.
*
* If this is true, the `attribute` property must be defined.
*/
reflects?: boolean;
}
export interface ClassMethod extends FunctionLike {
kind: 'method';
static?: boolean;
privacy?: Privacy;
inheritedFrom?: Reference;
source?: SourceReference;
}
/**
* A description of a class mixin.
*
* Mixins are functions which generate a new subclass of a given superclass.
* This interfaces describes the class and custom element features that
* are added by the mixin. As such, it extends the CustomElement interface and
* ClassLike interface.
*
* Since mixins are functions, it also extends the FunctionLike interface. This
* means a mixin is callable, and has parameters and a return type.
*
* The return type is often hard or impossible to accurately describe in type
* systems like TypeScript. It requires generics and an `extends` operator
* that TypeScript lacks. Therefore it's recommended that the return type is
* left empty. The most common form of a mixin function takes a single
* argument, so consumers of this interface should assume that the return type
* is the single argument subclassed by this declaration.
*
* A mixin should not have a superclass. If a mixins composes other mixins,
* they should be listed in the `mixins` field.
*
* See [this article]{@link https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/}
* for more information on the classmixin pattern in JavaScript.
*
* @example
*
* This JavaScript mixin declaration:
* ```javascript
* const MyMixin = (base) => class extends base {
* foo() { ... }
* }
* ```
*
* Is described by this JSON:
* ```json
* {
* "kind": "mixin",
* "name": "MyMixin",
* "parameters": [
* {
* "name": "base",
* }
* ],
* "members": [
* {
* "kind": "method",
* "name": "foo",
* }
* ]
* }
* ```
*/
export interface MixinDeclaration extends ClassLike, FunctionLike {
kind: 'mixin';
}
/**
* A class mixin that also adds custom element related properties.
*/
// Note: this needs to be an interface to be included in the generated JSON
// Schema output.
export interface CustomElementMixinDeclaration
extends MixinDeclaration,
CustomElement {}
export interface VariableDeclaration extends PropertyLike {
kind: 'variable';
source?: SourceReference;
}
export interface FunctionDeclaration extends FunctionLike {
kind: 'function';
source?: SourceReference;
}
export interface Parameter extends PropertyLike {
/**
* Whether the parameter is optional. Undefined implies non-optional.
*/
optional?: boolean;
/**
* Whether the parameter is a rest parameter. Only the last parameter may be a rest parameter.
* Undefined implies single parameter.
*/
rest?: boolean;
}
export interface FunctionLike {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
/**
* Whether the function is deprecated.
* If the value is a string, it's the reason for the deprecation.
*/
deprecated?: boolean | string;
parameters?: Parameter[];
return?: {
type?: Type;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description.
*/
description?: string;
};
}
export type Privacy = 'public' | 'private' | 'protected';
export interface Demo {
/**
* A markdown description of the demo.
*/
description?: string;
/**
* Relative URL of the demo if it's published with the package. Absolute URL
* if it's hosted.
*/
url: string;
source?: SourceReference;
}