diff --git a/package.json b/package.json index aa7242cc82..e820e8d2e8 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,8 @@ }, "homepage": "https://github.com/sveltejs/svelte#README", "devDependencies": { + "@types/mocha": "^2.2.41", + "@types/node": "^7.0.22", "acorn": "^4.0.4", "babel": "^6.23.0", "babel-core": "^6.23.1", @@ -74,9 +76,11 @@ "rollup-plugin-commonjs": "^7.0.0", "rollup-plugin-json": "^2.1.0", "rollup-plugin-node-resolve": "^2.0.0", + "rollup-plugin-typescript": "^0.8.1", "rollup-watch": "^3.2.2", "source-map": "^0.5.6", - "source-map-support": "^0.4.8" + "source-map-support": "^0.4.8", + "typescript": "^2.3.2" }, "nyc": { "include": [ diff --git a/rename.js b/rename.js new file mode 100644 index 0000000000..ad3804e39d --- /dev/null +++ b/rename.js @@ -0,0 +1,9 @@ +const glob = require( 'glob' ); +const fs = require( 'fs' ); + +glob.sync( 'src/**/*.js' ).forEach( file => { + console.log( file ); + const js = fs.readFileSync( file, 'utf-8' ); + fs.writeFileSync( file.replace( /\.js$/, '.ts' ), js ); + fs.unlinkSync( file ); +}); \ No newline at end of file diff --git a/rollup/rollup.config.main.js b/rollup/rollup.config.main.js index c05b9911cf..cfb80b5d52 100644 --- a/rollup/rollup.config.main.js +++ b/rollup/rollup.config.main.js @@ -1,24 +1,35 @@ +import path from 'path'; import nodeResolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import json from 'rollup-plugin-json'; -import buble from 'rollup-plugin-buble'; +import typescript from 'rollup-plugin-typescript'; + +const src = path.resolve( 'src' ); export default { - entry: 'src/index.js', + entry: 'src/index.ts', moduleName: 'svelte', targets: [ { dest: 'compiler/svelte.js', format: 'umd' } ], plugins: [ + { + resolveId ( importee, importer ) { + // bit of a hack — TypeScript only really works if it can resolve imports, + // but they misguidedly chose to reject imports with file extensions. This + // means we need to resolve them here + if ( importer && importer.startsWith( src ) && importee[0] === '.' && path.extname( importee ) === '' ) { + return path.resolve( path.dirname( importer ), `${importee}.ts` ); + } + } + }, nodeResolve({ jsnext: true, module: true }), commonjs(), json(), - buble({ + typescript({ include: 'src/**', exclude: 'src/shared/**', - target: { - node: 4 - } + typescript: require( 'typescript' ) }) ], sourceMap: true diff --git a/rollup/rollup.config.ssr.js b/rollup/rollup.config.ssr.js index 38caf3ece4..e44315af38 100644 --- a/rollup/rollup.config.ssr.js +++ b/rollup/rollup.config.ssr.js @@ -20,9 +20,9 @@ export default { } }) ], - external: [ path.resolve( 'src/index.js' ), 'fs', 'path' ], + external: [ path.resolve( 'src/index.ts' ), 'fs', 'path' ], paths: { - [ path.resolve( 'src/index.js' ) ]: '../compiler/svelte.js' + [ path.resolve( 'src/index.ts' ) ]: '../compiler/svelte.js' }, sourceMap: true }; diff --git a/src/generators/Generator.js b/src/generators/Generator.ts similarity index 78% rename from src/generators/Generator.js rename to src/generators/Generator.ts index 7a316adc85..fc87740e5a 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.ts @@ -1,20 +1,45 @@ import MagicString, { Bundle } from 'magic-string'; import { walk } from 'estree-walker'; -import isReference from '../utils/isReference.js'; -import flattenReference from '../utils/flattenReference.js'; -import globalWhitelist from '../utils/globalWhitelist.js'; -import reservedNames from '../utils/reservedNames.js'; -import namespaces from '../utils/namespaces.js'; -import { removeNode, removeObjectKey } from '../utils/removeNode.js'; -import getIntro from './shared/utils/getIntro.js'; -import getOutro from './shared/utils/getOutro.js'; -import processCss from './shared/processCss.js'; -import annotateWithScopes from '../utils/annotateWithScopes.js'; +import isReference from '../utils/isReference'; +import flattenReference from '../utils/flattenReference'; +import globalWhitelist from '../utils/globalWhitelist'; +import reservedNames from '../utils/reservedNames'; +import namespaces from '../utils/namespaces'; +import { removeNode, removeObjectKey } from '../utils/removeNode'; +import getIntro from './shared/utils/getIntro'; +import getOutro from './shared/utils/getOutro'; +import processCss from './shared/processCss'; +import annotateWithScopes from '../utils/annotateWithScopes'; +import DomBlock from './dom/Block'; +import SsrBlock from './server-side-rendering/Block'; +import { Node, Parsed, CompileOptions } from '../interfaces'; const test = typeof global !== 'undefined' && global.__svelte_test; export default class Generator { - constructor ( parsed, source, name, options ) { + parsed: Parsed; + source: string; + name: string; + options: CompileOptions; + + imports: Node[]; + helpers: Set; + components: Set; + events: Set; + transitions: Set; + importedComponents: Map; + + bindingGroups: string[]; + expectedProperties: Set; + css: string; + cssId: string; + usesRefs: boolean; + + importedNames: Set; + aliases: Map; + usedNames: Set; + + constructor ( parsed: Parsed, source: string, name: string, options: CompileOptions ) { this.parsed = parsed; this.source = source; this.name = name; @@ -39,22 +64,22 @@ export default class Generator { this.usesRefs = false; // allow compiler to deconflict user's `import { get } from 'whatever'` and - // Svelte's builtin `import { get, ... } from 'svelte/shared.js'`; + // Svelte's builtin `import { get, ... } from 'svelte/shared.ts'`; this.importedNames = new Set(); this.aliases = new Map(); - this._usedNames = new Set( [ name ] ); + this.usedNames = new Set( [ name ] ); } - addSourcemapLocations ( node ) { + addSourcemapLocations ( node: Node ) { walk( node, { - enter: node => { + enter: ( node: Node ) => { this.code.addSourcemapLocation( node.start ); this.code.addSourcemapLocation( node.end ); } }); } - alias ( name ) { + alias ( name: string ) { if ( !this.aliases.has( name ) ) { this.aliases.set( name, this.getUniqueName( name ) ); } @@ -62,10 +87,10 @@ export default class Generator { return this.aliases.get( name ); } - contextualise ( block, expression, context, isEventHandler ) { + contextualise ( block: DomBlock | SsrBlock, expression: Node, context: string, isEventHandler: boolean ) { this.addSourcemapLocations( expression ); - const usedContexts = []; + const usedContexts: string[] = []; const { code, helpers } = this; const { contexts, indexes } = block; @@ -76,7 +101,7 @@ export default class Generator { const self = this; walk( expression, { - enter ( node, parent, key ) { + enter ( node: Node, parent: Node, key: string ) { if ( /^Function/.test( node.type ) ) lexicalDepth += 1; if ( node._scope ) { @@ -138,7 +163,7 @@ export default class Generator { } }, - leave ( node ) { + leave ( node: Node ) { if ( /^Function/.test( node.type ) ) lexicalDepth -= 1; if ( node._scope ) scope = scope.parent; } @@ -151,16 +176,16 @@ export default class Generator { }; } - findDependencies ( contextDependencies, indexes, expression ) { + findDependencies ( contextDependencies: Map, indexes: Map, expression: Node ) { if ( expression._dependencies ) return expression._dependencies; let scope = annotateWithScopes( expression ); - const dependencies = []; + const dependencies: string[] = []; const generator = this; // can't use arrow functions, because of this.skip() walk( expression, { - enter ( node, parent ) { + enter ( node: Node, parent: Node ) { if ( node._scope ) { scope = node._scope; return; @@ -180,7 +205,7 @@ export default class Generator { } }, - leave ( node ) { + leave ( node: Node ) { if ( node._scope ) scope = scope.parent; } }); @@ -196,7 +221,7 @@ export default class Generator { generate ( result, options, { name, format } ) { if ( this.imports.length ) { - const statements = []; + const statements: string[] = []; this.imports.forEach( ( declaration, i ) => { if ( format === 'es' ) { @@ -204,14 +229,14 @@ export default class Generator { return; } - const defaultImport = declaration.specifiers.find( x => x.type === 'ImportDefaultSpecifier' || x.type === 'ImportSpecifier' && x.imported.name === 'default' ); - const namespaceImport = declaration.specifiers.find( x => x.type === 'ImportNamespaceSpecifier' ); - const namedImports = declaration.specifiers.filter( x => x.type === 'ImportSpecifier' && x.imported.name !== 'default' ); + const defaultImport = declaration.specifiers.find( ( x: Node ) => x.type === 'ImportDefaultSpecifier' || x.type === 'ImportSpecifier' && x.imported.name === 'default' ); + const namespaceImport = declaration.specifiers.find( ( x: Node ) => x.type === 'ImportNamespaceSpecifier' ); + const namedImports = declaration.specifiers.filter( ( x: Node ) => x.type === 'ImportSpecifier' && x.imported.name !== 'default' ); const name = ( defaultImport || namespaceImport ) ? ( defaultImport || namespaceImport ).local.name : `__import${i}`; declaration.name = name; // hacky but makes life a bit easier later - namedImports.forEach( specifier => { + namedImports.forEach( ( specifier: Node ) => { statements.push( `var ${specifier.local.name} = ${name}.${specifier.imported.name}` ); }); @@ -230,7 +255,7 @@ export default class Generator { const compiled = new Bundle({ separator: '' }); - function addString ( str ) { + function addString ( str: string ) { compiled.addSource({ content: new MagicString( str ) }); @@ -250,7 +275,7 @@ export default class Generator { }); } - parts.forEach( str => { + parts.forEach( ( str: string ) => { const chunk = str.replace( pattern, '' ); if ( chunk ) addString( chunk ); @@ -274,11 +299,11 @@ export default class Generator { }; } - getUniqueName ( name ) { + getUniqueName ( name: string ) { if ( test ) name = `${name}$`; let alias = name; - for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this._usedNames.has( alias ); alias = `${name}_${i++}` ); - this._usedNames.add( alias ); + for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this.usedNames.has( alias ); alias = `${name}_${i++}` ); + this.usedNames.add( alias ); return alias; } @@ -287,13 +312,13 @@ export default class Generator { return name => { if ( test ) name = `${name}$`; let alias = name; - for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this._usedNames.has( alias ) || localUsedNames.has( alias ); alias = `${name}_${i++}` ); + for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this.usedNames.has( alias ) || localUsedNames.has( alias ); alias = `${name}_${i++}` ); localUsedNames.add( alias ); return alias; }; } - parseJs ( ssr ) { + parseJs ( ssr: boolean = false ) { const { source } = this; const { js } = this.parsed; @@ -315,23 +340,23 @@ export default class Generator { removeNode( this.code, js.content, node ); imports.push( node ); - node.specifiers.forEach( specifier => { + node.specifiers.forEach( ( specifier: Node ) => { this.importedNames.add( specifier.local.name ); }); } } - const defaultExport = body.find( node => node.type === 'ExportDefaultDeclaration' ); + const defaultExport = body.find( ( node: Node ) => node.type === 'ExportDefaultDeclaration' ); if ( defaultExport ) { - defaultExport.declaration.properties.forEach( prop => { + defaultExport.declaration.properties.forEach( ( prop: Node ) => { templateProperties[ prop.key.name ] = prop; }); } [ 'helpers', 'events', 'components', 'transitions' ].forEach( key => { if ( templateProperties[ key ] ) { - templateProperties[ key ].value.properties.forEach( prop => { + templateProperties[ key ].value.properties.forEach( ( prop: node ) => { this[ key ].add( prop.key.name ); }); } @@ -340,11 +365,11 @@ export default class Generator { if ( templateProperties.computed ) { const dependencies = new Map(); - templateProperties.computed.value.properties.forEach( prop => { + templateProperties.computed.value.properties.forEach( ( prop: Node ) => { const key = prop.key.name; const value = prop.value; - const deps = value.params.map( param => param.type === 'AssignmentPattern' ? param.left.name : param.name ); + const deps = value.params.map( ( param: Node ) => param.type === 'AssignmentPattern' ? param.left.name : param.name ); dependencies.set( key, deps ); }); @@ -362,7 +387,7 @@ export default class Generator { computations.push({ key, deps }); } - templateProperties.computed.value.properties.forEach( prop => visit( prop.key.name ) ); + templateProperties.computed.value.properties.forEach( ( prop: Node ) => visit( prop.key.name ) ); } if ( templateProperties.namespace ) { @@ -374,7 +399,7 @@ export default class Generator { if ( templateProperties.components ) { let hasNonImportedComponent = false; - templateProperties.components.value.properties.forEach( property => { + templateProperties.components.value.properties.forEach( ( property: Node ) => { const key = property.key.name; const value = source.slice( property.value.start, property.value.end ); if ( this.importedNames.has( value ) ) { diff --git a/src/generators/dom/Block.js b/src/generators/dom/Block.ts similarity index 78% rename from src/generators/dom/Block.js rename to src/generators/dom/Block.ts index 83841b738d..9523d42e7c 100644 --- a/src/generators/dom/Block.js +++ b/src/generators/dom/Block.ts @@ -1,8 +1,70 @@ -import CodeBuilder from '../../utils/CodeBuilder.js'; +import CodeBuilder from '../../utils/CodeBuilder'; import deindent from '../../utils/deindent.js'; +import { DomGenerator } from './index'; +import { Node } from '../../interfaces'; + +export interface BlockOptions { + name: string; + generator?: DomGenerator; + expression?: Node; + context?: string; + key?: string; + contexts?: Map; + indexes?: Map; + contextDependencies?: Map; + params?: string[]; + indexNames?: Map; + listNames?: Map; + indexName?: string; + listName?: string; + dependencies?: Set; +} export default class Block { - constructor ( options ) { + generator: DomGenerator; + name: string; + expression: Node; + context: string; + + key: string; + first: string; + + contexts: Map; + indexes: Map; + contextDependencies: Map; + dependencies: Set; + params: string[]; + indexNames: Map; + listNames: Map; + indexName: string; + listName: string; + + builders: { + create: CodeBuilder; + mount: CodeBuilder; + update: CodeBuilder; + intro: CodeBuilder; + outro: CodeBuilder; + detach: CodeBuilder; + detachRaw: CodeBuilder; + destroy: CodeBuilder; + } + + hasIntroMethod: boolean; + hasOutroMethod: boolean; + outros: number; + + aliases: Map; + variables: Map; + getUniqueName: (name: string) => string; + + component: string; + target: string; + + hasUpdateMethod: boolean; + autofocus: string; + + constructor ( options: BlockOptions ) { this.generator = options.generator; this.name = options.name; this.expression = options.expression; @@ -55,7 +117,7 @@ export default class Block { }); } - addElement ( name, renderStatement, parentNode, needsIdentifier = false ) { + addElement ( name: string, renderStatement: string, parentNode: string, needsIdentifier = false ) { const isToplevel = !parentNode; if ( needsIdentifier || isToplevel ) { this.builders.create.addLine( @@ -72,7 +134,7 @@ export default class Block { } } - addVariable ( name, init ) { + addVariable ( name: string, init?: string ) { if ( this.variables.has( name ) && this.variables.get( name ) !== init ) { throw new Error( `Variable '${name}' already initialised with a different value` ); } @@ -80,7 +142,7 @@ export default class Block { this.variables.set( name, init ); } - alias ( name ) { + alias ( name: string ) { if ( !this.aliases.has( name ) ) { this.aliases.set( name, this.getUniqueName( name ) ); } @@ -88,11 +150,11 @@ export default class Block { return this.aliases.get( name ); } - child ( options ) { + child ( options: BlockOptions ) { return new Block( Object.assign( {}, this, options, { parent: this } ) ); } - contextualise ( expression, context, isEventHandler ) { + contextualise ( expression: Node, context?: string, isEventHandler?: boolean ) { return this.generator.contextualise( this, expression, context, isEventHandler ); } @@ -100,7 +162,7 @@ export default class Block { return this.generator.findDependencies( this.contextDependencies, this.indexes, expression ); } - mount ( name, parentNode ) { + mount ( name: string, parentNode: string ) { if ( parentNode ) { this.builders.create.addLine( `${this.generator.helper( 'appendNode' )}( ${name}, ${parentNode} );` ); } else { diff --git a/src/generators/dom/index.js b/src/generators/dom/index.ts similarity index 89% rename from src/generators/dom/index.js rename to src/generators/dom/index.ts index cb331fd96a..dc112bb4ca 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.ts @@ -1,17 +1,28 @@ import MagicString from 'magic-string'; import { parseExpressionAt } from 'acorn'; -import annotateWithScopes from '../../utils/annotateWithScopes.js'; -import isReference from '../../utils/isReference.js'; +import annotateWithScopes from '../../utils/annotateWithScopes'; +import isReference from '../../utils/isReference'; import { walk } from 'estree-walker'; import deindent from '../../utils/deindent.js'; -import CodeBuilder from '../../utils/CodeBuilder.js'; -import visit from './visit.js'; -import shared from './shared.js'; -import Generator from '../Generator.js'; -import preprocess from './preprocess.js'; - -class DomGenerator extends Generator { - constructor ( parsed, source, name, options ) { +import CodeBuilder from '../../utils/CodeBuilder'; +import visit from './visit'; +import shared from './shared'; +import Generator from '../Generator'; +import preprocess from './preprocess'; +import Block from './Block'; +import { Parsed, CompileOptions, Node } from '../../interfaces'; + +export class DomGenerator extends Generator { + blocks: Block[] + uses: Set; + readonly: Set; + metaBindings: string[]; + + hasIntroTransitions: boolean; + hasOutroTransitions: boolean; + hasComplexBindings: boolean; + + constructor ( parsed: Parsed, source: string, name: string, options: CompileOptions ) { super( parsed, source, name, options ); this.blocks = []; this.uses = new Set(); @@ -22,7 +33,7 @@ class DomGenerator extends Generator { this.metaBindings = []; } - helper ( name ) { + helper ( name: string ) { if ( this.options.dev && `${name}Dev` in shared ) { name = `${name}Dev`; } @@ -33,7 +44,7 @@ class DomGenerator extends Generator { } } -export default function dom ( parsed, source, options ) { +export default function dom ( parsed: Parsed, source: string, options: CompileOptions ) { const format = options.format || 'es'; const name = options.name || 'SvelteComponent'; @@ -41,15 +52,9 @@ export default function dom ( parsed, source, options ) { const { computations, hasJs, templateProperties, namespace } = generator.parseJs(); - const state = { - namespace, - parentNode: null, - isTopLevel: true - }; - - const block = preprocess( generator, state, parsed.html ); + const { block, state } = preprocess( generator, namespace, parsed.html ); - parsed.html.children.forEach( node => { + parsed.html.children.forEach( ( node: Node ) => { visit( generator, block, state, node ); }); diff --git a/src/generators/dom/interfaces.ts b/src/generators/dom/interfaces.ts new file mode 100644 index 0000000000..a58069da90 --- /dev/null +++ b/src/generators/dom/interfaces.ts @@ -0,0 +1,11 @@ +export interface State { + name: string; + namespace: string; + parentNode: string; + isTopLevel: boolean + parentNodeName?: string; + basename?: string; + inEachBlock?: boolean; + allUsedContexts?: string[]; + usesComponent?: boolean; +} diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.ts similarity index 84% rename from src/generators/dom/preprocess.js rename to src/generators/dom/preprocess.ts index 522a682074..3a96aca3f2 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.ts @@ -1,12 +1,15 @@ -import Block from './Block.js'; -import { trimStart, trimEnd } from '../../utils/trim.js'; +import Block from './Block'; +import { trimStart, trimEnd } from '../../utils/trim'; import { assign } from '../../shared/index.js'; +import { DomGenerator } from './index'; +import { Node } from '../../interfaces'; +import { State } from './interfaces'; -function isElseIf ( node ) { +function isElseIf ( node: Node ) { return node && node.children.length === 1 && node.children[0].type === 'IfBlock'; } -function getChildState ( parent, child ) { +function getChildState ( parent: State, child = {} ) { return assign( {}, parent, { name: null, parentNode: null }, child || {} ); } @@ -25,7 +28,7 @@ const elementsWithoutText = new Set([ ]); const preprocessors = { - MustacheTag: ( generator, block, state, node ) => { + MustacheTag: ( generator: DomGenerator, block: Block, state: State, node: Node ) => { const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); @@ -34,7 +37,7 @@ const preprocessors = { }); }, - RawMustacheTag: ( generator, block, state, node ) => { + RawMustacheTag: ( generator: DomGenerator, block: Block, state: State, node: Node ) => { const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); @@ -44,7 +47,7 @@ const preprocessors = { node._state = getChildState( state, { basename, name }); }, - Text: ( generator, block, state, node ) => { + Text: ( generator: DomGenerator, block: Block, state: State, node: Node ) => { node._state = getChildState( state ); if ( !/\S/.test( node.data ) ) { @@ -56,13 +59,13 @@ const preprocessors = { node._state.name = block.getUniqueName( `text` ); }, - IfBlock: ( generator, block, state, node ) => { - const blocks = []; + IfBlock: ( generator: DomGenerator, block: Block, state: State, node: Node ) => { + const blocks: Block[] = []; let dynamic = false; let hasIntros = false; let hasOutros = false; - function attachBlocks ( node ) { + function attachBlocks ( node: Node ) { const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); @@ -113,7 +116,7 @@ const preprocessors = { generator.blocks.push( ...blocks ); }, - EachBlock: ( generator, block, state, node ) => { + EachBlock: ( generator: DomGenerator, block: Block, state: State, node: Node ) => { const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); @@ -175,7 +178,7 @@ const preprocessors = { } }, - Element: ( generator, block, state, node ) => { + Element: ( generator: DomGenerator, block: Block, state: State, node: Node ) => { const isComponent = generator.components.has( node.name ) || node.name === ':Self'; if ( isComponent ) { @@ -193,9 +196,9 @@ const preprocessors = { }); } - node.attributes.forEach( attribute => { + node.attributes.forEach( ( attribute: Node ) => { if ( attribute.type === 'Attribute' && attribute.value !== true ) { - attribute.value.forEach( chunk => { + attribute.value.forEach( ( chunk: Node ) => { if ( chunk.type !== 'Text' ) { const dependencies = block.findDependencies( chunk.expression ); block.addDependencies( dependencies ); @@ -238,12 +241,12 @@ const preprocessors = { } }; -function preprocessChildren ( generator, block, state, node, isTopLevel ) { +function preprocessChildren ( generator: DomGenerator, block: Block, state: State, node: Node, isTopLevel: boolean = false ) { // glue text nodes together - const cleaned = []; - let lastChild; + const cleaned: Node[] = []; + let lastChild: Node; - node.children.forEach( child => { + node.children.forEach( ( child: Node ) => { if ( child.type === 'Comment' ) return; if ( child.type === 'Text' && lastChild && lastChild.type === 'Text' ) { @@ -273,7 +276,7 @@ function preprocessChildren ( generator, block, state, node, isTopLevel ) { lastChild = null; - cleaned.forEach( child => { + cleaned.forEach( ( child: Node ) => { const preprocess = preprocessors[ child.type ]; if ( preprocess ) preprocess( generator, block, state, child ); @@ -292,7 +295,7 @@ function preprocessChildren ( generator, block, state, node, isTopLevel ) { node.children = cleaned; } -export default function preprocess ( generator, state, node ) { +export default function preprocess ( generator: DomGenerator, namespace: string, node: Node ) { const block = new Block({ generator, name: generator.alias( 'create_main_fragment' ), @@ -309,9 +312,15 @@ export default function preprocess ( generator, state, node ) { dependencies: new Set() }); + const state: State = { + namespace, + parentNode: null, + isTopLevel: true + }; + generator.blocks.push( block ); preprocessChildren( generator, block, state, node, true ); block.hasUpdateMethod = block.dependencies.size > 0; - return block; + return { block, state }; } \ No newline at end of file diff --git a/src/generators/dom/shared.ts b/src/generators/dom/shared.ts new file mode 100644 index 0000000000..906b6222ad --- /dev/null +++ b/src/generators/dom/shared.ts @@ -0,0 +1,35 @@ +// this file is auto-generated, do not edit it +export default { + "appendNode": "function appendNode ( node, target ) {\n\ttarget.appendChild( node );\n}", + "insertNode": "function insertNode ( node, target, anchor ) {\n\ttarget.insertBefore( node, anchor );\n}", + "detachNode": "function detachNode ( node ) {\n\tnode.parentNode.removeChild( node );\n}", + "detachBetween": "function detachBetween ( before, after ) {\n\twhile ( before.nextSibling && before.nextSibling !== after ) {\n\t\tbefore.parentNode.removeChild( before.nextSibling );\n\t}\n}", + "destroyEach": "function destroyEach ( iterations, detach, start ) {\n\tfor ( var i = start; i < iterations.length; i += 1 ) {\n\t\tif ( iterations[i] ) iterations[i].destroy( detach );\n\t}\n}", + "createElement": "function createElement ( name ) {\n\treturn document.createElement( name );\n}", + "createSvgElement": "function createSvgElement ( name ) {\n\treturn document.createElementNS( 'http://www.w3.org/2000/svg', name );\n}", + "createText": "function createText ( data ) {\n\treturn document.createTextNode( data );\n}", + "createComment": "function createComment () {\n\treturn document.createComment( '' );\n}", + "addEventListener": "function addEventListener ( node, event, handler ) {\n\tnode.addEventListener( event, handler, false );\n}", + "removeEventListener": "function removeEventListener ( node, event, handler ) {\n\tnode.removeEventListener( event, handler, false );\n}", + "setAttribute": "function setAttribute ( node, attribute, value ) {\n\tnode.setAttribute( attribute, value );\n}", + "setXlinkAttribute": "function setXlinkAttribute ( node, attribute, value ) {\n\tnode.setAttributeNS( 'http://www.w3.org/1999/xlink', attribute, value );\n}", + "getBindingGroupValue": "function getBindingGroupValue ( group ) {\n\tvar value = [];\n\tfor ( var i = 0; i < group.length; i += 1 ) {\n\t\tif ( group[i].checked ) value.push( group[i].__value );\n\t}\n\treturn value;\n}", + "differs": "function differs ( a, b ) {\n\treturn ( a !== b ) || ( a && ( typeof a === 'object' ) || ( typeof a === 'function' ) );\n}", + "dispatchObservers": "function dispatchObservers ( component, group, newState, oldState ) {\n\tfor ( var key in group ) {\n\t\tif ( !( key in newState ) ) continue;\n\n\t\tvar newValue = newState[ key ];\n\t\tvar oldValue = oldState[ key ];\n\n\t\tif ( differs( newValue, oldValue ) ) {\n\t\t\tvar callbacks = group[ key ];\n\t\t\tif ( !callbacks ) continue;\n\n\t\t\tfor ( var i = 0; i < callbacks.length; i += 1 ) {\n\t\t\t\tvar callback = callbacks[i];\n\t\t\t\tif ( callback.__calling ) continue;\n\n\t\t\t\tcallback.__calling = true;\n\t\t\t\tcallback.call( component, newValue, oldValue );\n\t\t\t\tcallback.__calling = false;\n\t\t\t}\n\t\t}\n\t}\n}", + "get": "function get ( key ) {\n\treturn key ? this._state[ key ] : this._state;\n}", + "fire": "function fire ( eventName, data ) {\n\tvar handlers = eventName in this._handlers && this._handlers[ eventName ].slice();\n\tif ( !handlers ) return;\n\n\tfor ( var i = 0; i < handlers.length; i += 1 ) {\n\t\thandlers[i].call( this, data );\n\t}\n}", + "observe": "function observe ( key, callback, options ) {\n\tvar group = ( options && options.defer ) ? this._observers.post : this._observers.pre;\n\n\t( group[ key ] || ( group[ key ] = [] ) ).push( callback );\n\n\tif ( !options || options.init !== false ) {\n\t\tcallback.__calling = true;\n\t\tcallback.call( this, this._state[ key ] );\n\t\tcallback.__calling = false;\n\t}\n\n\treturn {\n\t\tcancel: function () {\n\t\t\tvar index = group[ key ].indexOf( callback );\n\t\t\tif ( ~index ) group[ key ].splice( index, 1 );\n\t\t}\n\t};\n}", + "observeDev": "function observeDev ( key, callback, options ) {\n\tvar c = ( key = '' + key ).search( /[^\\w]/ );\n\tif ( c > -1 ) {\n\t\tvar message = \"The first argument to component.observe(...) must be the name of a top-level property\";\n\t\tif ( c > 0 ) message += \", i.e. '\" + key.slice( 0, c ) + \"' rather than '\" + key + \"'\";\n\n\t\tthrow new Error( message );\n\t}\n\n\treturn observe.call( this, key, callback, options );\n}", + "on": "function on ( eventName, handler ) {\n\tif ( eventName === 'teardown' ) return this.on( 'destroy', handler );\n\n\tvar handlers = this._handlers[ eventName ] || ( this._handlers[ eventName ] = [] );\n\thandlers.push( handler );\n\n\treturn {\n\t\tcancel: function () {\n\t\t\tvar index = handlers.indexOf( handler );\n\t\t\tif ( ~index ) handlers.splice( index, 1 );\n\t\t}\n\t};\n}", + "onDev": "function onDev ( eventName, handler ) {\n\tif ( eventName === 'teardown' ) {\n\t\tconsole.warn( \"Use component.on('destroy', ...) instead of component.on('teardown', ...) which has been deprecated and will be unsupported in Svelte 2\" );\n\t\treturn this.on( 'destroy', handler );\n\t}\n\n\treturn on.call( this, eventName, handler );\n}", + "set": "function set ( newState ) {\n\tthis._set( assign( {}, newState ) );\n\tthis._root._flush();\n}", + "_flush": "function _flush () {\n\tif ( !this._renderHooks ) return;\n\n\twhile ( this._renderHooks.length ) {\n\t\tthis._renderHooks.pop()();\n\t}\n}", + "proto": "{\n\tget: get,\n\tfire: fire,\n\tobserve: observe,\n\ton: on,\n\tset: set,\n\t_flush: _flush\n}", + "protoDev": "{\n\tget: get,\n\tfire: fire,\n\tobserve: observeDev,\n\ton: onDev,\n\tset: set,\n\t_flush: _flush\n}", + "linear": "function linear ( t ) {\n\treturn t;\n}", + "generateKeyframes": "function generateKeyframes ( a, b, delta, duration, ease, fn, node, style ) {\n\tvar id = '__svelte' + ~~( Math.random() * 1e9 ); // TODO make this more robust\n\tvar keyframes = '@keyframes ' + id + '{\\n';\n\n\tfor ( var p = 0; p <= 1; p += 16.666 / duration ) {\n\t\tvar t = a + delta * ease( p );\n\t\tkeyframes += ( p * 100 ) + '%{' + fn( t ) + '}\\n';\n\t}\n\n\tkeyframes += '100% {' + fn( b ) + '}\\n}';\n\tstyle.textContent += keyframes;\n\n\tdocument.head.appendChild( style );\n\n\tnode.style.animation = ( node.style.animation || '' ).split( ',' )\n\t\t.filter( function ( anim ) {\n\t\t\t// when introing, discard old animations if there are any\n\t\t\treturn anim && ( delta < 0 || !/__svelte/.test( anim ) );\n\t\t})\n\t\t.concat( id + ' ' + duration + 'ms linear 1 forwards' )\n\t\t.join( ', ' );\n}", + "wrapTransition": "function wrapTransition ( node, fn, params, intro, outgroup ) {\n\tvar obj = fn( node, params );\n\tvar duration = obj.duration || 300;\n\tvar ease = obj.easing || linear;\n\n\t// TODO share