From 0a017d24a573d5a346cb562ab9a31a262822aa38 Mon Sep 17 00:00:00 2001 From: Andreas Moldskred Date: Sun, 4 Oct 2020 15:10:50 +0200 Subject: [PATCH 1/2] Remove any types and implement proper type assertions --- .../custom-elements-json-core/src/create.ts | 307 ++++++++++-------- .../src/customElementsJson.ts | 26 +- .../src/utils/index.ts | 99 +++--- .../src/helpers.ts | 47 ++- packages/custom-elements-json/schema.ts | 1 + 5 files changed, 274 insertions(+), 206 deletions(-) diff --git a/packages/custom-elements-json-core/src/create.ts b/packages/custom-elements-json-core/src/create.ts index d839290..d872ec8 100644 --- a/packages/custom-elements-json-core/src/create.ts +++ b/packages/custom-elements-json-core/src/create.ts @@ -2,8 +2,18 @@ import path from 'path'; import fs from 'fs'; import globby from 'globby'; import ts from 'typescript'; -import { Package, Declaration, JavaScriptModule, CustomElement, Export, Attribute, ClassMember, Event } from 'custom-elements-json/schema'; -import { ExportType } from './utils'; +import { + Package, + Declaration, + ClassDeclaration, + JavaScriptModule, + CustomElement, + Export, + Attribute, + ClassMember, + Event, +} from 'custom-elements-json/schema'; +import { ExportType, isImport } from './utils'; import { Import, isBareModuleSpecifier } from './utils'; import { customElementsJson } from './customElementsJson'; @@ -24,14 +34,14 @@ export async function create(packagePath: string): Promise { kind: 'javascript-module', path: relativeModulePath, declarations: [], - exports: [] + exports: [], }); const sourceFile = ts.createSourceFile( modulePath, fs.readFileSync(modulePath).toString(), ts.ScriptTarget.ES2015, - true + true, ); customElementsJson.setCurrentModule(sourceFile); @@ -42,7 +52,9 @@ export async function create(packagePath: string): Promise { * This includes a modules imports, which are not specified in custom-elements.json, but are * required for the LINK PHASE, and deleted when processed */ - const currModule = (customElementsJson.modules.find(_module => _module.path === relativeModulePath) as JavaScriptModule); + const currModule = customElementsJson.modules.find( + _module => _module.path === relativeModulePath, + ) as JavaScriptModule; visit(sourceFile, currModule); /** @@ -54,93 +66,101 @@ export async function create(packagePath: string): Promise { */ // Match mixins with their imports - const classes = currModule.declarations.filter(declaration => declaration.kind === 'class'); + const classes = currModule.declarations.filter( + (declaration): declaration is ClassDeclaration => declaration.kind === 'class', + ); - classes.forEach((customElement: any) => { - if(customElement.superclass && customElement.superclass.name !== 'HTMLElement') { - const foundSuperclass = [...(classes || []), ...(customElementsJson.imports || [])].find((_import: Import) => { - return _import.name === customElement.superclass.name; + classes.forEach(customElement => { + if (customElement.superclass && customElement.superclass.name !== 'HTMLElement') { + const classesAndImports = [...(classes || []), ...(customElementsJson.imports || [])]; + const foundSuperclass = classesAndImports.find(_import => { + const superclassName = customElement?.superclass?.name; + return superclassName && _import.name === superclassName; }); - if(foundSuperclass) { - // Superclass is imported, but from a bare module specifier - if(foundSuperclass.kind && foundSuperclass.isBareModuleSpecifier) { - customElement.superclass.package = foundSuperclass.importPath; - } - - // Superclass is imported, but from a different local module - if(foundSuperclass.kind && !foundSuperclass.isBareModuleSpecifier) { - customElement.superclass.module = foundSuperclass.importPath; - } - - // Superclass declared in local module - if(foundSuperclass.isBareModuleSpecifier === undefined) { + if (foundSuperclass) { + if (isImport(foundSuperclass)) { + if (foundSuperclass.isBareModuleSpecifier) { + // Superclass is imported, but from a bare module specifier + customElement.superclass.package = foundSuperclass.importPath; + } else { + // Superclass is imported, but from a different local module + customElement.superclass.module = foundSuperclass.importPath; + } + } else { + // Superclass declared in local module customElement.superclass.module = currModule.path; } } } + customElement.mixins?.forEach(mixin => { + const foundMixin = [ + ...(currModule.declarations || []), + ...(customElementsJson.imports || []), + ].find(_import => _import.name === mixin.name); - - customElement.mixins && customElement.mixins.forEach((mixin: any) => { - const foundMixin = [...(currModule.declarations || []), ...(customElementsJson.imports || [])].find((_import: Import) => _import.name === mixin.name); - - if(foundMixin) { - + if (foundMixin) { /** * Find a mixin's nested/inner mixins and add them to the class's list of mixins * @example const MyMixin1 = klass => class MyMixin1 extends MyMixin2(klass) {} */ - if(Array.isArray(foundMixin.mixins) && foundMixin.mixins.length > 0) { - foundMixin.mixins.forEach((mixin: any) => { - const nestedFoundMixin = [...(currModule.declarations || []), ...(customElementsJson.imports || [])].find((_import: Import) => _import.name === mixin.name); - - // Mixin is imported from a third party module (bare module specifier) - if(nestedFoundMixin.importPath && nestedFoundMixin.isBareModuleSpecifier) { - mixin.package = nestedFoundMixin.importPath; - } - - // Mixin is imported from a different local module - if(nestedFoundMixin.importPath && !nestedFoundMixin.isBareModuleSpecifier) { - mixin.module = nestedFoundMixin.importPath; - } - - // Mixin was found in the current modules declarations, so defined locally - if(!nestedFoundMixin.importPath) { - mixin.module = currModule.path; + if ('mixins' in foundMixin) { + foundMixin.mixins?.forEach((mixin: any) => { + const nestedFoundMixin = [ + ...(currModule.declarations || []), + ...(customElementsJson.imports || []), + ].find(_import => _import.name === mixin.name); + + if (isImport(nestedFoundMixin)) { + if (nestedFoundMixin.importPath) { + if (nestedFoundMixin.isBareModuleSpecifier) { + // Mixin is imported from a third party module (bare module specifier) + mixin.package = nestedFoundMixin.importPath; + } else { + // Mixin is imported from a different local module + mixin.module = nestedFoundMixin.importPath; + } + } else { + // Mixin was found in the current modules declarations, so defined locally + mixin.module = currModule.path; + } } - - customElement.mixins.push(mixin); + customElement.mixins = [...(customElement.mixins || []), mixin]; }); } - // Mixin is imported from bare module specifier - if(foundMixin.importPath && foundMixin.isBareModuleSpecifier) { - mixin.package = foundMixin.importPath; - } - - // Mixin is imported from a different local module - if(foundMixin.importPath && !foundMixin.isBareModuleSpecifier) { - mixin.module = foundMixin.importPath; + if (isImport(foundMixin)) { + // Mixin is imported from bare module specifier + if (foundMixin.isBareModuleSpecifier) { + mixin.package = foundMixin.importPath; + } else { + // Mixin is imported from a different local module + mixin.module = foundMixin.importPath; + } } - + } else { // Mixin was found in the current modules declarations, so defined locally - if(!foundMixin.importPath) { - mixin.module = currModule.path; - } + mixin.module = currModule.path; } }); }); // Find any mixins that were used in a class, so we can add them to a modules declarations - const usedMixins: any = []; - currModule.declarations.forEach((declaration: any) => { - if(declaration.kind === 'mixin') { + const usedMixins: Declaration[] = []; + currModule.declarations.forEach(declaration => { + if (declaration.kind === 'mixin') { // if its a mixin, find out if a class is making use of it const isUsed = currModule.declarations.find(nestedDeclaration => { - if(nestedDeclaration.kind === 'class' && Array.isArray(nestedDeclaration.mixins) && nestedDeclaration.mixins.length > 0) { - return nestedDeclaration.mixins.find(mixin => mixin.name === declaration.name) !== undefined; + if ( + nestedDeclaration.kind === 'class' && + Array.isArray(nestedDeclaration.mixins) && + nestedDeclaration.mixins.length > 0 + ) { + return ( + nestedDeclaration.mixins.find(mixin => mixin.name === declaration.name) !== undefined + ); } - }) - if(isUsed) { + }); + if (isUsed) { usedMixins.push(declaration); } } @@ -148,9 +168,12 @@ export async function create(packagePath: string): Promise { // remove any declarations that are not exported currModule.declarations = currModule.declarations.filter(declaration => { - return currModule.exports && currModule.exports.some(_export => { - return declaration.name === _export.name || declaration.name === _export.declaration.name - }); + return ( + currModule.exports && + currModule.exports.some(_export => { + return declaration.name === _export.name || declaration.name === _export.declaration.name; + }) + ); }); currModule.declarations = [...(currModule.declarations || []), ...(usedMixins || [])]; @@ -162,16 +185,17 @@ export async function create(packagePath: string): Promise { const definitions = customElementsJson.getDefinitions(); // CustomElementExports // Match modulePath for definition declarations - for(const definition of definitions) { - for(const _module of customElementsJson.modules) { + for (const definition of definitions) { + for (const _module of customElementsJson.modules) { const modulePath = _module.path; // @TODO: I dont think you need to go through the exports here - const match = [..._module.declarations, ..._module.exports] - .some(classDoc => { - return classDoc.name === definition.declaration.name - }); + const match = [...(_module.declarations), ...(_module.exports)].some( + classDoc => { + return classDoc.name === definition.declaration.name; + }, + ); - if(match) { + if (match) { definition.declaration.module = modulePath; break; } @@ -180,8 +204,10 @@ export async function create(packagePath: string): Promise { // Match tagNames for classDocs, and inheritance chain classes.forEach((customElement: CustomElement) => { - const tagName = definitions.find(def => def && def.declaration && def.declaration.name === customElement.name)?.name; - if(tagName) { + const tagName = definitions.find( + def => def && def.declaration && def.declaration.name === customElement.name, + )?.name; + if (tagName) { customElement.tagName = tagName; } @@ -189,78 +215,79 @@ export async function create(packagePath: string): Promise { const inheritanceChain = customElementsJson.getInheritanceTree(customElement.name); inheritanceChain.forEach((klass: any) => { - // Handle mixins - if(klass.kind !== 'class') { - if(klass.package) { + if (klass.kind !== 'class') { + if (klass.package) { // the mixin comes from a bare module specifier, skip it return; } - if(klass.module) { + if (klass.module) { // @TODO add attrs/members/events - const klassModule = customElementsJson.modules.find((_module: any) => _module.path === klass.module); - if(klassModule) { - const foundMixin: any = klassModule.declarations.find((declaration: any) => declaration.kind === 'mixin' && declaration.name === klass.name); - foundMixin.members && foundMixin.members.forEach((member: any) => { - const newMember = { - ...member, - inheritedFrom: { - name: klass.name, - module: klass.module + const klassModule = customElementsJson.modules.find( + (_module: any) => _module.path === klass.module, + ); + if (klassModule) { + const foundMixin: any = klassModule.declarations.find( + (declaration: any) => declaration.kind === 'mixin' && declaration.name === klass.name, + ); + foundMixin.members && + foundMixin.members.forEach((member: any) => { + const newMember = { + ...member, + inheritedFrom: { + name: klass.name, + module: klass.module, + }, + }; + + if (Array.isArray(customElement.members) && customElement.members.length > 0) { + customElement.members.push(newMember); + } else { + customElement.members = [newMember]; } - } - - if(Array.isArray(customElement.members) && customElement.members.length > 0) { - customElement.members.push(newMember); - } else { - customElement.members = [newMember]; - } - }); + }); } } } // ignore the current class itself - if(klass.name === customElement.name) { + if (klass.name === customElement.name) { return; } // loop through attrs, events, members, add inherited from field, push to og class - klass.attributes && klass.attributes.forEach((attr: Attribute) => { - - }); - klass.events && klass.events.forEach((event: Event) => { - - }); - - klass.members && klass.members.forEach((member: ClassMember) => { - const moduleForKlass = customElementsJson.getModuleForClass(klass.name); - let newMember; - - if(moduleForKlass && isBareModuleSpecifier(moduleForKlass)) { - newMember = { - ...member, - inheritedFrom: { - name: klass.name, - package: moduleForKlass - } - } - } else { - newMember = { - ...member, - inheritedFrom: { - name: klass.name, - module: moduleForKlass - } + klass.attributes && klass.attributes.forEach((attr: Attribute) => {}); + klass.events && klass.events.forEach((event: Event) => {}); + + klass.members && + klass.members.forEach((member: ClassMember) => { + const moduleForKlass = customElementsJson.getModuleForClass(klass.name); + let newMember; + + if (moduleForKlass && isBareModuleSpecifier(moduleForKlass)) { + newMember = { + ...member, + inheritedFrom: { + name: klass.name, + package: moduleForKlass, + }, + }; + } else { + newMember = { + ...member, + inheritedFrom: { + name: klass.name, + module: moduleForKlass, + }, + }; } - } - if(Array.isArray(customElement.members) && customElement.members.length > 0) { - customElement.members.push(newMember); - } else { - customElement.members = [newMember]; - } - }); + if (Array.isArray(customElement.members) && customElement.members.length > 0) { + customElement.members.push(newMember); + } else { + customElement.members = [newMember]; + } + }); }); }); @@ -275,13 +302,13 @@ function visit(source: ts.SourceFile, moduleDoc: JavaScriptModule) { visitNode(source); function visitNode(node: ts.Node) { - const mixin: any = getMixin((node as ts.VariableStatement | ts.FunctionDeclaration)); + const mixin: any = getMixin(node as ts.VariableStatement | ts.FunctionDeclaration); const isMixin = mixin !== false; switch (node.kind) { case ts.SyntaxKind.ClassDeclaration: handleClass(node, moduleDoc, 'class'); - handleExport((node as ExportType), moduleDoc); + handleExport(node as ExportType, moduleDoc); break; case ts.SyntaxKind.PropertyAccessExpression: handleCustomElementsDefine(node, moduleDoc); @@ -290,12 +317,12 @@ function visit(source: ts.SourceFile, moduleDoc: JavaScriptModule) { case ts.SyntaxKind.ExportDeclaration: case ts.SyntaxKind.FunctionDeclaration: case ts.SyntaxKind.ExportAssignment: - if(isMixin) { + if (isMixin) { handleClass(mixin, moduleDoc, 'mixin'); - handleExport((node as ExportType), moduleDoc, mixin.name.text); + handleExport(node as ExportType, moduleDoc, mixin.name.text); break; } - handleExport((node as ExportType), moduleDoc); + handleExport(node as ExportType, moduleDoc); break; case ts.SyntaxKind.ImportDeclaration: handleImport(node); @@ -304,4 +331,4 @@ function visit(source: ts.SourceFile, moduleDoc: JavaScriptModule) { ts.forEachChild(node, visitNode); } -} \ No newline at end of file +} diff --git a/packages/custom-elements-json-core/src/customElementsJson.ts b/packages/custom-elements-json-core/src/customElementsJson.ts index a7d58a4..fb1b907 100644 --- a/packages/custom-elements-json-core/src/customElementsJson.ts +++ b/packages/custom-elements-json-core/src/customElementsJson.ts @@ -1,29 +1,33 @@ import ts from 'typescript'; -import { CustomElementsJson } from '@custom-elements-json/helpers'; +import { CustomElementsJson } from 'custom-elements-json-helpers'; import { Import } from './utils'; +import { Package } from 'custom-elements-json/schema'; export class ExtendedCustomElementsJson extends CustomElementsJson { - currentModule: any; - imports: any; + currentModule: ts.Node | undefined; + imports: Import[]; + constructor(props: Package) { + super(props); + this.imports = []; + } - setCurrentModule(source: any) { + setCurrentModule(source: ts.Node) { this.currentModule = source; } setImportsForCurrentModule(imports: Import[]) { - this.imports = [...this.imports || [], ...imports]; + this.imports = [...(this.imports || []), ...imports]; } - visitCurrentModule(cb: (node: any) => void) { - visitNode(this.currentModule); - + visitCurrentModule(cb: (node: ts.Node) => void) { function visitNode(node: ts.Node) { - cb(node) + cb(node); ts.forEachChild(node, visitNode); } + if (this.currentModule) { + visitNode(this.currentModule); + } } } - - export const customElementsJson = new ExtendedCustomElementsJson(); diff --git a/packages/custom-elements-json-core/src/utils/index.ts b/packages/custom-elements-json-core/src/utils/index.ts index 16f232c..cf5d586 100644 --- a/packages/custom-elements-json-core/src/utils/index.ts +++ b/packages/custom-elements-json-core/src/utils/index.ts @@ -5,7 +5,7 @@ import { FunctionDeclaration, ClassDeclaration, JavaScriptModule, - Export + Export, } from 'custom-elements-json/schema'; import { JSDoc } from './extractJsDoc'; @@ -29,26 +29,34 @@ export function hasStaticKeyword(node: any): boolean { export function isAlsoProperty(node: any) { let result = true; ((node.initializer as ts.ObjectLiteralExpression) || node).properties.forEach((property: any) => { - if((property.name as ts.Identifier).text === 'attribute' && property.initializer.kind === ts.SyntaxKind.FalseKeyword) { + if ( + (property.name as ts.Identifier).text === 'attribute' && + property.initializer.kind === ts.SyntaxKind.FalseKeyword + ) { result = false; } - }) + }); return result; } export function getAttrName(node: any): string | undefined { let result = undefined; ((node.initializer as ts.ObjectLiteralExpression) || node).properties.forEach((property: any) => { - if((property.name as ts.Identifier).text === 'attribute' && property.initializer.kind !== ts.SyntaxKind.FalseKeyword) { + if ( + (property.name as ts.Identifier).text === 'attribute' && + property.initializer.kind !== ts.SyntaxKind.FalseKeyword + ) { result = property.initializer.text; } - }) + }); return result; } export function getReturnVal(node: any) { - if(ts.isGetAccessor(node)) { - return (node.body!.statements.find((statement: any) => statement.kind === ts.SyntaxKind.ReturnStatement) as ts.ReturnStatement).expression; + if (ts.isGetAccessor(node)) { + return (node.body!.statements.find( + (statement: any) => statement.kind === ts.SyntaxKind.ReturnStatement, + ) as ts.ReturnStatement).expression; } else { return node.initializer; } @@ -58,21 +66,26 @@ export function alreadyHasAttributes(doc: CustomElement): boolean { return isValidArray(doc.attributes); } -export function hasPropertyDecorator(node: ts.PropertyDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration): boolean { - return isValidArray(node.decorators) && - node.decorators!.some((decorator: ts.Decorator) => ts.isDecorator(decorator)); +export function hasPropertyDecorator( + node: ts.PropertyDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration, +): boolean { + return ( + isValidArray(node.decorators) && + node.decorators!.some((decorator: ts.Decorator) => ts.isDecorator(decorator)) + ); } /** EXPORTS */ -export type ExportType = ts.VariableStatement +export type ExportType = + | ts.VariableStatement | ts.ExportDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration | ts.ExportAssignment; export function hasExportModifier(node: ExportType): boolean { - if(isValidArray(node.modifiers)) { - if(node.modifiers!.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) { + if (isValidArray(node.modifiers)) { + if (node.modifiers!.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) { return true; } } @@ -80,8 +93,8 @@ export function hasExportModifier(node: ExportType): boolean { } export function hasDefaultModifier(node: ExportType): boolean { - if(isValidArray(node.modifiers)) { - if(node.modifiers!.some(mod => mod.kind === ts.SyntaxKind.DefaultKeyword)) { + if (isValidArray(node.modifiers)) { + if (node.modifiers!.some(mod => mod.kind === ts.SyntaxKind.DefaultKeyword)) { return true; } } @@ -89,25 +102,25 @@ export function hasDefaultModifier(node: ExportType): boolean { } export function safePush( - _export: Export | null, - _declaration: VariableDeclaration | FunctionDeclaration | ClassDeclaration | null, - moduleDoc: JavaScriptModule, - ignore: string | undefined - ) { - if(_export) { - if(isValidArray(moduleDoc.exports)) { + _export: Export | null, + _declaration: VariableDeclaration | FunctionDeclaration | ClassDeclaration | null, + moduleDoc: JavaScriptModule, + ignore: string | undefined, +) { + if (_export) { + if (isValidArray(moduleDoc.exports)) { moduleDoc.exports!.push(_export); } else { moduleDoc.exports = [_export]; } } - if(_declaration) { - if(ignore !== undefined && _declaration.name === ignore) return; - if(isValidArray(moduleDoc.declarations)) { + if (_declaration) { + if (ignore !== undefined && _declaration.name === ignore) return; + if (isValidArray(moduleDoc.declarations)) { moduleDoc.declarations.push(_declaration); } else { - moduleDoc.declarations = [_declaration] + moduleDoc.declarations = [_declaration]; } } } @@ -117,7 +130,7 @@ export function safePush( * @example export { var1, var2 }; */ export function hasNamedExports(node: ts.ExportDeclaration): boolean { - if(isValidArray((node as any).exportClause?.elements)) { + if (isValidArray((node as any).exportClause?.elements)) { return true; } return false; @@ -127,9 +140,7 @@ export function hasNamedExports(node: ts.ExportDeclaration): boolean { * @example export { var1, var2 } from 'foo'; */ export function isReexport(node: ts.ExportDeclaration): boolean { - if( - node.moduleSpecifier !== undefined - ) { + if (node.moduleSpecifier !== undefined) { return true; } return false; @@ -140,10 +151,11 @@ export interface Mixin { } export function extractMixins(jsDocs: JSDoc[]): Mixin[] { - if(isValidArray(jsDocs)) { - return jsDocs.filter(jsDoc => jsDoc.tag === 'mixin') - .map((jsDoc) => ({ - name: jsDoc.type + if (isValidArray(jsDocs)) { + return jsDocs + .filter(jsDoc => jsDoc.tag === 'mixin') + .map(jsDoc => ({ + name: jsDoc.type, })); } else { return []; @@ -157,7 +169,8 @@ export function hasMixins(mixins: Mixin[]) { /** IMPORTS */ /** @example import defaultExport from 'foo'; */ -export function hasDefaultImport(node: ts.ImportDeclaration): boolean { // eslint-disable-line +export function hasDefaultImport(node: ts.ImportDeclaration): boolean { + // eslint-disable-line return !!node?.importClause?.name; } @@ -172,12 +185,20 @@ export function hasAggregatingImport(node: any): boolean { } export function isBareModuleSpecifier(specifier: string): boolean { - return !!(specifier.replace(/'/g, ''))[0].match(/[a-zA-Z]/g); + return !!specifier.replace(/'/g, '')[0].match(/[a-zA-Z]/g); } export interface Import { name: string; - kind: "default" | "named" | "aggregate", + kind: 'default' | 'named' | 'aggregate' | 'javascript-module'; importPath: string; - isBareModuleSpecifier: boolean -} \ No newline at end of file + isBareModuleSpecifier: boolean; +} + +/** Type asserters */ +export function isImport(C: T | Import): C is Import { + if ('importPath' in C && 'isBareModuleSpecifier' in C) { + return true; + } + return false; +} diff --git a/packages/custom-elements-json-helpers/src/helpers.ts b/packages/custom-elements-json-helpers/src/helpers.ts index d9d222a..24fce25 100644 --- a/packages/custom-elements-json-helpers/src/helpers.ts +++ b/packages/custom-elements-json-helpers/src/helpers.ts @@ -1,17 +1,24 @@ -import { JavaScriptModule, Declaration, Package, Export, CustomElement, ClassMember } from 'custom-elements-json/schema'; +import { + JavaScriptModule, + Declaration, + Package, + Export, + CustomElement, + ClassMember, +} from 'custom-elements-json/schema'; /** Package */ export function hasModules(_package: Package): boolean { - return Array.isArray(_package?.modules) && (_package?.modules.length > 0); + return Array.isArray(_package?.modules) && _package?.modules.length > 0; } /** JavaScriptModule */ export function hasExports(_module: JavaScriptModule): boolean { - return Array.isArray(_module?.exports) && (_module?.exports.length > 0); + return Array.isArray(_module?.exports) && _module?.exports.length > 0; } export function hasDeclarations(_module: JavaScriptModule): boolean { - return Array.isArray(_module?.declarations) && (_module?.declarations.length > 0); + return Array.isArray(_module?.declarations) && _module?.declarations.length > 0; } export function isJavaScriptModule(_module: JavaScriptModule): boolean { @@ -19,7 +26,7 @@ export function isJavaScriptModule(_module: JavaScriptModule): boolean { } /** Exports */ -export function isCustomElementExport(_export: Declaration|Export): boolean { +export function isCustomElementExport(_export: Declaration | Export): boolean { return _export.kind === 'custom-element-definition'; } @@ -28,48 +35,56 @@ export function isJavaScriptExport(_export: Export): boolean { } /** Declarations */ -export function isClass(item: Declaration|Export): boolean { +export function isClass(item: Declaration | Export): boolean { return item.kind === 'class'; } -export function isFunction(item: Declaration|Export): boolean { +export function isFunction(item: Declaration | Export): boolean { return item.kind === 'function'; } -export function isVariable(item: Declaration|Export): boolean { +export function isVariable(item: Declaration | Export): boolean { return item.kind === 'variable'; } /** CustomElement */ export function hasAttributes(customElement: CustomElement): boolean { - return Array.isArray(customElement?.attributes) && (customElement?.attributes.length > 0); + return Array.isArray(customElement?.attributes) && customElement?.attributes.length > 0; } export function hasEvents(customElement: CustomElement): boolean { - return Array.isArray(customElement?.events) && (customElement?.events.length > 0); + return Array.isArray(customElement?.events) && customElement?.events.length > 0; } export function hasSlots(customElement: CustomElement): boolean { - return Array.isArray(customElement?.slots) && (customElement?.slots.length > 0); + return Array.isArray(customElement?.slots) && customElement?.slots.length > 0; } export function hasMethods(customElement: CustomElement): boolean { - return Array.isArray(customElement?.members) && (customElement?.members.length > 0) && customElement?.members.some(member => member.kind === "method"); + return ( + Array.isArray(customElement?.members) && + customElement?.members.length > 0 && + customElement?.members.some(member => member.kind === 'method') + ); } export function hasFields(customElement: CustomElement): boolean { - return Array.isArray(customElement?.members) && (customElement?.members.length > 0) && customElement?.members.some(member => member.kind === "field"); + return ( + Array.isArray(customElement?.members) && + customElement?.members.length > 0 && + customElement?.members.some(member => member.kind === 'field') + ); } export function hasMixins(customElement: CustomElement): boolean { - return Array.isArray(customElement?.mixins) && (customElement?.mixins.length > 0); + return Array.isArray(customElement?.mixins) && customElement?.mixins.length > 0; } /** ClassMember */ export function isField(member: ClassMember): boolean { - return member.kind === "field"; + return member.kind === 'field'; } export function isMethod(member: ClassMember): boolean { - return member.kind === "method"; + return member.kind === 'method'; } diff --git a/packages/custom-elements-json/schema.ts b/packages/custom-elements-json/schema.ts index d5eb896..6778c11 100644 --- a/packages/custom-elements-json/schema.ts +++ b/packages/custom-elements-json/schema.ts @@ -130,6 +130,7 @@ export type Declaration = | ClassDeclaration | FunctionDeclaration | VariableDeclaration + | MixinDeclaration | CustomElement; /** From 608372081035c6a95a43c90e8ed95f76d3f43b79 Mon Sep 17 00:00:00 2001 From: Andreas Moldskred Date: Sun, 4 Oct 2020 22:15:27 +0200 Subject: [PATCH 2/2] Fix type errors --- .../src/ast/handleEvents.ts | 55 +++++++++++-------- .../custom-elements-json-core/src/create.ts | 31 +++++------ .../src/customElementsJson.ts | 7 +-- .../custom-elements-json-helpers/index.mjs | 3 +- 4 files changed, 50 insertions(+), 46 deletions(-) diff --git a/packages/custom-elements-json-core/src/ast/handleEvents.ts b/packages/custom-elements-json-core/src/ast/handleEvents.ts index 8ab701d..8d933ab 100644 --- a/packages/custom-elements-json-core/src/ast/handleEvents.ts +++ b/packages/custom-elements-json-core/src/ast/handleEvents.ts @@ -1,4 +1,4 @@ -import ts from 'typescript'; +import ts, { isVariableDeclaration, isIdentifier, isCallExpression } from 'typescript'; import { Event, CustomElement } from 'custom-elements-json/schema'; import { customElementsJson } from '../customElementsJson'; import { extractJsDoc } from '../utils/extractJsDoc'; @@ -7,19 +7,21 @@ export function handleEvents(node: any, classDoc: CustomElement) { const events: Event[] = []; classDoc.events = []; - node.members && node.members.forEach((member: ts.MemberExpression) => { - if (ts.isMethodDeclaration(member)) { - visit(member, events); - } - }); + node.members && + node.members.forEach((member: ts.MemberExpression) => { + if (ts.isMethodDeclaration(member)) { + visit(member, events); + } + }); /** Extract events from JSdoc, if any */ const jsDocs = extractJsDoc(node); - if(Array.isArray(jsDocs) && jsDocs.length > 0) { - jsDocs.filter(jsDoc => jsDoc.tag === 'fires' || jsDoc.tag === 'event') + if (Array.isArray(jsDocs) && jsDocs.length > 0) { + jsDocs + .filter(jsDoc => jsDoc.tag === 'fires' || jsDoc.tag === 'event') .forEach(jsDoc => { - const existingEvent = events.find(event => event.name === jsDoc.name) - if(existingEvent) { + const existingEvent = events.find(event => event.name === jsDoc.name); + if (existingEvent) { // event already exists, add the jsdoc description to it existingEvent.description = jsDoc.description.replace('- ', ''); } else { @@ -33,7 +35,7 @@ export function handleEvents(node: any, classDoc: CustomElement) { }); } - if(events.length === 0) { + if (events.length === 0) { delete classDoc.events; } else { classDoc.events = events; @@ -46,17 +48,16 @@ function visit(source: any, events: Event[]) { function visitNode(node: any) { switch (node.kind) { case ts.SyntaxKind.CallExpression: - if(node.expression.name.getText() === 'dispatchEvent') { - + if (node.expression.name.getText() === 'dispatchEvent') { const eventDoc: Event = { name: '', type: { type: '', - } + }, }; node.arguments.forEach((arg: any) => { - if(arg.kind === ts.SyntaxKind.NewExpression) { + if (arg.kind === ts.SyntaxKind.NewExpression) { // @TODO // if the type of event is not Event or CustomEvent, find a reference to the type eventDoc.name = arg.arguments[0].text; @@ -64,17 +65,23 @@ function visit(source: any, events: Event[]) { events.push(eventDoc); } - if(arg.kind === ts.SyntaxKind.Identifier) { - customElementsJson.visitCurrentModule((node) => { - switch (node.kind) { - case ts.SyntaxKind.Identifier: - if(node.parent.kind === ts.SyntaxKind.VariableDeclaration) { - if(node.getText() === arg.getText()) { - eventDoc.name = node.parent.initializer.arguments[0].text; - eventDoc.type = { type: node.parent.initializer.expression.getText() }; + if (isIdentifier(arg)) { + customElementsJson.visitCurrentModule(node => { + if (isIdentifier(node)) { + if (isVariableDeclaration(node.parent)) { + if (node.getText() === arg.getText()) { + const initializer = node?.parent?.initializer; + if (initializer && isCallExpression(initializer)) { + // TODO: I didn't want to type this as any. + // But I think you might've made some assumptions + // that I don't understand by reading this code. + const firstArg = initializer.arguments?.[0] as any; + eventDoc.name = firstArg.text; + eventDoc.type = { type: initializer.expression?.getText() }; events.push(eventDoc); } } + } } }); } @@ -84,4 +91,4 @@ function visit(source: any, events: Event[]) { ts.forEachChild(node, visitNode); } -} \ No newline at end of file +} diff --git a/packages/custom-elements-json-core/src/create.ts b/packages/custom-elements-json-core/src/create.ts index d872ec8..802d3c6 100644 --- a/packages/custom-elements-json-core/src/create.ts +++ b/packages/custom-elements-json-core/src/create.ts @@ -1,28 +1,25 @@ -import path from 'path'; -import fs from 'fs'; -import globby from 'globby'; -import ts from 'typescript'; import { - Package, - Declaration, - ClassDeclaration, - JavaScriptModule, - CustomElement, - Export, Attribute, + ClassDeclaration, ClassMember, + CustomElement, + Declaration, Event, + Export, + JavaScriptModule, + Package, } from 'custom-elements-json/schema'; -import { ExportType, isImport } from './utils'; -import { Import, isBareModuleSpecifier } from './utils'; - -import { customElementsJson } from './customElementsJson'; - +import fs from 'fs'; +import globby from 'globby'; +import path from 'path'; +import ts from 'typescript'; +import { getMixin } from './ast/getMixin'; import { handleClass } from './ast/handleClass'; import { handleCustomElementsDefine } from './ast/handleCustomElementsDefine'; import { handleExport } from './ast/handleExport'; import { handleImport } from './ast/handleImport'; -import { getMixin } from './ast/getMixin'; +import { customElementsJson } from './customElementsJson'; +import { ExportType, isBareModuleSpecifier, isImport } from './utils'; export async function create(packagePath: string): Promise { const modulePaths = await globby([`${packagePath}/**/*.js`]); @@ -290,8 +287,8 @@ export async function create(packagePath: string): Promise { }); }); }); + customElementsJson.imports = []; - delete customElementsJson.imports; delete customElementsJson.currentModule; console.log(JSON.stringify(customElementsJson, null, 2)); diff --git a/packages/custom-elements-json-core/src/customElementsJson.ts b/packages/custom-elements-json-core/src/customElementsJson.ts index fb1b907..db5c64a 100644 --- a/packages/custom-elements-json-core/src/customElementsJson.ts +++ b/packages/custom-elements-json-core/src/customElementsJson.ts @@ -1,13 +1,12 @@ +import { CustomElementsJson } from '@custom-elements-json/helpers'; import ts from 'typescript'; -import { CustomElementsJson } from 'custom-elements-json-helpers'; import { Import } from './utils'; -import { Package } from 'custom-elements-json/schema'; export class ExtendedCustomElementsJson extends CustomElementsJson { currentModule: ts.Node | undefined; imports: Import[]; - constructor(props: Package) { - super(props); + constructor() { + super(); this.imports = []; } diff --git a/packages/custom-elements-json-helpers/index.mjs b/packages/custom-elements-json-helpers/index.mjs index 5e20c1b..259f092 100644 --- a/packages/custom-elements-json-helpers/index.mjs +++ b/packages/custom-elements-json-helpers/index.mjs @@ -32,4 +32,5 @@ export { hasMixins, isField, isMethod, -}; \ No newline at end of file +}; +export default cjsEntrypoint;