@wc-toolkit/cem-inheritance
Version:
A tool for mapping inherited content (including class members, attributes, CSS parts, CSS variables, slots, and events) from parent web component classes in the Custom Elements Manifest
350 lines (311 loc) • 9.55 kB
TypeScript
import { AnalyzePhaseParams, PackageLinkPhaseParams } from '@custom-elements-manifest/analyzer';
/**
* 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:"`.
*/
interface Reference {
name: string;
package?: string;
module?: string;
}
/**
* A reference to the source of a declaration or member.
*/
interface SourceReference {
/**
* An absolute URL to the source (ie. a GitHub URL).
*/
href: string;
}
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.
*/
interface TypeReference extends Reference {
start?: number;
end?: number;
}
/**
* The common interface of classes and mixins.
*/
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;
}
type ClassMember = ClassField | ClassMethod;
/**
* The common interface of variables, class fields, and function
* parameters.
*/
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;
}
interface ClassField extends PropertyLike {
kind: 'field';
static?: boolean;
privacy?: Privacy;
inheritedFrom?: Reference;
source?: SourceReference;
}
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",
* }
* ]
* }
* ```
*/
interface MixinDeclaration extends ClassLike, FunctionLike {
kind: 'mixin';
}
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;
}
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;
};
}
type Privacy = 'public' | 'private' | 'protected';
type CemInheritanceOptions = {
/** Name of the updated CEM file - default is "custom-elements.json" */
fileName?: string;
/** Path to output directory */
outdir?: string;
/** Class names of any components you would like to exclude from inheritance */
exclude?: string[];
/** Omit items from inheritance based on a custom CEM property */
omitByProperty?: OmittedProperties;
/** Omit items from inheritance based on CEM Analyzer plugin config */
omitByConfig?: ConfigOmit;
/** Skip inheritance for an aspect of your components */
ignore?: string[];
/** External CEMs that your components extend */
externalManifests?: unknown[];
/** Include external manifest declarations in your manifest */
includeExternalManifests?: boolean;
/** Shows process logs */
debug?: boolean;
/** Prevents plugin from executing */
skip?: boolean;
/** @internal Used to indicate if this is used as a CEM a plugin */
usedByPlugin?: boolean;
};
/** @deprecated This has been replaced with `CemInheritanceOptions` */
type Options = CemInheritanceOptions;
type ConfigOmit = {
[key: string]: OmittedApis;
};
type OmittedProperties = {
attributes?: string;
cssParts?: string;
cssProperties?: string;
cssStates?: string;
events?: string;
methods?: string;
properties?: string;
slots?: string;
};
type OmittedApis = Record<keyof OmittedProperties, string[]>;
/** A generic extension of the CEM `MixinDeclaration` type to allow for strongly typing your custom data */
type Mixin<T = Record<string, unknown>> = MixinDeclaration & T;
declare function cemInheritancePlugin(options?: CemInheritanceOptions): {
name: string;
analyzePhase(params: AnalyzePhaseParams): void;
packageLinkPhase({ customElementsManifest }: PackageLinkPhaseParams): void;
};
declare function updateCemInheritance(cem: unknown, options?: CemInheritanceOptions): void;
declare function generateUpdatedCem(cem: unknown, options?: CemInheritanceOptions): unknown;
export { type CemInheritanceOptions, type ConfigOmit, type Mixin, type OmittedApis, type OmittedProperties, type Options, cemInheritancePlugin, generateUpdatedCem, updateCemInheritance };