From 4d5107113e51b4a3a01aae57784bd2a7e18691ba Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 21 May 2017 18:05:11 -0400 Subject: [PATCH] more TS --- src/index.ts | 3 +- src/interfaces.ts | 9 ++++- src/parse/index.ts | 4 +-- src/utils/annotateWithScopes.ts | 39 +++++++++++--------- src/utils/flattenReference.ts | 4 ++- src/utils/removeNode.ts | 4 ++- src/utils/toSource.ts | 44 ----------------------- src/validate/html/index.ts | 6 ++-- src/validate/html/validateElement.ts | 20 ++++++----- src/validate/html/validateEventHandler.ts | 4 ++- src/validate/html/validateWindow.ts | 6 ++-- src/validate/index.ts | 10 +++--- src/validate/js/index.ts | 20 +++++------ 13 files changed, 78 insertions(+), 95 deletions(-) delete mode 100644 src/utils/toSource.ts diff --git a/src/index.ts b/src/index.ts index 0c53e1840b..19c5b41930 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import generate from './generators/dom/index'; import generateSSR from './generators/server-side-rendering/index'; import { assign } from './shared/index.js'; import { version } from '../package.json'; +import { Parsed } from './interface'; function normalizeOptions ( options ) { return assign( { @@ -29,7 +30,7 @@ function normalizeOptions ( options ) { export function compile ( source, _options ) { const options = normalizeOptions( _options ); - let parsed; + let parsed: Parsed; try { parsed = parse( source, options ); diff --git a/src/interfaces.ts b/src/interfaces.ts index acdcd71e99..897c50b625 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -15,5 +15,12 @@ export interface Parser { html: Node; css: Node; js: Node; - metaTags: {} + metaTags: {}; +} + +export interface Parsed { + hash: number; + html: Node; + css: Node; + js: Node; } \ No newline at end of file diff --git a/src/parse/index.ts b/src/parse/index.ts index 5c9e2257fe..262dc764d5 100644 --- a/src/parse/index.ts +++ b/src/parse/index.ts @@ -4,7 +4,7 @@ import { whitespace } from '../utils/patterns'; import { trimStart, trimEnd } from '../utils/trim'; import getCodeFrame from '../utils/getCodeFrame'; import hash from './utils/hash'; -import { Node } from '../interfaces'; +import { Node, Parsed } from '../interfaces'; import CompileError from '../utils/CompileError' class ParseError extends CompileError { @@ -178,7 +178,7 @@ export class Parser { } } -export default function parse ( template: string, options: ParserOptions = {} ) { +export default function parse ( template: string, options: ParserOptions = {} ) :Parsed { const parser = new Parser( template, options ); return { diff --git a/src/utils/annotateWithScopes.ts b/src/utils/annotateWithScopes.ts index cc7926e6b9..7989065f38 100644 --- a/src/utils/annotateWithScopes.ts +++ b/src/utils/annotateWithScopes.ts @@ -1,10 +1,11 @@ import { walk } from 'estree-walker'; +import { Node } from '../interfaces'; -export default function annotateWithScopes ( expression ) { +export default function annotateWithScopes ( expression: Node ) { let scope = new Scope( null, false ); walk( expression, { - enter ( node ) { + enter ( node: Node ) { if ( /Function/.test( node.type ) ) { if ( node.type === 'FunctionDeclaration' ) { scope.declarations.add( node.id.name ); @@ -13,7 +14,7 @@ export default function annotateWithScopes ( expression ) { if ( node.id ) scope.declarations.add( node.id.name ); } - node.params.forEach( param => { + node.params.forEach( ( param: Node ) => { extractNames( param ).forEach( name => { scope.declarations.add( name ); }); @@ -33,7 +34,7 @@ export default function annotateWithScopes ( expression ) { } }, - leave ( node ) { + leave ( node: Node ) { if ( node._scope ) { scope = scope.parent; } @@ -44,17 +45,21 @@ export default function annotateWithScopes ( expression ) { } class Scope { - constructor ( parent, block ) { + parent: Scope + block: boolean + declarations: Set + + constructor ( parent: Scope, block: boolean ) { this.parent = parent; this.block = block; this.declarations = new Set(); } - addDeclaration ( node ) { + addDeclaration ( node: Node ) { if ( node.kind === 'var' && !this.block && this.parent ) { this.parent.addDeclaration( node ); } else if ( node.type === 'VariableDeclaration' ) { - node.declarations.forEach( declarator => { + node.declarations.forEach( ( declarator: Node ) => { extractNames( declarator.id ).forEach( name => { this.declarations.add( name ); }); @@ -64,39 +69,39 @@ class Scope { } } - has ( name ) { + has ( name: string ) :boolean { return this.declarations.has( name ) || this.parent && this.parent.has( name ); } } -function extractNames ( param ) { - const names = []; +function extractNames ( param: Node ) { + const names: string[] = []; extractors[ param.type ]( names, param ); return names; } const extractors = { - Identifier ( names, param ) { + Identifier ( names: string[], param: Node ) { names.push( param.name ); }, - ObjectPattern ( names, param ) { - param.properties.forEach( prop => { + ObjectPattern ( names: string[], param: Node ) { + param.properties.forEach( ( prop: Node ) => { extractors[ prop.value.type ]( names, prop.value ); }); }, - ArrayPattern ( names, param ) { - param.elements.forEach( element => { + ArrayPattern ( names: string[], param: Node ) { + param.elements.forEach( ( element: Node ) => { if ( element ) extractors[ element.type ]( names, element ); }); }, - RestElement ( names, param ) { + RestElement ( names: string[], param: Node ) { extractors[ param.argument.type ]( names, param.argument ); }, - AssignmentPattern ( names, param ) { + AssignmentPattern ( names: string[], param: Node ) { extractors[ param.left.type ]( names, param.left ); } }; diff --git a/src/utils/flattenReference.ts b/src/utils/flattenReference.ts index c4b46e914f..90946f3a8b 100644 --- a/src/utils/flattenReference.ts +++ b/src/utils/flattenReference.ts @@ -1,4 +1,6 @@ -export default function flatten ( node ) { +import { Node } from '../interfaces'; + +export default function flatten ( node: Node ) { const parts = []; const propEnd = node.end; diff --git a/src/utils/removeNode.ts b/src/utils/removeNode.ts index aecec33455..ec3a7152fa 100644 --- a/src/utils/removeNode.ts +++ b/src/utils/removeNode.ts @@ -1,3 +1,5 @@ +import { Node } from '../interfaces'; + const keys = { ObjectExpression: 'properties', Program: 'body' @@ -8,7 +10,7 @@ const offsets = { Program: [ 0, 0 ] }; -export function removeNode ( code, parent, node ) { +export function removeNode ( code, parent: Node, node: Node ) { const key = keys[ parent.type ]; const offset = offsets[ parent.type ]; if ( !key || !offset ) throw new Error( `not implemented: ${parent.type}` ); diff --git a/src/utils/toSource.ts b/src/utils/toSource.ts deleted file mode 100644 index 2318a6bd44..0000000000 --- a/src/utils/toSource.ts +++ /dev/null @@ -1,44 +0,0 @@ -import deindent from './deindent.js'; - -export default function toSource ( thing: any ) :string { - if ( typeof thing === 'function' ) { - return normaliseIndentation( thing.toString() ); - } - - if ( Array.isArray( thing ) ) { - if ( thing.length === 0 ) return '[]'; - throw new Error( 'TODO' ); // not currently needed - } - - if ( thing && typeof thing === 'object' ) { - const keys = Object.keys( thing ); - if ( keys.length === 0 ) return '{}'; - - const props = keys.map( key => `${key}: ${toSource( thing[ key ] )}` ).join( ',\n' ); - return deindent` - { - ${props} - } - `; - } - - return JSON.stringify( thing ); -} - -function normaliseIndentation ( str: string ) { - const lines = str.split( '\n' ).slice( 1, -1 ); - let minIndentation = Infinity; - - lines.forEach( line => { - if ( !/\S/.test( line ) ) return; - const indentation = /^\t*/.exec( line )[0].length; - if ( indentation < minIndentation ) minIndentation = indentation; - }); - - if ( minIndentation !== Infinity && minIndentation !== 1 ) { - const pattern = new RegExp( `^\\t{${minIndentation - 1}}`, 'gm' ); - return str.replace( pattern, '' ); - } - - return str; -} \ No newline at end of file diff --git a/src/validate/html/index.ts b/src/validate/html/index.ts index 53076c69a3..4256ca3951 100644 --- a/src/validate/html/index.ts +++ b/src/validate/html/index.ts @@ -1,6 +1,8 @@ import * as namespaces from '../../utils/namespaces'; import validateElement from './validateElement'; import validateWindow from './validateWindow'; +import { Validator } from '../index'; +import { Node } from '../../interfaces'; const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|switch|symbol|text|textPath|title|tref|tspan|unknown|use|view|vkern)$/; @@ -8,10 +10,10 @@ const meta = new Map([ [ ':Window', validateWindow ] ]); -export default function validateHtml ( validator, html ) { +export default function validateHtml ( validator: Validator, html: Node ) { let elementDepth = 0; - function visit ( node ) { + function visit ( node: Node ) { if ( node.type === 'Element' ) { if ( elementDepth === 0 && validator.namespace !== namespaces.svg && svg.test( node.name ) ) { validator.warn( `<${node.name}> is an SVG element – did you forget to add { namespace: 'svg' } ?`, node.start ); diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts index bc0ba07f12..6610e7ee69 100644 --- a/src/validate/html/validateElement.ts +++ b/src/validate/html/validateElement.ts @@ -1,13 +1,15 @@ import validateEventHandler from './validateEventHandler'; +import { Validator } from '../index'; +import { Node } from '../../interfaces'; -export default function validateElement ( validator, node ) { +export default function validateElement ( validator: Validator, node: Node ) { const isComponent = node.name === ':Self' || validator.components.has( node.name ); - let hasIntro; - let hasOutro; - let hasTransition; + let hasIntro: boolean; + let hasOutro: boolean; + let hasTransition: boolean; - node.attributes.forEach( attribute => { + node.attributes.forEach( ( attribute: Node ) => { if ( !isComponent && attribute.type === 'Binding' ) { const { name } = attribute; @@ -35,13 +37,13 @@ export default function validateElement ( validator, node ) { const type = getType( validator, node ); if ( type !== 'checkbox' && type !== 'radio' ) { - validator.error( `'checked' binding can only be used with or ` ); + validator.error( `'checked' binding can only be used with or `, attribute.start ); } } else if ( name === 'currentTime' || name === 'duration' || name === 'paused' ) { if ( node.name !== 'audio' && node.name !== 'video' ) { - validator.error( `'${name}' binding can only be used with