Type Parser
Using type aliases to define the types for your component’s APIs, can be helpful for keeping your code clean and organized as well as making your types reusable.
The down-side is that it can be difficult to integrate with other tooling or communicate in documentation what the available options are. This plugin parses the types so they available in a more usable format.
Installation
npm i -D @wc-toolkit/type-parserUsage
Using type aliases to define the types for your component’s APIs, can be helpful for keeping your code clean and organized as well as making your types reusable.
type Target = '_blank' | '_self' | '_parent' | '_top';
class MyLink extends HTMLElement { target?: Target;}This plugin parses the types for your component APIs in Custom Elements Manifest using the Custom Element Manifest Analyzer.
import { getTsProgram, typeParserPlugin } from "@wc-toolkit/type-parser";
export default { ... // Give the plugin access to the TypeScript type checker overrideModuleCreation({ts, globs}) { const program = getTsProgram(ts, globs, "tsconfig.json"); return program .getSourceFiles() .filter((sf) => globs.find((glob) => sf.fileName.includes(glob))); },
// Add the plugin to the config plugins: [typeParserPlugin()],};Result
It doesn’t overwrite the existing property, but will create a new property with the parsed type value.
{ "kind": "field", "name": "target", "description": "A lookup type for example", "attribute": "target", "type": { "text": "Target | undefined" }, "parsedType": { "text": "'_blank' | '_self' | '_parent' | '_top' | undefined" }}Complex types
The plugin parses complex types, such as union, intersection, and generic types. It also supports Enums and TypeScript’s utility types.
type Test1 = "value1" | "value2" | "value3";type Test2 = "value4" | "value5" | "value6";
type UnionType = Test1 | Test2; // "value1" | "value2" | "value3" | "value4" | "value5" | "value6"type ExcludeUnionType = Exclude<Test1 | Test2, "value1">; // "value2" | "value3" | "value4" | "value5" | "value6"type GenericType<T> = T | Test1; // T | "value1" | "value2" | "value3"type MyGeneric = GenericType<Test2>; // "value4" | "value5" | "value6" | "value1" | "value2" | "value3"enum DirectionEnum { Up, Down, Left, Right,}; // 0 | 1 | 2 | 3type DirectionOptions = keyof typeof DirectionEnum; // "Up" | "Down" | "Left" | "Right"Limitations
If a type cannot be safely expanded, such as a recursive or overly complex external type, the plugin keeps the original type text and logs a warning with the type name, declaration location, and reason it was skipped.
Configuration
There are a few ways you can configure the plugin to meet your environment.
type Options = { /** Controls whether object types are parsed, and if so, whether fully or partially ('none', 'partial', 'full') */ parseObjectTypes?: 'none' | 'partial' | 'full'; /** Controls whether method parameters are parsed */ parseParameters?: boolean; /** Determines the name of the property used in the manifest to store the parsed type */ propertyName?: string; /** Maximum depth to which nested types are expanded before bailing (default: 8) */ maxParseDepth?: number; /** Maximum number of properties a type can have before bailing (default: 50) */ maxParseProperties?: number; /** Shows process logs */ debug?: boolean; /** Prevents plugin from executing when true */ skip?: boolean;}Object Types
By default the plugin does not expand object types. Set parseObjectTypes to 'partial' to expand the first level of properties, or 'full' to expand nested objects as well.
export default { ... plugins: [typeParserPlugin({ parseObjectTypes: "full" })],};Parameters
Set parseParameters to true to also parse the types of method parameters.
Parse Limits
If a type is overly complex, the plugin bails out and keeps the original type text. You can raise the defaults with maxParseDepth (how deeply nested types are expanded) and maxParseProperties (how many properties a type can have).
export default { ... plugins: [ typeParserPlugin({ parseObjectTypes: "full", maxParseDepth: 12, maxParseProperties: 100, }), ],};Property Name
The default property name that the values are assigned to is parsedType.
If you want to change that, you can do so by passing the propertyName option.
export default { ...
/** Provide custom plugins */ plugins: [typeParserPlugin({ propertyName: "expandedType" })],};Once that has been updated, the parsed type will appear under the new property name.
{ "kind": "field", "name": "target", "description": "A lookup type for example", "attribute": "target", "type": { "text": "Target | undefined" }, "expandedType": { "text": "'_blank' | '_self' | '_parent' | '_top' | undefined" }}NOTE: As you can see in the example above, the structure will follow the same pattern as the
typeobject in that your custom name will have a property calledtext.