From 27f7df4db83a35401603b85c4fe35b9ea7b342c0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Sep 2018 22:13:15 -0400 Subject: [PATCH 01/14] move files around a bit --- src/compile/dom/Block.ts | 1 - src/compile/dom/index.ts | 9 +-- src/compile/index.ts | 69 +++++++++++++++++ src/index.ts | 158 +++------------------------------------ src/interfaces.ts | 13 +--- src/parse/index.ts | 8 +- src/preprocess/index.ts | 100 +++++++++++++++++++++++++ test/preprocess/index.js | 2 +- 8 files changed, 186 insertions(+), 174 deletions(-) create mode 100644 src/compile/index.ts create mode 100644 src/preprocess/index.ts diff --git a/src/compile/dom/Block.ts b/src/compile/dom/Block.ts index ca3984b5d729..5024b636a266 100644 --- a/src/compile/dom/Block.ts +++ b/src/compile/dom/Block.ts @@ -2,7 +2,6 @@ import CodeBuilder from '../../utils/CodeBuilder'; import deindent from '../../utils/deindent'; import { escape } from '../../utils/stringify'; import Compiler from '../Compiler'; -import { Node } from '../../interfaces'; export interface BlockOptions { parent?: Block; diff --git a/src/compile/dom/index.ts b/src/compile/dom/index.ts index 3ced0254a24a..d3e98e38fb69 100644 --- a/src/compile/dom/index.ts +++ b/src/compile/dom/index.ts @@ -1,19 +1,12 @@ -import MagicString from 'magic-string'; -import isReference from 'is-reference'; -import { parseExpressionAt } from 'acorn'; -import annotateWithScopes from '../../utils/annotateWithScopes'; -import { walk } from 'estree-walker'; import deindent from '../../utils/deindent'; import { stringify, escape } from '../../utils/stringify'; import CodeBuilder from '../../utils/CodeBuilder'; import globalWhitelist from '../../utils/globalWhitelist'; -import reservedNames from '../../utils/reservedNames'; import Compiler from '../Compiler'; import Stylesheet from '../../css/Stylesheet'; import Stats from '../../Stats'; import Block from './Block'; -import { test } from '../../config'; -import { Ast, CompileOptions, Node } from '../../interfaces'; +import { Ast, CompileOptions } from '../../interfaces'; export class DomTarget { blocks: (Block|string)[]; diff --git a/src/compile/index.ts b/src/compile/index.ts new file mode 100644 index 000000000000..cfb1b9e832d5 --- /dev/null +++ b/src/compile/index.ts @@ -0,0 +1,69 @@ +import { assign } from '../shared'; +import Stats from '../Stats'; +import parse from '../parse/index'; +import Stylesheet from '../css/Stylesheet'; +import validate from '../validate'; +import generate from './dom/index'; +import generateSSR from './ssr/index'; +import { CompileOptions, Warning, Ast } from '../interfaces'; + +function normalize_options(options: CompileOptions): CompileOptions { + let normalized = assign({ generate: 'dom' }, options); + const { onwarn, onerror } = normalized; + + normalized.onwarn = onwarn + ? (warning: Warning) => onwarn(warning, default_onwarn) + : default_onwarn; + + normalized.onerror = onerror + ? (error: Error) => onerror(error, default_onerror) + : default_onerror; + + return normalized; +} + +function default_onwarn({ start, message }: Warning) { + if (start) { + console.warn(`(${start.line}:${start.column}) – ${message}`); + } else { + console.warn(message); + } +} + +function default_onerror(error: Error) { + throw error; +} + +export default function compile(source: string, _options: CompileOptions) { + const options = normalize_options(_options); + let ast: Ast; + + const stats = new Stats({ + onwarn: options.onwarn + }); + + try { + stats.start('parse'); + ast = parse(source, options); + stats.stop('parse'); + } catch (err) { + options.onerror(err); + return; + } + + stats.start('stylesheet'); + const stylesheet = new Stylesheet(source, ast, options.filename, options.dev); + stats.stop('stylesheet'); + + stats.start('validate'); + validate(ast, source, stylesheet, stats, options); + stats.stop('validate'); + + if (options.generate === false) { + return { ast, stats: stats.render(null), js: null, css: null }; + } + + const compiler = options.generate === 'ssr' ? generateSSR : generate; + + return compiler(ast, source, stylesheet, options, stats); +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2895dd297799..6c1949e472db 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,149 +1,10 @@ -import parse from './parse/index'; -import validate from './validate/index'; -import generate from './compile/dom/index'; -import generateSSR from './compile/ssr/index'; -import Stats from './Stats'; -import { assign } from './shared/index.js'; -import Stylesheet from './css/Stylesheet'; -import { Ast, CompileOptions, Warning, PreprocessOptions, Preprocessor } from './interfaces'; -import { SourceMap } from 'magic-string'; +import compile from './compile/index'; +import { CompileOptions } from './interfaces'; -const version = '__VERSION__'; +export function create(source: string, options: CompileOptions = {}) { + options.format = 'eval'; -function normalizeOptions(options: CompileOptions): CompileOptions { - let normalizedOptions = assign({ generate: 'dom' }, options); - const { onwarn, onerror } = normalizedOptions; - normalizedOptions.onwarn = onwarn - ? (warning: Warning) => onwarn(warning, defaultOnwarn) - : defaultOnwarn; - normalizedOptions.onerror = onerror - ? (error: Error) => onerror(error, defaultOnerror) - : defaultOnerror; - return normalizedOptions; -} - -function defaultOnwarn(warning: Warning) { - if (warning.start) { - console.warn( - `(${warning.start.line}:${warning.start.column}) – ${warning.message}` - ); // eslint-disable-line no-console - } else { - console.warn(warning.message); // eslint-disable-line no-console - } -} - -function defaultOnerror(error: Error) { - throw error; -} - -function parseAttributeValue(value: string) { - return /^['"]/.test(value) ? - value.slice(1, -1) : - value; -} - -function parseAttributes(str: string) { - const attrs = {}; - str.split(/\s+/).filter(Boolean).forEach(attr => { - const [name, value] = attr.split('='); - attrs[name] = value ? parseAttributeValue(value) : true; - }); - return attrs; -} - -async function replaceTagContents(source, type: 'script' | 'style', preprocessor: Preprocessor, options: PreprocessOptions) { - const exp = new RegExp(`<${type}([\\S\\s]*?)>([\\S\\s]*?)<\\/${type}>`, 'ig'); - const match = exp.exec(source); - - if (match) { - const attributes: Record = parseAttributes(match[1]); - const content: string = match[2]; - const processed: { code: string, map?: SourceMap | string } = await preprocessor({ - content, - attributes, - filename : options.filename - }); - - if (processed && processed.code) { - return ( - source.slice(0, match.index) + - `<${type}>${processed.code}` + - source.slice(match.index + match[0].length) - ); - } - } - - return source; -} - -export async function preprocess(source: string, options: PreprocessOptions) { - const { markup, style, script } = options; - if (!!markup) { - const processed: { code: string, map?: SourceMap | string } = await markup({ - content: source, - filename: options.filename - }); - source = processed.code; - } - - if (!!style) { - source = await replaceTagContents(source, 'style', style, options); - } - - if (!!script) { - source = await replaceTagContents(source, 'script', script, options); - } - - return { - // TODO return separated output, in future version where svelte.compile supports it: - // style: { code: styleCode, map: styleMap }, - // script { code: scriptCode, map: scriptMap }, - // markup { code: markupCode, map: markupMap }, - - toString() { - return source; - } - }; -} - -function compile(source: string, _options: CompileOptions) { - const options = normalizeOptions(_options); - let ast: Ast; - - const stats = new Stats({ - onwarn: options.onwarn - }); - - try { - stats.start('parse'); - ast = parse(source, options); - stats.stop('parse'); - } catch (err) { - options.onerror(err); - return; - } - - stats.start('stylesheet'); - const stylesheet = new Stylesheet(source, ast, options.filename, options.dev); - stats.stop('stylesheet'); - - stats.start('validate'); - validate(ast, source, stylesheet, stats, options); - stats.stop('validate'); - - if (options.generate === false) { - return { ast, stats: stats.render(null), js: null, css: null }; - } - - const compiler = options.generate === 'ssr' ? generateSSR : generate; - - return compiler(ast, source, stylesheet, options, stats); -}; - -function create(source: string, _options: CompileOptions = {}) { - _options.format = 'eval'; - - const compiled = compile(source, _options); + const compiled = compile(source, options); if (!compiled || !compiled.js.code) { return; @@ -152,8 +13,8 @@ function create(source: string, _options: CompileOptions = {}) { try { return (new Function(`return ${compiled.js.code}`))(); } catch (err) { - if (_options.onerror) { - _options.onerror(err); + if (options.onerror) { + options.onerror(err); return; } else { throw err; @@ -161,4 +22,7 @@ function create(source: string, _options: CompileOptions = {}) { } } -export { parse, create, compile, version as VERSION }; +export { default as compile } from './compile/index'; +export { default as parse } from './parse/index'; +export { default as preprocess } from './preprocess/index'; +export const VERSION = '__VERSION__'; \ No newline at end of file diff --git a/src/interfaces.ts b/src/interfaces.ts index a30a67a91f44..bb7b7e2fb279 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,5 +1,3 @@ -import {SourceMap} from 'magic-string'; - export interface Node { start: number; end: number; @@ -67,7 +65,7 @@ export interface CompileOptions { // to remove in v3 skipIntroByDefault?: boolean; - nestedTransitions: boolean; + nestedTransitions?: boolean; } export interface GenerateOptions { @@ -92,15 +90,6 @@ export interface CustomElementOptions { props?: string[]; } -export interface PreprocessOptions { - markup?: (options: {content: string, filename: string}) => { code: string, map?: SourceMap | string }; - style?: Preprocessor; - script?: Preprocessor; - filename?: string -} - -export type Preprocessor = (options: {content: string, attributes: Record, filename?: string}) => { code: string, map?: SourceMap | string }; - export interface AppendTarget { slots: Record; slotStack: string[] diff --git a/src/parse/index.ts b/src/parse/index.ts index 6fb40193d6a9..f81a341273b0 100644 --- a/src/parse/index.ts +++ b/src/parse/index.ts @@ -1,17 +1,15 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn'; -import { locate, Location } from 'locate-character'; import fragment from './state/fragment'; import { whitespace } from '../utils/patterns'; -import { trimStart, trimEnd } from '../utils/trim'; import reservedNames from '../utils/reservedNames'; import fullCharCodeAt from '../utils/fullCharCodeAt'; -import { Node, Ast } from '../interfaces'; +import { Node, Ast, CustomElementOptions } from '../interfaces'; import error from '../utils/error'; interface ParserOptions { filename?: string; bind?: boolean; - customElement?: boolean; + customElement?: CustomElementOptions | true; } type ParserState = (parser: Parser) => (ParserState | void); @@ -19,7 +17,7 @@ type ParserState = (parser: Parser) => (ParserState | void); export class Parser { readonly template: string; readonly filename?: string; - readonly customElement: boolean; + readonly customElement: CustomElementOptions | true; index: number; stack: Array; diff --git a/src/preprocess/index.ts b/src/preprocess/index.ts new file mode 100644 index 000000000000..047b124991bc --- /dev/null +++ b/src/preprocess/index.ts @@ -0,0 +1,100 @@ +import { SourceMap } from 'magic-string'; + +export interface PreprocessOptions { + markup?: (options: { + content: string, + filename: string + }) => { code: string, map?: SourceMap | string }; + style?: Preprocessor; + script?: Preprocessor; + filename?: string +} + +export type Preprocessor = (options: { + content: string, + attributes: Record, + filename?: string +}) => { code: string, map?: SourceMap | string }; + +function parseAttributeValue(value: string) { + return /^['"]/.test(value) ? + value.slice(1, -1) : + value; +} + +function parseAttributes(str: string) { + const attrs = {}; + str.split(/\s+/).filter(Boolean).forEach(attr => { + const [name, value] = attr.split('='); + attrs[name] = value ? parseAttributeValue(value) : true; + }); + return attrs; +} + +async function replaceTagContents( + source, + type: 'script' | 'style', + preprocessor: Preprocessor, + options: PreprocessOptions +) { + const exp = new RegExp(`<${type}([\\S\\s]*?)>([\\S\\s]*?)<\\/${type}>`, 'ig'); + const match = exp.exec(source); + + if (match) { + const attributes: Record = parseAttributes(match[1]); + const content: string = match[2]; + const processed: { code: string, map?: SourceMap | string } = await preprocessor({ + content, + attributes, + filename : options.filename + }); + + if (processed && processed.code) { + return ( + source.slice(0, match.index) + + `<${type}>${processed.code}` + + source.slice(match.index + match[0].length) + ); + } + } + + return source; +} + +export default async function preprocess( + source: string, + options: PreprocessOptions +) { + const { markup, style, script } = options; + + if (!!markup) { + const processed: { + code: string, + map?: SourceMap | string + } = await markup({ + content: source, + filename: options.filename + }); + + source = processed.code; + } + + if (!!style) { + source = await replaceTagContents(source, 'style', style, options); + } + + if (!!script) { + source = await replaceTagContents(source, 'script', script, options); + } + + return { + // TODO return separated output, in future version where svelte.compile supports it: + // style: { code: styleCode, map: styleMap }, + // script { code: scriptCode, map: scriptMap }, + // markup { code: markupCode, map: markupMap }, + + toString() { + return source; + } + }; +} \ No newline at end of file diff --git a/test/preprocess/index.js b/test/preprocess/index.js index 6ed452f672a4..044f6965e69e 100644 --- a/test/preprocess/index.js +++ b/test/preprocess/index.js @@ -1,5 +1,5 @@ import assert from 'assert'; -import {svelte} from '../helpers.js'; +import { svelte } from '../helpers.js'; describe('preprocess', () => { it('preprocesses entire component', () => { From 8f854b4b49dde4f6f189870fc18b9a754bcd8715 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Sep 2018 22:34:58 -0400 Subject: [PATCH 02/14] rename Component to InlineComponent --- src/compile/nodes/Binding.ts | 2 +- src/compile/nodes/Element.ts | 8 ++++---- src/compile/nodes/{Component.ts => InlineComponent.ts} | 4 ++-- src/compile/nodes/Text.ts | 4 ++-- src/compile/nodes/shared/mapChildren.ts | 4 ++-- src/parse/state/tag.ts | 4 ++-- src/validate/html/index.ts | 2 +- src/validate/html/validateElement.ts | 6 +++--- test/parser/samples/binding-shorthand/output.json | 2 +- test/parser/samples/component-dynamic/output.json | 2 +- test/parser/samples/self-reference/output.json | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) rename src/compile/nodes/{Component.ts => InlineComponent.ts} (99%) diff --git a/src/compile/nodes/Binding.ts b/src/compile/nodes/Binding.ts index 168c3b44b578..45db895f7ed1 100644 --- a/src/compile/nodes/Binding.ts +++ b/src/compile/nodes/Binding.ts @@ -16,7 +16,7 @@ const readOnlyMediaAttributes = new Set([ ]); // TODO a lot of this element-specific stuff should live in Element — -// Binding should ideally be agnostic between Element and Component +// Binding should ideally be agnostic between Element and InlineComponent export default class Binding extends Node { name: string; diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index a3040b81c241..d693fc04d75d 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -284,11 +284,11 @@ export default class Element extends Node { } const slot = this.getStaticAttributeValue('slot'); - if (slot && this.hasAncestor('Component')) { + if (slot && this.hasAncestor('InlineComponent')) { this.cannotUseInnerHTML(); this.slotted = true; // TODO validate slots — no nesting, no dynamic names... - const component = this.findNearest(/^Component/); + const component = this.findNearest(/^InlineComponent/); component._slots.add(slot); } @@ -318,7 +318,7 @@ export default class Element extends Node { const slot = this.attributes.find((attribute: Node) => attribute.name === 'slot'); const prop = slot && quotePropIfNecessary(slot.chunks[0].data); const initialMountNode = this.slotted ? - `${this.findNearest(/^Component/).var}._slotted${prop}` : // TODO this looks bonkers + `${this.findNearest(/^InlineComponent/).var}._slotted${prop}` : // TODO this looks bonkers parentNode; block.addVariable(node); @@ -977,7 +977,7 @@ export default class Element extends Node { let textareaContents; // awkward special case const slot = this.getStaticAttributeValue('slot'); - if (slot && this.hasAncestor('Component')) { + if (slot && this.hasAncestor('InlineComponent')) { const slot = this.attributes.find((attribute: Node) => attribute.name === 'slot'); const slotName = slot.chunks[0].data; const appendTarget = compiler.target.appendTargets[compiler.target.appendTargets.length - 1]; diff --git a/src/compile/nodes/Component.ts b/src/compile/nodes/InlineComponent.ts similarity index 99% rename from src/compile/nodes/Component.ts rename to src/compile/nodes/InlineComponent.ts index 526af029c8f2..dc5e87fd1076 100644 --- a/src/compile/nodes/Component.ts +++ b/src/compile/nodes/InlineComponent.ts @@ -15,8 +15,8 @@ import Expression from './shared/Expression'; import { AppendTarget } from '../../interfaces'; import addToSet from '../../utils/addToSet'; -export default class Component extends Node { - type: 'Component'; +export default class InlineComponent extends Node { + type: 'InlineComponent'; name: string; expression: Expression; attributes: Attribute[]; diff --git a/src/compile/nodes/Text.ts b/src/compile/nodes/Text.ts index bba5b2848b0c..ab502bf6404d 100644 --- a/src/compile/nodes/Text.ts +++ b/src/compile/nodes/Text.ts @@ -17,11 +17,11 @@ const elementsWithoutText = new Set([ function shouldSkip(node: Text) { if (/\S/.test(node.data)) return false; - const parentElement = node.findNearest(/(?:Element|Component|Head)/); + const parentElement = node.findNearest(/(?:Element|InlineComponent|Head)/); if (!parentElement) return false; if (parentElement.type === 'Head') return true; - if (parentElement.type === 'Component') return parentElement.children.length === 1 && node === parentElement.children[0]; + if (parentElement.type === 'InlineComponent') return parentElement.children.length === 1 && node === parentElement.children[0]; return parentElement.namespace || elementsWithoutText.has(parentElement.name); } diff --git a/src/compile/nodes/shared/mapChildren.ts b/src/compile/nodes/shared/mapChildren.ts index 9cd238644c8d..ee36d31626b7 100644 --- a/src/compile/nodes/shared/mapChildren.ts +++ b/src/compile/nodes/shared/mapChildren.ts @@ -1,10 +1,10 @@ import AwaitBlock from '../AwaitBlock'; import Comment from '../Comment'; -import Component from '../Component'; import EachBlock from '../EachBlock'; import Element from '../Element'; import Head from '../Head'; import IfBlock from '../IfBlock'; +import InlineComponent from '../InlineComponent'; import MustacheTag from '../MustacheTag'; import RawMustacheTag from '../RawMustacheTag'; import DebugTag from '../DebugTag'; @@ -18,11 +18,11 @@ function getConstructor(type): typeof Node { switch (type) { case 'AwaitBlock': return AwaitBlock; case 'Comment': return Comment; - case 'Component': return Component; case 'EachBlock': return EachBlock; case 'Element': return Element; case 'Head': return Head; case 'IfBlock': return IfBlock; + case 'InlineComponent': return InlineComponent; case 'MustacheTag': return MustacheTag; case 'RawMustacheTag': return RawMustacheTag; case 'DebugTag': return DebugTag; diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 4a0d05014442..bc112d4bbcda 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -65,7 +65,7 @@ function parentIsHead(stack) { while (i--) { const { type } = stack[i]; if (type === 'Head') return true; - if (type === 'Element' || type === 'Component') return false; + if (type === 'Element' || type === 'InlineComponent') return false; } return false; } @@ -123,7 +123,7 @@ export default function tag(parser: Parser) { const type = metaTags.has(name) ? metaTags.get(name) - : (/[A-Z]/.test(name[0]) || name === 'svelte:self' || name === 'svelte:component') ? 'Component' + : (/[A-Z]/.test(name[0]) || name === 'svelte:self' || name === 'svelte:component') ? 'InlineComponent' : name === 'title' && parentIsHead(parser.stack) ? 'Title' : name === 'slot' && !parser.customElement ? 'Slot' : 'Element'; diff --git a/src/validate/html/index.ts b/src/validate/html/index.ts index eabe9d88724f..056b920cad6a 100644 --- a/src/validate/html/index.ts +++ b/src/validate/html/index.ts @@ -36,7 +36,7 @@ export default function validateHtml(validator: Validator, html: Node) { validateSlot(validator, node); } - else if (node.type === 'Component' || node.name === 'svelte:self' || node.name === 'svelte:component') { + else if (node.type === 'InlineComponent' || node.name === 'svelte:self' || node.name === 'svelte:component') { validateComponent( validator, node, diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts index 3d2d96f380b5..c01109f2f240 100644 --- a/src/validate/html/validateElement.ts +++ b/src/validate/html/validateElement.ts @@ -85,11 +85,11 @@ export default function validateElement( if (attribute.type === 'Ref') { if (!isValidIdentifier(attribute.name)) { const suggestion = attribute.name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&'); - + validator.error(attribute, { code: `invalid-reference-name`, message: `Reference name '${attribute.name}' is invalid — must be a valid identifier such as ${suggestion}` - }); + }); } else { if (!refs.has(attribute.name)) refs.set(attribute.name, []); refs.get(attribute.name).push(node); @@ -350,7 +350,7 @@ function checkSlotAttribute(validator: Validator, node: Node, attribute: Node, s while (i--) { const parent = stack[i]; - if (parent.type === 'Component') { + if (parent.type === 'InlineComponent') { // if we're inside a component or a custom element, gravy if (parent.name === 'svelte:self' || parent.name === 'svelte:component' || validator.components.has(parent.name)) return; } else if (parent.type === 'Element') { diff --git a/test/parser/samples/binding-shorthand/output.json b/test/parser/samples/binding-shorthand/output.json index 4c92fb9e20a3..b0465e0a3e64 100644 --- a/test/parser/samples/binding-shorthand/output.json +++ b/test/parser/samples/binding-shorthand/output.json @@ -8,7 +8,7 @@ { "start": 0, "end": 18, - "type": "Component", + "type": "InlineComponent", "name": "Widget", "attributes": [ { diff --git a/test/parser/samples/component-dynamic/output.json b/test/parser/samples/component-dynamic/output.json index 67e8f1e4ca7a..6c3fa442ced0 100644 --- a/test/parser/samples/component-dynamic/output.json +++ b/test/parser/samples/component-dynamic/output.json @@ -8,7 +8,7 @@ { "start": 0, "end": 62, - "type": "Component", + "type": "InlineComponent", "name": "svelte:component", "attributes": [], "children": [], diff --git a/test/parser/samples/self-reference/output.json b/test/parser/samples/self-reference/output.json index c7e29c6f592b..370f5f7bed40 100644 --- a/test/parser/samples/self-reference/output.json +++ b/test/parser/samples/self-reference/output.json @@ -32,7 +32,7 @@ { "start": 17, "end": 51, - "type": "Component", + "type": "InlineComponent", "name": "svelte:self", "attributes": [ { From d08051b35ca1a7529f7f498eb3bb89762b242dac Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Sep 2018 23:02:56 -0400 Subject: [PATCH 03/14] rename Compiler to Component --- src/Stats.ts | 16 ++--- src/compile/{Compiler.ts => Component.ts} | 40 ++++++----- src/compile/dom/Block.ts | 22 +++--- src/compile/dom/index.ts | 78 ++++++++++---------- src/compile/nodes/Action.ts | 6 +- src/compile/nodes/Animation.ts | 6 +- src/compile/nodes/Attribute.ts | 16 ++--- src/compile/nodes/AwaitBlock.ts | 24 +++---- src/compile/nodes/Binding.ts | 34 ++++----- src/compile/nodes/CatchBlock.ts | 6 +- src/compile/nodes/Class.ts | 6 +- src/compile/nodes/Comment.ts | 8 +-- src/compile/nodes/DebugTag.ts | 20 +++--- src/compile/nodes/EachBlock.ts | 56 +++++++-------- src/compile/nodes/Element.ts | 88 +++++++++++------------ src/compile/nodes/ElseBlock.ts | 6 +- src/compile/nodes/EventHandler.ts | 24 +++---- src/compile/nodes/Fragment.ts | 12 ++-- src/compile/nodes/Head.ts | 10 +-- src/compile/nodes/IfBlock.ts | 42 +++++------ src/compile/nodes/InlineComponent.ts | 46 ++++++------ src/compile/nodes/MustacheTag.ts | 2 +- src/compile/nodes/PendingBlock.ts | 6 +- src/compile/nodes/RawMustacheTag.ts | 2 +- src/compile/nodes/Slot.ts | 8 +-- src/compile/nodes/Text.ts | 6 +- src/compile/nodes/ThenBlock.ts | 6 +- src/compile/nodes/Title.ts | 10 +-- src/compile/nodes/Transition.ts | 6 +- src/compile/nodes/Window.ts | 30 ++++---- src/compile/nodes/shared/Expression.ts | 20 +++--- src/compile/nodes/shared/Node.ts | 12 ++-- src/compile/nodes/shared/Tag.ts | 6 +- src/compile/nodes/shared/mapChildren.ts | 4 +- src/compile/ssr/index.ts | 18 ++--- src/utils/createDebuggingComment.ts | 9 ++- 36 files changed, 359 insertions(+), 352 deletions(-) rename src/compile/{Compiler.ts => Component.ts} (95%) diff --git a/src/Stats.ts b/src/Stats.ts index 613064f987ad..4c8d2817c66f 100644 --- a/src/Stats.ts +++ b/src/Stats.ts @@ -1,5 +1,5 @@ import { Node, Warning } from './interfaces'; -import Compiler from './compile/Compiler'; +import Component from './compile/Component'; const now = (typeof process !== 'undefined' && process.hrtime) ? () => { @@ -73,14 +73,14 @@ export default class Stats { this.currentChildren = this.currentTiming ? this.currentTiming.children : this.timings; } - render(compiler: Compiler) { + render(component: Component) { const timings = Object.assign({ total: now() - this.startTime }, collapseTimings(this.timings)); // TODO would be good to have this info even // if options.generate is false - const imports = compiler && compiler.imports.map(node => { + const imports = component && component.imports.map(node => { return { source: node.source.value, specifiers: node.specifiers.map(specifier => { @@ -96,11 +96,11 @@ export default class Stats { } }); - const hooks: Record = compiler && { - oncreate: !!compiler.templateProperties.oncreate, - ondestroy: !!compiler.templateProperties.ondestroy, - onstate: !!compiler.templateProperties.onstate, - onupdate: !!compiler.templateProperties.onupdate + const hooks: Record = component && { + oncreate: !!component.templateProperties.oncreate, + ondestroy: !!component.templateProperties.ondestroy, + onstate: !!component.templateProperties.onstate, + onupdate: !!component.templateProperties.onupdate }; return { diff --git a/src/compile/Compiler.ts b/src/compile/Component.ts similarity index 95% rename from src/compile/Compiler.ts rename to src/compile/Component.ts index 690b837d7901..db43ce2f9159 100644 --- a/src/compile/Compiler.ts +++ b/src/compile/Component.ts @@ -6,20 +6,19 @@ import { getLocator } from 'locate-character'; import Stats from '../Stats'; import deindent from '../utils/deindent'; import CodeBuilder from '../utils/CodeBuilder'; -import flattenReference from '../utils/flattenReference'; import reservedNames from '../utils/reservedNames'; import namespaces from '../utils/namespaces'; -import { removeNode, removeObjectKey } from '../utils/removeNode'; +import { removeNode } from '../utils/removeNode'; import nodeToString from '../utils/nodeToString'; import wrapModule from './wrapModule'; -import annotateWithScopes, { Scope } from '../utils/annotateWithScopes'; +import annotateWithScopes from '../utils/annotateWithScopes'; import getName from '../utils/getName'; import Stylesheet from '../css/Stylesheet'; import { test } from '../config'; import Fragment from './nodes/Fragment'; import shared from './shared'; -import { DomTarget } from './dom/index'; -import { SsrTarget } from './ssr/index'; +import { DomTarget } from './dom'; +import { SsrTarget } from './ssr'; import { Node, GenerateOptions, ShorthandImport, Ast, CompileOptions, CustomElementOptions } from '../interfaces'; interface Computation { @@ -79,7 +78,7 @@ function removeIndentation( childKeys.EachBlock = childKeys.IfBlock = ['children', 'else']; childKeys.Attribute = ['value']; -export default class Compiler { +export default class Component { stats: Stats; ast: Ast; @@ -136,7 +135,6 @@ export default class Compiler { stylesheet: Stylesheet, options: CompileOptions, stats: Stats, - dom: boolean, target: DomTarget | SsrTarget ) { stats.start('compile'); @@ -189,7 +187,7 @@ export default class Compiler { this.computations = []; this.templateProperties = {}; - this.walkJs(dom); + this.walkJs(); this.name = this.alias(name); if (options.customElement === true) { @@ -266,7 +264,7 @@ export default class Compiler { } else { let inlineHelpers = ''; - const compiler = this; + const component = this; importedHelpers = []; @@ -291,7 +289,7 @@ export default class Compiler { const dependency = node.name; helpers.add(dependency); - const alias = compiler.alias(dependency); + const alias = component.alias(dependency); if (alias !== node.name) { code.overwrite(node.start, node.end, alias); } @@ -432,7 +430,7 @@ export default class Compiler { }; } - walkJs(dom: boolean) { + walkJs() { const { code, source, @@ -532,7 +530,13 @@ export default class Compiler { `); }; - const addDeclaration = (key: string, node: Node, allowShorthandImport?: boolean, disambiguator?: string, conflicts?: Record) => { + const addDeclaration = ( + key: string, + node: Node, + allowShorthandImport?: boolean, + disambiguator?: string, + conflicts?: Record + ) => { const qualified = disambiguator ? `${disambiguator}-${key}` : key; if (node.type === 'Identifier' && node.name === key) { @@ -634,7 +638,7 @@ export default class Compiler { addDeclaration('data', templateProperties.data.value); } - if (templateProperties.events && dom) { + if (templateProperties.events) { templateProperties.events.value.properties.forEach((property: Node) => { addDeclaration(getName(property.key), property.value, false, 'events'); }); @@ -646,7 +650,7 @@ export default class Compiler { }); } - if (templateProperties.methods && dom) { + if (templateProperties.methods) { addDeclaration('methods', templateProperties.methods.value); templateProperties.methods.value.properties.forEach(prop => { @@ -659,19 +663,19 @@ export default class Compiler { this.namespace = namespaces[ns] || ns; } - if (templateProperties.oncreate && dom) { + if (templateProperties.oncreate) { addDeclaration('oncreate', templateProperties.oncreate.value); } - if (templateProperties.ondestroy && dom) { + if (templateProperties.ondestroy) { addDeclaration('ondestroy', templateProperties.ondestroy.value); } - if (templateProperties.onstate && dom) { + if (templateProperties.onstate) { addDeclaration('onstate', templateProperties.onstate.value); } - if (templateProperties.onupdate && dom) { + if (templateProperties.onupdate) { addDeclaration('onupdate', templateProperties.onupdate.value); } diff --git a/src/compile/dom/Block.ts b/src/compile/dom/Block.ts index 5024b636a266..3de06ec75990 100644 --- a/src/compile/dom/Block.ts +++ b/src/compile/dom/Block.ts @@ -1,12 +1,12 @@ import CodeBuilder from '../../utils/CodeBuilder'; import deindent from '../../utils/deindent'; import { escape } from '../../utils/stringify'; -import Compiler from '../Compiler'; +import Component from '../Component'; export interface BlockOptions { parent?: Block; name: string; - compiler?: Compiler; + component?: Component; comment?: string; key?: string; bindings?: Map; @@ -15,7 +15,7 @@ export interface BlockOptions { export default class Block { parent?: Block; - compiler: Compiler; + component: Component; name: string; comment?: string; @@ -58,7 +58,7 @@ export default class Block { constructor(options: BlockOptions) { this.parent = options.parent; - this.compiler = options.compiler; + this.component = options.component; this.name = options.name; this.comment = options.comment; @@ -90,7 +90,7 @@ export default class Block { this.hasOutroMethod = false; this.outros = 0; - this.getUniqueName = this.compiler.getUniqueNameMaker(); + this.getUniqueName = this.component.getUniqueNameMaker(); this.variables = new Map(); this.aliases = new Map() @@ -128,11 +128,11 @@ export default class Block { } addIntro() { - this.hasIntros = this.hasIntroMethod = this.compiler.target.hasIntroTransitions = true; + this.hasIntros = this.hasIntroMethod = this.component.target.hasIntroTransitions = true; } addOutro() { - this.hasOutros = this.hasOutroMethod = this.compiler.target.hasOutroTransitions = true; + this.hasOutros = this.hasOutroMethod = this.component.target.hasOutroTransitions = true; this.outros += 1; } @@ -167,7 +167,7 @@ export default class Block { } toString() { - const { dev } = this.compiler.options; + const { dev } = this.component.options; if (this.hasIntroMethod || this.hasOutroMethod) { this.addVariable('#current'); @@ -202,7 +202,7 @@ export default class Block { properties.addBlock(`c: @noop,`); } else { const hydrate = !this.builders.hydrate.isEmpty() && ( - this.compiler.options.hydratable + this.component.options.hydratable ? `this.h()` : this.builders.hydrate ); @@ -215,7 +215,7 @@ export default class Block { `); } - if (this.compiler.options.hydratable) { + if (this.component.options.hydratable) { if (this.builders.claim.isEmpty() && this.builders.hydrate.isEmpty()) { properties.addBlock(`l: @noop,`); } else { @@ -228,7 +228,7 @@ export default class Block { } } - if (this.compiler.options.hydratable && !this.builders.hydrate.isEmpty()) { + if (this.component.options.hydratable && !this.builders.hydrate.isEmpty()) { properties.addBlock(deindent` ${dev ? 'h: function hydrate' : 'h'}() { ${this.builders.hydrate} diff --git a/src/compile/dom/index.ts b/src/compile/dom/index.ts index d3e98e38fb69..b51c05b2cc4e 100644 --- a/src/compile/dom/index.ts +++ b/src/compile/dom/index.ts @@ -2,7 +2,7 @@ import deindent from '../../utils/deindent'; import { stringify, escape } from '../../utils/stringify'; import CodeBuilder from '../../utils/CodeBuilder'; import globalWhitelist from '../../utils/globalWhitelist'; -import Compiler from '../Compiler'; +import Component from '../Component'; import Stylesheet from '../../css/Stylesheet'; import Stats from '../../Stats'; import Block from './Block'; @@ -36,19 +36,19 @@ export default function dom( const format = options.format || 'es'; const target = new DomTarget(); - const compiler = new Compiler(ast, source, options.name || 'SvelteComponent', stylesheet, options, stats, true, target); + const component = new Component(ast, source, options.name || 'SvelteComponent', stylesheet, options, stats, target); const { computations, name, templateProperties, namespace, - } = compiler; + } = component; - compiler.fragment.build(); - const { block } = compiler.fragment; + component.fragment.build(); + const { block } = component.fragment; - if (compiler.options.nestedTransitions) { + if (component.options.nestedTransitions) { block.hasOutroMethod = true; } @@ -89,24 +89,24 @@ export default function dom( }); } - if (compiler.javascript) { - builder.addBlock(compiler.javascript); + if (component.javascript) { + builder.addBlock(component.javascript); } - if (compiler.options.dev) { - builder.addLine(`const ${compiler.fileVar} = ${JSON.stringify(compiler.file)};`); + if (component.options.dev) { + builder.addLine(`const ${component.fileVar} = ${JSON.stringify(component.file)};`); } - const css = compiler.stylesheet.render(options.filename, !compiler.customElement); - const styles = compiler.stylesheet.hasStyles && stringify(options.dev ? + const css = component.stylesheet.render(options.filename, !component.customElement); + const styles = component.stylesheet.hasStyles && stringify(options.dev ? `${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */` : css.code, { onlyEscapeAtSymbol: true }); - if (styles && compiler.options.css !== false && !compiler.customElement) { + if (styles && component.options.css !== false && !component.customElement) { builder.addBlock(deindent` function @add_css() { var style = @createElement("style"); - style.id = '${compiler.stylesheet.id}-style'; + style.id = '${component.stylesheet.id}-style'; style.textContent = ${styles}; @append(document.head, style); } @@ -130,10 +130,10 @@ export default function dom( .join(',\n')} }`; - const debugName = `<${compiler.customElement ? compiler.tag : name}>`; + const debugName = `<${component.customElement ? component.tag : name}>`; // generate initial state object - const expectedProperties = Array.from(compiler.expectedProperties); + const expectedProperties = Array.from(component.expectedProperties); const globals = expectedProperties.filter(prop => globalWhitelist.has(prop)); const storeProps = expectedProperties.filter(prop => prop[0] === '$'); const initialState = []; @@ -158,32 +158,32 @@ export default function dom( const constructorBody = deindent` ${options.dev && `this._debugName = '${debugName}';`} - ${options.dev && !compiler.customElement && + ${options.dev && !component.customElement && `if (!options || (!options.target && !options.root)) throw new Error("'target' is a required option");`} @init(this, options); ${templateProperties.store && `this.store = %store();`} - ${compiler.usesRefs && `this.refs = {};`} + ${component.usesRefs && `this.refs = {};`} this._state = ${initialState.reduce((state, piece) => `@assign(${state}, ${piece})`)}; ${storeProps.length > 0 && `this.store._add(this, [${storeProps.map(prop => `"${prop.slice(1)}"`)}]);`} ${target.metaBindings} ${computations.length && `this._recompute({ ${Array.from(computationDeps).map(dep => `${dep}: 1`).join(', ')} }, this._state);`} ${options.dev && - Array.from(compiler.expectedProperties).map(prop => { + Array.from(component.expectedProperties).map(prop => { if (globalWhitelist.has(prop)) return; if (computations.find(c => c.key === prop)) return; - const message = compiler.components.has(prop) ? + const message = component.components.has(prop) ? `${debugName} expected to find '${prop}' in \`data\`, but found it in \`components\` instead` : `${debugName} was created without expected data property '${prop}'`; const conditions = [`!('${prop}' in this._state)`]; - if (compiler.customElement) conditions.push(`!('${prop}' in this.attributes)`); + if (component.customElement) conditions.push(`!('${prop}' in this.attributes)`); return `if (${conditions.join(' && ')}) console.warn("${message}");` })} - ${compiler.bindingGroups.length && - `this._bindingGroups = [${Array(compiler.bindingGroups.length).fill('[]').join(', ')}];`} - this._intro = ${compiler.options.skipIntroByDefault ? '!!options.intro' : 'true'}; + ${component.bindingGroups.length && + `this._bindingGroups = [${Array(component.bindingGroups.length).fill('[]').join(', ')}];`} + this._intro = ${component.options.skipIntroByDefault ? '!!options.intro' : 'true'}; ${templateProperties.onstate && `this._handlers.state = [%onstate];`} ${templateProperties.onupdate && `this._handlers.update = [%onupdate];`} @@ -194,15 +194,15 @@ export default function dom( }];` )} - ${compiler.slots.size && `this._slotted = options.slots || {};`} + ${component.slots.size && `this._slotted = options.slots || {};`} - ${compiler.customElement ? + ${component.customElement ? deindent` this.attachShadow({ mode: 'open' }); ${css.code && `this.shadowRoot.innerHTML = \`\`;`} ` : - (compiler.stylesheet.hasStyles && options.css !== false && - `if (!document.getElementById("${compiler.stylesheet.id}-style")) @add_css();`) + (component.stylesheet.hasStyles && options.css !== false && + `if (!document.getElementById("${component.stylesheet.id}-style")) @add_css();`) } ${templateProperties.onstate && `%onstate.call(this, { changed: @assignTrue({}, this._state), current: this._state });`} @@ -216,14 +216,14 @@ export default function dom( }); `} - ${compiler.customElement ? deindent` + ${component.customElement ? deindent` this._fragment.c(); this._fragment.${block.hasIntroMethod ? 'i' : 'm'}(this.shadowRoot, null); if (options.target) this._mount(options.target, options.anchor); ` : deindent` if (options.target) { - ${compiler.options.hydratable + ${component.options.hydratable ? deindent` var nodes = @children(options.target); options.hydrate ? this._fragment.l(nodes) : this._fragment.c(); @@ -234,16 +234,16 @@ export default function dom( this._fragment.c();`} this._mount(options.target, options.anchor); - ${(compiler.hasComponents || target.hasComplexBindings || hasInitHooks || target.hasIntroTransitions) && + ${(component.hasComponents || target.hasComplexBindings || hasInitHooks || target.hasIntroTransitions) && `@flush(this);`} } `} - ${compiler.options.skipIntroByDefault && `this._intro = true;`} + ${component.options.skipIntroByDefault && `this._intro = true;`} `; - if (compiler.customElement) { - const props = compiler.props || Array.from(compiler.expectedProperties); + if (component.customElement) { + const props = component.props || Array.from(component.expectedProperties); builder.addBlock(deindent` class ${name} extends HTMLElement { @@ -266,7 +266,7 @@ export default function dom( } `).join('\n\n')} - ${compiler.slots.size && deindent` + ${component.slots.size && deindent` connectedCallback() { Object.keys(this._slotted).forEach(key => { this.appendChild(this._slotted[key]); @@ -277,7 +277,7 @@ export default function dom( this.set({ [attr]: newValue }); } - ${(compiler.hasComponents || target.hasComplexBindings || templateProperties.oncreate || target.hasIntroTransitions) && deindent` + ${(component.hasComponents || target.hasComplexBindings || templateProperties.oncreate || target.hasIntroTransitions) && deindent` connectedCallback() { @flush(this); } @@ -292,7 +292,7 @@ export default function dom( } }); - customElements.define("${compiler.tag}", ${name}); + customElements.define("${component.tag}", ${name}); `); } else { builder.addBlock(deindent` @@ -332,8 +332,8 @@ export default function dom( let result = builder.toString(); - return compiler.generate(result, options, { - banner: `/* ${compiler.file ? `${compiler.file} ` : ``}generated by Svelte v${"__VERSION__"} */`, + return component.generate(result, options, { + banner: `/* ${component.file ? `${component.file} ` : ``}generated by Svelte v${"__VERSION__"} */`, sharedPath, name, format, diff --git a/src/compile/nodes/Action.ts b/src/compile/nodes/Action.ts index 1e8f4311e7a8..79b8f7bdcbee 100644 --- a/src/compile/nodes/Action.ts +++ b/src/compile/nodes/Action.ts @@ -6,13 +6,13 @@ export default class Action extends Node { name: string; expression: Expression; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.name = info.name; this.expression = info.expression - ? new Expression(compiler, this, scope, info.expression) + ? new Expression(component, this, scope, info.expression) : null; } } \ No newline at end of file diff --git a/src/compile/nodes/Animation.ts b/src/compile/nodes/Animation.ts index cf9ec3514374..ed9f6f6e5d71 100644 --- a/src/compile/nodes/Animation.ts +++ b/src/compile/nodes/Animation.ts @@ -7,13 +7,13 @@ export default class Animation extends Node { name: string; expression: Expression; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.name = info.name; this.expression = info.expression - ? new Expression(compiler, this, scope, info.expression) + ? new Expression(component, this, scope, info.expression) : null; } diff --git a/src/compile/nodes/Attribute.ts b/src/compile/nodes/Attribute.ts index b0c26c534d8f..b569022ba2f7 100644 --- a/src/compile/nodes/Attribute.ts +++ b/src/compile/nodes/Attribute.ts @@ -2,7 +2,7 @@ import deindent from '../../utils/deindent'; import { escape, escapeTemplate, stringify } from '../../utils/stringify'; import fixAttributeCasing from '../../utils/fixAttributeCasing'; import addToSet from '../../utils/addToSet'; -import Compiler from '../Compiler'; +import Component from '../Component'; import Node from './shared/Node'; import Element from './Element'; import Text from './Text'; @@ -19,7 +19,7 @@ export default class Attribute extends Node { start: number; end: number; - compiler: Compiler; + component: Component; parent: Element; name: string; isSpread: boolean; @@ -31,8 +31,8 @@ export default class Attribute extends Node { chunks: (Text | Expression)[]; dependencies: Set; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); if (info.type === 'Spread') { this.name = null; @@ -40,7 +40,7 @@ export default class Attribute extends Node { this.isTrue = false; this.isSynthetic = false; - this.expression = new Expression(compiler, this, scope, info.expression); + this.expression = new Expression(component, this, scope, info.expression); this.dependencies = this.expression.dependencies; this.chunks = null; @@ -60,7 +60,7 @@ export default class Attribute extends Node { : info.value.map(node => { if (node.type === 'Text') return node; - const expression = new Expression(compiler, this, scope, node.expression); + const expression = new Expression(component, this, scope, node.expression); addToSet(this.dependencies, expression.dependencies); return expression; @@ -136,9 +136,9 @@ export default class Attribute extends Node { ? '@setXlinkAttribute' : '@setAttribute'; - const isLegacyInputType = this.compiler.options.legacy && name === 'type' && this.parent.name === 'input'; + const isLegacyInputType = this.component.options.legacy && name === 'type' && this.parent.name === 'input'; - const isDataSet = /^data-/.test(name) && !this.compiler.options.legacy && !node.namespace; + const isDataSet = /^data-/.test(name) && !this.component.options.legacy && !node.namespace; const camelCaseName = isDataSet ? name.replace('data-', '').replace(/(-\w)/g, function (m) { return m[1].toUpperCase(); }) : name; diff --git a/src/compile/nodes/AwaitBlock.ts b/src/compile/nodes/AwaitBlock.ts index 4897adcd59b7..df30f828a355 100644 --- a/src/compile/nodes/AwaitBlock.ts +++ b/src/compile/nodes/AwaitBlock.ts @@ -17,18 +17,18 @@ export default class AwaitBlock extends Node { then: ThenBlock; catch: CatchBlock; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); - this.expression = new Expression(compiler, this, scope, info.expression); + this.expression = new Expression(component, this, scope, info.expression); const deps = this.expression.dependencies; this.value = info.value; this.error = info.error; - this.pending = new PendingBlock(compiler, this, scope, info.pending); - this.then = new ThenBlock(compiler, this, scope.add(this.value, deps), info.then); - this.catch = new CatchBlock(compiler, this, scope.add(this.error, deps), info.catch); + this.pending = new PendingBlock(component, this, scope, info.pending); + this.then = new ThenBlock(component, this, scope.add(this.value, deps), info.then); + this.catch = new CatchBlock(component, this, scope.add(this.error, deps), info.catch); } init( @@ -49,12 +49,12 @@ export default class AwaitBlock extends Node { const child = this[status]; child.block = block.child({ - comment: createDebuggingComment(child, this.compiler), - name: this.compiler.getUniqueName(`create_${status}_block`) + comment: createDebuggingComment(child, this.component), + name: this.component.getUniqueName(`create_${status}_block`) }); child.initChildren(child.block, stripWhitespace, nextSibling); - this.compiler.target.blocks.push(child.block); + this.component.target.blocks.push(child.block); if (child.block.dependencies.size > 0) { isDynamic = true; @@ -77,7 +77,7 @@ export default class AwaitBlock extends Node { this.then.block.hasOutroMethod = hasOutros; this.catch.block.hasOutroMethod = hasOutros; - if (hasOutros && this.compiler.options.nestedTransitions) block.addOutro(); + if (hasOutros && this.component.options.nestedTransitions) block.addOutro(); } build( @@ -171,7 +171,7 @@ export default class AwaitBlock extends Node { `); } - if (this.pending.block.hasOutroMethod && this.compiler.options.nestedTransitions) { + if (this.pending.block.hasOutroMethod && this.component.options.nestedTransitions) { const countdown = block.getUniqueName('countdown'); block.builders.outro.addBlock(deindent` const ${countdown} = @callAfter(#outrocallback, 3); @@ -196,7 +196,7 @@ export default class AwaitBlock extends Node { } ssr() { - const target: SsrTarget = this.compiler.target; + const target: SsrTarget = this.component.target; const { snippet } = this.expression; target.append('${(function(__value) { if(@isPromise(__value)) return `'); diff --git a/src/compile/nodes/Binding.ts b/src/compile/nodes/Binding.ts index 45db895f7ed1..2d88267e4d4e 100644 --- a/src/compile/nodes/Binding.ts +++ b/src/compile/nodes/Binding.ts @@ -3,7 +3,7 @@ import Element from './Element'; import getObject from '../../utils/getObject'; import getTailSnippet from '../../utils/getTailSnippet'; import flattenReference from '../../utils/flattenReference'; -import Compiler from '../Compiler'; +import Component from '../Component'; import Block from '../dom/Block'; import Expression from './shared/Expression'; import { dimensions } from '../../utils/patterns'; @@ -26,11 +26,11 @@ export default class Binding extends Node { obj: string; prop: string; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.name = info.name; - this.value = new Expression(compiler, this, scope, info.value); + this.value = new Expression(component, this, scope, info.value); let obj; let prop; @@ -78,7 +78,7 @@ export default class Binding extends Node { // TODO should this happen in preprocess? const dependencies = new Set(this.value.dependencies); this.value.dependencies.forEach((prop: string) => { - const indirectDependencies = this.compiler.indirectDependencies.get(prop); + const indirectDependencies = this.component.indirectDependencies.get(prop); if (indirectDependencies) { indirectDependencies.forEach(indirectDependency => { dependencies.add(indirectDependency); @@ -87,8 +87,8 @@ export default class Binding extends Node { }); // view to model - const valueFromDom = getValueFromDom(this.compiler, node, this); - const handler = getEventHandler(this, this.compiler, block, name, snippet, dependencies, valueFromDom); + const valueFromDom = getValueFromDom(this.component, node, this); + const handler = getEventHandler(this, this.component, block, name, snippet, dependencies, valueFromDom); // model to view let updateDom = getDomUpdater(node, this, snippet); @@ -96,7 +96,7 @@ export default class Binding extends Node { // special cases if (this.name === 'group') { - const bindingGroup = getBindingGroup(this.compiler, this.value.node); + const bindingGroup = getBindingGroup(this.component, this.value.node); block.builders.hydrate.addLine( `#component._bindingGroups[${bindingGroup}].push(${node.var});` @@ -184,16 +184,16 @@ function getDomUpdater( return `${node.var}.${binding.name} = ${snippet};`; } -function getBindingGroup(compiler: Compiler, value: Node) { +function getBindingGroup(component: Component, value: Node) { const { parts } = flattenReference(value); // TODO handle cases involving computed member expressions const keypath = parts.join('.'); // TODO handle contextual bindings — `keypath` should include unique ID of // each block that provides context - let index = compiler.bindingGroups.indexOf(keypath); + let index = component.bindingGroups.indexOf(keypath); if (index === -1) { - index = compiler.bindingGroups.length; - compiler.bindingGroups.push(keypath); + index = component.bindingGroups.length; + component.bindingGroups.push(keypath); } return index; @@ -201,7 +201,7 @@ function getBindingGroup(compiler: Compiler, value: Node) { function getEventHandler( binding: Binding, - compiler: Compiler, + component: Component, block: Block, name: string, snippet: string, @@ -235,9 +235,9 @@ function getEventHandler( // Svelte tries to `set()` a computed property, which throws an // error in dev mode. a) it's possible that we should be // replacing computations with *their* dependencies, and b) - // we should probably populate `compiler.target.readonly` sooner so + // we should probably populate `component.target.readonly` sooner so // that we don't have to do the `.some()` here - dependencies = dependencies.filter(prop => !compiler.computations.some(computation => computation.key === prop)); + dependencies = dependencies.filter(prop => !component.computations.some(computation => computation.key === prop)); return { usesContext: false, @@ -271,7 +271,7 @@ function getEventHandler( } function getValueFromDom( - compiler: Compiler, + component: Component, node: Element, binding: Node ) { @@ -286,7 +286,7 @@ function getValueFromDom( // if (binding.name === 'group') { - const bindingGroup = getBindingGroup(compiler, binding.value.node); + const bindingGroup = getBindingGroup(component, binding.value.node); if (type === 'checkbox') { return `@getBindingGroupValue(#component._bindingGroups[${bindingGroup}])`; } diff --git a/src/compile/nodes/CatchBlock.ts b/src/compile/nodes/CatchBlock.ts index db15f7ceb17f..3a9235424fcb 100644 --- a/src/compile/nodes/CatchBlock.ts +++ b/src/compile/nodes/CatchBlock.ts @@ -6,8 +6,8 @@ export default class CatchBlock extends Node { block: Block; children: Node[]; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); - this.children = mapChildren(compiler, parent, scope, info.children); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); + this.children = mapChildren(component, parent, scope, info.children); } } \ No newline at end of file diff --git a/src/compile/nodes/Class.ts b/src/compile/nodes/Class.ts index 965cf7ea0d71..75000371d9e7 100644 --- a/src/compile/nodes/Class.ts +++ b/src/compile/nodes/Class.ts @@ -6,13 +6,13 @@ export default class Class extends Node { name: string; expression: Expression; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.name = info.name; this.expression = info.expression - ? new Expression(compiler, this, scope, info.expression) + ? new Expression(component, this, scope, info.expression) : null; } } \ No newline at end of file diff --git a/src/compile/nodes/Comment.ts b/src/compile/nodes/Comment.ts index ba20f5750abf..03ea0be9e671 100644 --- a/src/compile/nodes/Comment.ts +++ b/src/compile/nodes/Comment.ts @@ -4,15 +4,15 @@ export default class Comment extends Node { type: 'Comment'; data: string; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.data = info.data; } ssr() { // Allow option to preserve comments, otherwise ignore - if (this.compiler.options.preserveComments) { - this.compiler.target.append(``); + if (this.component.options.preserveComments) { + this.component.target.append(``); } } } \ No newline at end of file diff --git a/src/compile/nodes/DebugTag.ts b/src/compile/nodes/DebugTag.ts index b73208961a15..9768b5c121c9 100644 --- a/src/compile/nodes/DebugTag.ts +++ b/src/compile/nodes/DebugTag.ts @@ -9,11 +9,11 @@ import { stringify } from '../../utils/stringify'; export default class DebugTag extends Node { expressions: Expression[]; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.expressions = info.identifiers.map(node => { - return new Expression(compiler, parent, scope, node); + return new Expression(component, parent, scope, node); }); } @@ -22,9 +22,9 @@ export default class DebugTag extends Node { parentNode: string, parentNodes: string, ) { - if (!this.compiler.options.dev) return; + if (!this.component.options.dev) return; - const { code } = this.compiler; + const { code } = this.component; if (this.expressions.length === 0) { // Debug all @@ -36,7 +36,7 @@ export default class DebugTag extends Node { block.builders.create.addLine(statement); block.builders.update.addLine(statement); } else { - const { code } = this.compiler; + const { code } = this.component; code.overwrite(this.start + 1, this.start + 7, 'log', { storeName: true }); @@ -70,10 +70,10 @@ export default class DebugTag extends Node { } ssr() { - if (!this.compiler.options.dev) return; + if (!this.component.options.dev) return; - const filename = this.compiler.file || null; - const { line, column } = this.compiler.locate(this.start + 1); + const filename = this.component.file || null; + const { line, column } = this.component.locate(this.start + 1); const obj = this.expressions.length === 0 ? `ctx` @@ -84,6 +84,6 @@ export default class DebugTag extends Node { const str = '${@debug(' + `${filename && stringify(filename)}, ${line}, ${column}, ${obj})}`; - this.compiler.target.append(str); + this.component.target.append(str); } } \ No newline at end of file diff --git a/src/compile/nodes/EachBlock.ts b/src/compile/nodes/EachBlock.ts index 2a62249c6326..f40627c51fee 100644 --- a/src/compile/nodes/EachBlock.ts +++ b/src/compile/nodes/EachBlock.ts @@ -24,10 +24,10 @@ export default class EachBlock extends Node { children: Node[]; else?: ElseBlock; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); - this.expression = new Expression(compiler, this, scope, info.expression); + this.expression = new Expression(component, this, scope, info.expression); this.context = info.context.name || 'each'; // TODO this is used to facilitate binding; currently fails with destructuring this.index = info.index; @@ -41,7 +41,7 @@ export default class EachBlock extends Node { }); this.key = info.key - ? new Expression(compiler, this, this.scope, info.key) + ? new Expression(component, this, this.scope, info.key) : null; if (this.index) { @@ -50,10 +50,10 @@ export default class EachBlock extends Node { this.scope.add(this.index, dependencies); } - this.children = mapChildren(compiler, this, this.scope, info.children); + this.children = mapChildren(component, this, this.scope, info.children); this.else = info.else - ? new ElseBlock(compiler, this, this.scope, info.else) + ? new ElseBlock(component, this, this.scope, info.else) : null; } @@ -66,22 +66,22 @@ export default class EachBlock extends Node { this.var = block.getUniqueName(`each`); this.iterations = block.getUniqueName(`${this.var}_blocks`); - this.get_each_context = this.compiler.getUniqueName(`get_${this.var}_context`); + this.get_each_context = this.component.getUniqueName(`get_${this.var}_context`); const { dependencies } = this.expression; block.addDependencies(dependencies); this.block = block.child({ - comment: createDebuggingComment(this, this.compiler), - name: this.compiler.getUniqueName('create_each_block'), + comment: createDebuggingComment(this, this.component), + name: this.component.getUniqueName('create_each_block'), key: this.key, bindings: new Map(block.bindings) }); - this.each_block_value = this.compiler.getUniqueName('each_value'); + this.each_block_value = this.component.getUniqueName('each_value'); - const indexName = this.index || this.compiler.getUniqueName(`${this.context}_index`); + const indexName = this.index || this.component.getUniqueName(`${this.context}_index`); this.contexts.forEach(prop => { this.block.bindings.set(prop.key.name, `ctx.${this.each_block_value}[ctx.${indexName}]${prop.tail}`); @@ -99,18 +99,18 @@ export default class EachBlock extends Node { `child_ctx.${indexName} = i;` ); - this.compiler.target.blocks.push(this.block); + this.component.target.blocks.push(this.block); this.initChildren(this.block, stripWhitespace, nextSibling); block.addDependencies(this.block.dependencies); this.block.hasUpdateMethod = this.block.dependencies.size > 0; if (this.else) { this.else.block = block.child({ - comment: createDebuggingComment(this.else, this.compiler), - name: this.compiler.getUniqueName(`${this.block.name}_else`), + comment: createDebuggingComment(this.else, this.component), + name: this.component.getUniqueName(`${this.block.name}_else`), }); - this.compiler.target.blocks.push(this.else.block); + this.component.target.blocks.push(this.else.block); this.else.initChildren( this.else.block, stripWhitespace, @@ -131,7 +131,7 @@ export default class EachBlock extends Node { ) { if (this.children.length === 0) return; - const { compiler } = this; + const { component } = this; const each = this.var; @@ -146,8 +146,8 @@ export default class EachBlock extends Node { // hack the sourcemap, so that if data is missing the bug // is easy to find let c = this.start + 2; - while (compiler.source[c] !== 'e') c += 1; - compiler.code.overwrite(c, c + 4, 'length'); + while (component.source[c] !== 'e') c += 1; + component.code.overwrite(c, c + 4, 'length'); const length = `[✂${c}-${c+4}✂]`; const mountOrIntro = (this.block.hasIntroMethod || this.block.hasOutroMethod) ? 'i' : 'm'; @@ -164,7 +164,7 @@ export default class EachBlock extends Node { block.builders.init.addLine(`var ${this.each_block_value} = ${snippet};`); - this.compiler.target.blocks.push(deindent` + this.component.target.blocks.push(deindent` function ${this.get_each_context}(ctx, list, i) { const child_ctx = Object.create(ctx); ${this.contextProps} @@ -188,7 +188,7 @@ export default class EachBlock extends Node { } if (this.else) { - const each_block_else = compiler.getUniqueName(`${each}_else`); + const each_block_else = component.getUniqueName(`${each}_else`); const mountOrIntro = (this.else.block.hasIntroMethod || this.else.block.hasOutroMethod) ? 'i' : 'm'; block.builders.init.addLine(`var ${each_block_else} = null;`); @@ -331,7 +331,7 @@ export default class EachBlock extends Node { ${this.block.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].a();`} `); - if (this.block.hasOutros && this.compiler.options.nestedTransitions) { + if (this.block.hasOutros && this.component.options.nestedTransitions) { const countdown = block.getUniqueName('countdown'); block.builders.outro.addBlock(deindent` const ${countdown} = @callAfter(#outrocallback, ${blocks}.length); @@ -477,7 +477,7 @@ export default class EachBlock extends Node { `); } - if (outroBlock && this.compiler.options.nestedTransitions) { + if (outroBlock && this.component.options.nestedTransitions) { const countdown = block.getUniqueName('countdown'); block.builders.outro.addBlock(deindent` ${iterations} = ${iterations}.filter(Boolean); @@ -495,7 +495,7 @@ export default class EachBlock extends Node { } ssr() { - const { compiler } = this; + const { component } = this; const { snippet } = this.expression; const props = this.contexts.map(prop => `${prop.key.name}: item${prop.tail}`); @@ -505,23 +505,23 @@ export default class EachBlock extends Node { : `item => Object.assign({}, ctx, { ${props.join(', ')} })`; const open = `\${ ${this.else ? `${snippet}.length ? ` : ''}@each(${snippet}, ${getContext}, ctx => \``; - compiler.target.append(open); + component.target.append(open); this.children.forEach((child: Node) => { child.ssr(); }); const close = `\`)`; - compiler.target.append(close); + component.target.append(close); if (this.else) { - compiler.target.append(` : \``); + component.target.append(` : \``); this.else.children.forEach((child: Node) => { child.ssr(); }); - compiler.target.append(`\``); + component.target.append(`\``); } - compiler.target.append('}'); + component.target.append('}'); } } diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index d693fc04d75d..cca8db51161d 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -6,7 +6,7 @@ import validCalleeObjects from '../../utils/validCalleeObjects'; import reservedNames from '../../utils/reservedNames'; import fixAttributeCasing from '../../utils/fixAttributeCasing'; import { quoteNameIfNecessary, quotePropIfNecessary } from '../../utils/quoteIfNecessary'; -import Compiler from '../Compiler'; +import Component from '../Component'; import Node from './shared/Node'; import Block from '../dom/Block'; import Attribute from './Attribute'; @@ -80,15 +80,15 @@ export default class Element extends Node { ref: string; namespace: string; - constructor(compiler, parent, scope, info: any) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info: any) { + super(component, parent, scope, info); this.name = info.name; this.scope = scope; const parentElement = parent.findNearest(/^Element/); this.namespace = this.name === 'svg' ? namespaces.svg : - parentElement ? parentElement.namespace : this.compiler.namespace; + parentElement ? parentElement.namespace : this.component.namespace; this.attributes = []; this.actions = []; @@ -134,7 +134,7 @@ export default class Element extends Node { info.attributes.forEach(node => { switch (node.type) { case 'Action': - this.actions.push(new Action(compiler, this, scope, node)); + this.actions.push(new Action(component, this, scope, node)); break; case 'Attribute': @@ -142,36 +142,36 @@ export default class Element extends Node { // special case if (node.name === 'xmlns') this.namespace = node.value[0].data; - this.attributes.push(new Attribute(compiler, this, scope, node)); + this.attributes.push(new Attribute(component, this, scope, node)); break; case 'Binding': - this.bindings.push(new Binding(compiler, this, scope, node)); + this.bindings.push(new Binding(component, this, scope, node)); break; case 'Class': - this.classes.push(new Class(compiler, this, scope, node)); + this.classes.push(new Class(component, this, scope, node)); break; case 'EventHandler': - this.handlers.push(new EventHandler(compiler, this, scope, node)); + this.handlers.push(new EventHandler(component, this, scope, node)); break; case 'Transition': - const transition = new Transition(compiler, this, scope, node); + const transition = new Transition(component, this, scope, node); if (node.intro) this.intro = transition; if (node.outro) this.outro = transition; break; case 'Animation': - this.animation = new Animation(compiler, this, scope, node); + this.animation = new Animation(component, this, scope, node); break; case 'Ref': // TODO catch this in validation if (this.ref) throw new Error(`Duplicate refs`); - compiler.usesRefs = true + component.usesRefs = true this.ref = node.name; break; @@ -180,9 +180,9 @@ export default class Element extends Node { } }); - this.children = mapChildren(compiler, this, scope, info.children); + this.children = mapChildren(component, this, scope, info.children); - compiler.stylesheet.apply(this); + component.stylesheet.apply(this); } init( @@ -190,7 +190,7 @@ export default class Element extends Node { stripWhitespace: boolean, nextSibling: Node ) { - if (this.name === 'slot' || this.name === 'option' || this.compiler.options.dev) { + if (this.name === 'slot' || this.name === 'option' || this.component.options.dev) { this.cannotUseInnerHTML(); } @@ -217,7 +217,7 @@ export default class Element extends Node { if (select && select.selectBindingDependencies) { select.selectBindingDependencies.forEach(prop => { attr.dependencies.forEach((dependency: string) => { - this.compiler.indirectDependencies.get(prop).add(dependency); + this.component.indirectDependencies.get(prop).add(dependency); }); }); } @@ -276,7 +276,7 @@ export default class Element extends Node { const dependencies = binding.value.dependencies; this.selectBindingDependencies = dependencies; dependencies.forEach((prop: string) => { - this.compiler.indirectDependencies.set(prop, new Set()); + this.component.indirectDependencies.set(prop, new Set()); }); } else { this.selectBindingDependencies = null; @@ -303,11 +303,11 @@ export default class Element extends Node { parentNode: string, parentNodes: string ) { - const { compiler } = this; + const { component } = this; if (this.name === 'slot') { const slotName = this.getStaticAttributeValue('name') || 'default'; - this.compiler.slots.add(slotName); + this.component.slots.add(slotName); } if (this.name === 'noscript') return; @@ -327,10 +327,10 @@ export default class Element extends Node { `${node} = ${renderStatement};` ); - if (this.compiler.options.hydratable) { + if (this.component.options.hydratable) { if (parentNodes) { block.builders.claim.addBlock(deindent` - ${node} = ${getClaimStatement(compiler, this.namespace, parentNodes, this)}; + ${node} = ${getClaimStatement(component, this.namespace, parentNodes, this)}; var ${nodes} = @children(${this.name === 'template' ? `${node}.content` : node}); `); } else { @@ -453,10 +453,10 @@ export default class Element extends Node { return `${open}>${node.children.map(toHTML).join('')}`; } - if (this.compiler.options.dev) { - const loc = this.compiler.locate(this.start); + if (this.component.options.dev) { + const loc = this.component.locate(this.start); block.builders.hydrate.addLine( - `@addLoc(${this.var}, ${this.compiler.fileVar}, ${loc.line}, ${loc.column}, ${this.start});` + `@addLoc(${this.var}, ${this.component.fileVar}, ${loc.line}, ${loc.column}, ${this.start});` ); } } @@ -466,7 +466,7 @@ export default class Element extends Node { ) { if (this.bindings.length === 0) return; - if (this.name === 'select' || this.isMediaNode()) this.compiler.target.hasComplexBindings = true; + if (this.name === 'select' || this.isMediaNode()) this.component.target.hasComplexBindings = true; const needsLock = this.name !== 'input' || !/radio|checkbox|range|color/.test(this.getStaticAttributeValue('type')); @@ -575,7 +575,7 @@ export default class Element extends Node { .join(' && '); if (this.name === 'select' || group.bindings.find(binding => binding.name === 'indeterminate' || binding.isReadOnlyMediaAttribute)) { - this.compiler.target.hasComplexBindings = true; + this.component.target.hasComplexBindings = true; block.builders.hydrate.addLine( `if (!(${allInitialStateIsDefined})) #component.root._beforecreate.push(${handler});` @@ -583,7 +583,7 @@ export default class Element extends Node { } if (group.events[0] === 'resize') { - this.compiler.target.hasComplexBindings = true; + this.component.target.hasComplexBindings = true; block.builders.hydrate.addLine( `#component.root._beforecreate.push(${handler});` @@ -659,24 +659,24 @@ export default class Element extends Node { } addEventHandlers(block: Block) { - const { compiler } = this; + const { component } = this; this.handlers.forEach(handler => { - const isCustomEvent = compiler.events.has(handler.name); + const isCustomEvent = component.events.has(handler.name); if (handler.callee) { - handler.render(this.compiler, block, handler.shouldHoist); + handler.render(this.component, block, handler.shouldHoist); } const target = handler.shouldHoist ? 'this' : this.var; // get a name for the event handler that is globally unique // if hoisted, locally unique otherwise - const handlerName = (handler.shouldHoist ? compiler : block).getUniqueName( + const handlerName = (handler.shouldHoist ? component : block).getUniqueName( `${handler.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_handler` ); - const component = block.alias('component'); // can't use #component, might be hoisted + const component_name = block.alias('component'); // can't use #component, might be hoisted // create the handler body const handlerBody = deindent` @@ -688,14 +688,14 @@ export default class Element extends Node { ${handler.snippet ? handler.snippet : - `${component}.fire("${handler.name}", event);`} + `${component_name}.fire("${handler.name}", event);`} `; if (isCustomEvent) { block.addVariable(handlerName); block.builders.hydrate.addBlock(deindent` - ${handlerName} = %events-${handler.name}.call(${component}, ${this.var}, function(event) { + ${handlerName} = %events-${handler.name}.call(${component_name}, ${this.var}, function(event) { ${handlerBody} }); `); @@ -711,7 +711,7 @@ export default class Element extends Node { `; if (handler.shouldHoist) { - compiler.target.blocks.push(handlerFunction); + component.target.blocks.push(handlerFunction); } else { block.builders.init.addBlock(handlerFunction); } @@ -946,14 +946,14 @@ export default class Element extends Node { return `@append(${name}._slotted.default, ${this.var});`; } - addCssClass(className = this.compiler.stylesheet.id) { + addCssClass(className = this.component.stylesheet.id) { const classAttribute = this.attributes.find(a => a.name === 'class'); if (classAttribute && !classAttribute.isTrue) { if (classAttribute.chunks.length === 1 && classAttribute.chunks[0].type === 'Text') { (classAttribute.chunks[0]).data += ` ${className}`; } else { (classAttribute.chunks).push( - new Text(this.compiler, this, this.scope, { + new Text(this.component, this, this.scope, { type: 'Text', data: ` ${className}` }) @@ -961,7 +961,7 @@ export default class Element extends Node { } } else { this.attributes.push( - new Attribute(this.compiler, this, this.scope, { + new Attribute(this.component, this, this.scope, { type: 'Attribute', name: 'class', value: [{ type: 'Text', data: className }] @@ -971,7 +971,7 @@ export default class Element extends Node { } ssr() { - const { compiler } = this; + const { component } = this; let openingTag = `<${this.name}`; let textareaContents; // awkward special case @@ -980,7 +980,7 @@ export default class Element extends Node { if (slot && this.hasAncestor('InlineComponent')) { const slot = this.attributes.find((attribute: Node) => attribute.name === 'slot'); const slotName = slot.chunks[0].data; - const appendTarget = compiler.target.appendTargets[compiler.target.appendTargets.length - 1]; + const appendTarget = component.target.appendTargets[component.target.appendTargets.length - 1]; appendTarget.slotStack.push(slotName); appendTarget.slots[slotName] = ''; } @@ -1048,10 +1048,10 @@ export default class Element extends Node { openingTag += '>'; - compiler.target.append(openingTag); + component.target.append(openingTag); if (this.name === 'textarea' && textareaContents !== undefined) { - compiler.target.append(textareaContents); + component.target.append(textareaContents); } else { this.children.forEach((child: Node) => { child.ssr(); @@ -1059,7 +1059,7 @@ export default class Element extends Node { } if (!isVoidElementName(this.name)) { - compiler.target.append(``); + component.target.append(``); } } } @@ -1080,7 +1080,7 @@ function getRenderStatement( } function getClaimStatement( - compiler: Compiler, + component: Component, namespace: string, nodes: string, node: Node diff --git a/src/compile/nodes/ElseBlock.ts b/src/compile/nodes/ElseBlock.ts index 7d334e335664..8719941e3b6a 100644 --- a/src/compile/nodes/ElseBlock.ts +++ b/src/compile/nodes/ElseBlock.ts @@ -7,8 +7,8 @@ export default class ElseBlock extends Node { children: Node[]; block: Block; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); - this.children = mapChildren(compiler, this, scope, info.children); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); + this.children = mapChildren(component, this, scope, info.children); } } \ No newline at end of file diff --git a/src/compile/nodes/EventHandler.ts b/src/compile/nodes/EventHandler.ts index 54dbd66157d8..8315f5f7faf1 100644 --- a/src/compile/nodes/EventHandler.ts +++ b/src/compile/nodes/EventHandler.ts @@ -19,8 +19,8 @@ export default class EventHandler extends Node { args: Expression[]; snippet: string; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.name = info.name; this.dependencies = new Set(); @@ -33,7 +33,7 @@ export default class EventHandler extends Node { this.usesContext = false; this.args = info.expression.arguments.map(param => { - const expression = new Expression(compiler, this, scope, param); + const expression = new Expression(component, this, scope, param); addToSet(this.dependencies, expression.dependencies); if (expression.usesContext) this.usesContext = true; return expression; @@ -51,28 +51,28 @@ export default class EventHandler extends Node { this.snippet = null; // TODO handle shorthand events here? } - this.isCustomEvent = compiler.events.has(this.name); + this.isCustomEvent = component.events.has(this.name); this.shouldHoist = !this.isCustomEvent && parent.hasAncestor('EachBlock'); } - render(compiler, block, hoisted) { // TODO hoist more event handlers + render(component, block, hoisted) { // TODO hoist more event handlers if (this.insertionPoint === null) return; // TODO handle shorthand events here? if (!validCalleeObjects.has(this.callee.name)) { - const component = hoisted ? `component` : block.alias(`component`); + const component_name = hoisted ? `component` : block.alias(`component`); // allow event.stopPropagation(), this.select() etc // TODO verify that it's a valid callee (i.e. built-in or declared method) - if (this.callee.name[0] === '$' && !compiler.methods.has(this.callee.name)) { - compiler.code.overwrite( + if (this.callee.name[0] === '$' && !component.methods.has(this.callee.name)) { + component.code.overwrite( this.insertionPoint, this.insertionPoint + 1, - `${component}.store.` + `${component_name}.store.` ); } else { - compiler.code.prependRight( + component.code.prependRight( this.insertionPoint, - `${component}.` + `${component_name}.` ); } } @@ -84,7 +84,7 @@ export default class EventHandler extends Node { if (this.callee && this.callee.name === 'this') { const node = this.callee.nodes[0]; - compiler.code.overwrite(node.start, node.end, this.parent.var, { + component.code.overwrite(node.start, node.end, this.parent.var, { storeName: true, contentOnly: true }); diff --git a/src/compile/nodes/Fragment.ts b/src/compile/nodes/Fragment.ts index e874fe3707ef..f3d59adc2085 100644 --- a/src/compile/nodes/Fragment.ts +++ b/src/compile/nodes/Fragment.ts @@ -1,5 +1,5 @@ import Node from './shared/Node'; -import Compiler from '../Compiler'; +import Component from '../Component'; import mapChildren from './shared/mapChildren'; import Block from '../dom/Block'; import TemplateScope from './shared/TemplateScope'; @@ -9,17 +9,17 @@ export default class Fragment extends Node { children: Node[]; scope: TemplateScope; - constructor(compiler: Compiler, info: any) { + constructor(component: Component, info: any) { const scope = new TemplateScope(); - super(compiler, null, scope, info); + super(component, null, scope, info); this.scope = scope; - this.children = mapChildren(compiler, this, scope, info.children); + this.children = mapChildren(component, this, scope, info.children); } init() { this.block = new Block({ - compiler: this.compiler, + component: this.component, name: '@create_main_fragment', key: null, @@ -28,7 +28,7 @@ export default class Fragment extends Node { dependencies: new Set(), }); - this.compiler.target.blocks.push(this.block); + this.component.target.blocks.push(this.block); this.initChildren(this.block, true, null); this.block.hasUpdateMethod = true; diff --git a/src/compile/nodes/Head.ts b/src/compile/nodes/Head.ts index f65d91f36b7a..bbf745812f36 100644 --- a/src/compile/nodes/Head.ts +++ b/src/compile/nodes/Head.ts @@ -9,9 +9,9 @@ export default class Head extends Node { type: 'Head'; children: any[]; // TODO - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); - this.children = mapChildren(compiler, parent, scope, info.children.filter(child => { + constructor(component, parent, scope, info) { + super(component, parent, scope, info); + this.children = mapChildren(component, parent, scope, info.children.filter(child => { return (child.type !== 'Text' || /\S/.test(child.data)); })); } @@ -37,12 +37,12 @@ export default class Head extends Node { } ssr() { - this.compiler.target.append('${(__result.head += `'); + this.component.target.append('${(__result.head += `'); this.children.forEach((child: Node) => { child.ssr(); }); - this.compiler.target.append('`, "")}'); + this.component.target.append('`, "")}'); } } diff --git a/src/compile/nodes/IfBlock.ts b/src/compile/nodes/IfBlock.ts index eef654b90bbb..e48c28e2e878 100644 --- a/src/compile/nodes/IfBlock.ts +++ b/src/compile/nodes/IfBlock.ts @@ -1,7 +1,7 @@ import deindent from '../../utils/deindent'; import Node from './shared/Node'; import ElseBlock from './ElseBlock'; -import Compiler from '../Compiler'; +import Component from '../Component'; import Block from '../dom/Block'; import createDebuggingComment from '../../utils/createDebuggingComment'; import Expression from './shared/Expression'; @@ -25,14 +25,14 @@ export default class IfBlock extends Node { block: Block; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); - this.expression = new Expression(compiler, this, scope, info.expression); - this.children = mapChildren(compiler, this, scope, info.children); + this.expression = new Expression(component, this, scope, info.expression); + this.children = mapChildren(component, this, scope, info.children); this.else = info.else - ? new ElseBlock(compiler, this, scope, info.else) + ? new ElseBlock(component, this, scope, info.else) : null; } @@ -41,7 +41,7 @@ export default class IfBlock extends Node { stripWhitespace: boolean, nextSibling: Node ) { - const { compiler } = this; + const { component } = this; this.cannotUseInnerHTML(); @@ -56,8 +56,8 @@ export default class IfBlock extends Node { block.addDependencies(node.expression.dependencies); node.block = block.child({ - comment: createDebuggingComment(node, compiler), - name: compiler.getUniqueName(`create_if_block`), + comment: createDebuggingComment(node, component), + name: component.getUniqueName(`create_if_block`), }); blocks.push(node.block); @@ -75,8 +75,8 @@ export default class IfBlock extends Node { attachBlocks(node.else.children[0]); } else if (node.else) { node.else.block = block.child({ - comment: createDebuggingComment(node.else, compiler), - name: compiler.getUniqueName(`create_if_block`), + comment: createDebuggingComment(node.else, component), + name: component.getUniqueName(`create_if_block`), }); blocks.push(node.else.block); @@ -98,7 +98,7 @@ export default class IfBlock extends Node { attachBlocks(this); - if (compiler.options.nestedTransitions) { + if (component.options.nestedTransitions) { if (hasIntros) block.addIntro(); if (hasOutros) block.addOutro(); } @@ -109,7 +109,7 @@ export default class IfBlock extends Node { block.hasOutroMethod = hasOutros; }); - compiler.target.blocks.push(...blocks); + component.target.blocks.push(...blocks); } build( @@ -138,7 +138,7 @@ export default class IfBlock extends Node { if (hasOutros) { this.buildCompoundWithOutros(block, parentNode, parentNodes, branches, dynamic, vars); - if (this.compiler.options.nestedTransitions) { + if (this.component.options.nestedTransitions) { block.builders.outro.addBlock(deindent` if (${name}) ${name}.o(#outrocallback); else #outrocallback(); @@ -150,7 +150,7 @@ export default class IfBlock extends Node { } else { this.buildSimple(block, parentNode, parentNodes, branches[0], dynamic, vars); - if (hasOutros && this.compiler.options.nestedTransitions) { + if (hasOutros && this.component.options.nestedTransitions) { block.builders.outro.addBlock(deindent` if (${name}) ${name}.o(#outrocallback); else #outrocallback(); @@ -184,7 +184,7 @@ export default class IfBlock extends Node { dynamic, { name, anchor, hasElse, if_name } ) { - const select_block_type = this.compiler.getUniqueName(`select_block_type`); + const select_block_type = this.component.getUniqueName(`select_block_type`); const current_block_type = block.getUniqueName(`current_block_type`); const current_block_type_and = hasElse ? '' : `${current_block_type} && `; @@ -247,7 +247,7 @@ export default class IfBlock extends Node { dynamic, { name, anchor, hasElse } ) { - const select_block_type = this.compiler.getUniqueName(`select_block_type`); + const select_block_type = this.component.getUniqueName(`select_block_type`); const current_block_type_index = block.getUniqueName(`current_block_type_index`); const previous_block_index = block.getUniqueName(`previous_block_index`); const if_block_creators = block.getUniqueName(`if_block_creators`); @@ -482,16 +482,16 @@ export default class IfBlock extends Node { } ssr() { - const { compiler } = this; + const { component } = this; const { snippet } = this.expression; - compiler.target.append('${ ' + snippet + ' ? `'); + component.target.append('${ ' + snippet + ' ? `'); this.children.forEach((child: Node) => { child.ssr(); }); - compiler.target.append('` : `'); + component.target.append('` : `'); if (this.else) { this.else.children.forEach((child: Node) => { @@ -499,7 +499,7 @@ export default class IfBlock extends Node { }); } - compiler.target.append('` }'); + component.target.append('` }'); } visitChildren(block: Block, node: Node) { diff --git a/src/compile/nodes/InlineComponent.ts b/src/compile/nodes/InlineComponent.ts index dc5e87fd1076..0fbc7a635c52 100644 --- a/src/compile/nodes/InlineComponent.ts +++ b/src/compile/nodes/InlineComponent.ts @@ -25,15 +25,15 @@ export default class InlineComponent extends Node { children: Node[]; ref: string; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); - compiler.hasComponents = true; + component.hasComponents = true; this.name = info.name; this.expression = this.name === 'svelte:component' - ? new Expression(compiler, this, scope, info.expression) + ? new Expression(component, this, scope, info.expression) : null; this.attributes = []; @@ -44,22 +44,22 @@ export default class InlineComponent extends Node { switch (node.type) { case 'Attribute': case 'Spread': - this.attributes.push(new Attribute(compiler, this, scope, node)); + this.attributes.push(new Attribute(component, this, scope, node)); break; case 'Binding': - this.bindings.push(new Binding(compiler, this, scope, node)); + this.bindings.push(new Binding(component, this, scope, node)); break; case 'EventHandler': - this.handlers.push(new EventHandler(compiler, this, scope, node)); + this.handlers.push(new EventHandler(component, this, scope, node)); break; case 'Ref': // TODO catch this in validation if (this.ref) throw new Error(`Duplicate refs`); - compiler.usesRefs = true + component.usesRefs = true this.ref = node.name; break; @@ -68,7 +68,7 @@ export default class InlineComponent extends Node { } }); - this.children = mapChildren(compiler, this, scope, info.children); + this.children = mapChildren(component, this, scope, info.children); } init( @@ -96,7 +96,7 @@ export default class InlineComponent extends Node { this.var = block.getUniqueName( ( - this.name === 'svelte:self' ? this.compiler.name : + this.name === 'svelte:self' ? this.component.name : this.name === 'svelte:component' ? 'switch_instance' : this.name ).toLowerCase() @@ -110,7 +110,7 @@ export default class InlineComponent extends Node { }); } - if (this.compiler.options.nestedTransitions) { + if (this.component.options.nestedTransitions) { block.addOutro(); } } @@ -120,7 +120,7 @@ export default class InlineComponent extends Node { parentNode: string, parentNodes: string ) { - const { compiler } = this; + const { component } = this; const name = this.var; @@ -228,7 +228,7 @@ export default class InlineComponent extends Node { } if (this.bindings.length) { - compiler.target.hasComplexBindings = true; + component.target.hasComplexBindings = true; name_updating = block.alias(`${name}_updating`); block.addVariable(name_updating, '{}'); @@ -337,7 +337,7 @@ export default class InlineComponent extends Node { this.handlers.forEach(handler => { handler.var = block.getUniqueName(`${this.var}_${handler.name}`); // TODO this is hacky - handler.render(compiler, block, false); // TODO hoist when possible + handler.render(component, block, false); // TODO hoist when possible if (handler.usesContext) block.maintainContext = true; // TODO is there a better place to put this? }); @@ -403,7 +403,7 @@ export default class InlineComponent extends Node { block.builders.update.addBlock(deindent` if (${switch_value} !== (${switch_value} = ${snippet})) { if (${name}) { - ${this.compiler.options.nestedTransitions + ${this.component.options.nestedTransitions ? deindent` @groupOutros(); const old_component = ${name}; @@ -455,7 +455,7 @@ export default class InlineComponent extends Node { block.builders.destroy.addLine(`if (${name}) ${name}.destroy(${parentNode ? '' : 'detach'});`); } else { const expression = this.name === 'svelte:self' - ? compiler.name + ? component.name : `%components-${this.name}`; block.builders.init.addBlock(deindent` @@ -503,7 +503,7 @@ export default class InlineComponent extends Node { `); } - if (this.compiler.options.nestedTransitions) { + if (this.component.options.nestedTransitions) { block.builders.outro.addLine( `if (${name}) ${name}._fragment.o(#outrocallback);` ); @@ -570,7 +570,7 @@ export default class InlineComponent extends Node { const expression = ( this.name === 'svelte:self' - ? this.compiler.name + ? this.component.name : this.name === 'svelte:component' ? `((${this.expression.snippet}) || @missingComponent)` : `%components-${this.name}` @@ -594,7 +594,7 @@ export default class InlineComponent extends Node { const { name } = getObject(binding.value.node); - this.compiler.target.bindings.push(deindent` + this.component.target.bindings.push(deindent` if (${conditions.reverse().join('&&')}) { tmp = ${expression}.data(); if ('${name}' in tmp) { @@ -616,7 +616,7 @@ export default class InlineComponent extends Node { slotStack: ['default'] }; - this.compiler.target.appendTargets.push(appendTarget); + this.component.target.appendTargets.push(appendTarget); this.children.forEach((child: Node) => { child.ssr(); @@ -628,15 +628,15 @@ export default class InlineComponent extends Node { options.push(`slotted: { ${slotted} }`); - this.compiler.target.appendTargets.pop(); + this.component.target.appendTargets.pop(); } if (options.length) { open += `, { ${options.join(', ')} }`; } - this.compiler.target.append(open); - this.compiler.target.append(')}'); + this.component.target.append(open); + this.component.target.append(')}'); } } diff --git a/src/compile/nodes/MustacheTag.ts b/src/compile/nodes/MustacheTag.ts index f67ac5b64d48..f543ee9df2db 100644 --- a/src/compile/nodes/MustacheTag.ts +++ b/src/compile/nodes/MustacheTag.ts @@ -26,7 +26,7 @@ export default class MustacheTag extends Tag { } ssr() { - this.compiler.target.append( + this.component.target.append( this.parent && this.parent.type === 'Element' && this.parent.name === 'style' diff --git a/src/compile/nodes/PendingBlock.ts b/src/compile/nodes/PendingBlock.ts index 5359d3de6587..51428ada9a23 100644 --- a/src/compile/nodes/PendingBlock.ts +++ b/src/compile/nodes/PendingBlock.ts @@ -6,8 +6,8 @@ export default class PendingBlock extends Node { block: Block; children: Node[]; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); - this.children = mapChildren(compiler, parent, scope, info.children); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); + this.children = mapChildren(component, parent, scope, info.children); } } \ No newline at end of file diff --git a/src/compile/nodes/RawMustacheTag.ts b/src/compile/nodes/RawMustacheTag.ts index f50f1e6a3136..70f47a6332eb 100644 --- a/src/compile/nodes/RawMustacheTag.ts +++ b/src/compile/nodes/RawMustacheTag.ts @@ -95,6 +95,6 @@ export default class RawMustacheTag extends Tag { } ssr() { - this.compiler.target.append('${' + this.expression.snippet + '}'); + this.component.target.append('${' + this.expression.snippet + '}'); } } \ No newline at end of file diff --git a/src/compile/nodes/Slot.ts b/src/compile/nodes/Slot.ts index bfbf4254b13a..09e423948cee 100644 --- a/src/compile/nodes/Slot.ts +++ b/src/compile/nodes/Slot.ts @@ -36,10 +36,10 @@ export default class Slot extends Element { parentNode: string, parentNodes: string ) { - const { compiler } = this; + const { component } = this; const slotName = this.getStaticAttributeValue('name') || 'default'; - compiler.slots.add(slotName); + component.slots.add(slotName); const content_name = block.getUniqueName(`slot_content_${sanitize(slotName)}`); const prop = quotePropIfNecessary(slotName); @@ -160,12 +160,12 @@ export default class Slot extends Element { const slotName = name && name.chunks[0].data || 'default'; const prop = quotePropIfNecessary(slotName); - this.compiler.target.append(`\${options && options.slotted && options.slotted${prop} ? options.slotted${prop}() : \``); + this.component.target.append(`\${options && options.slotted && options.slotted${prop} ? options.slotted${prop}() : \``); this.children.forEach((child: Node) => { child.ssr(); }); - this.compiler.target.append(`\`}`); + this.component.target.append(`\`}`); } } \ No newline at end of file diff --git a/src/compile/nodes/Text.ts b/src/compile/nodes/Text.ts index ab502bf6404d..6bd5a958d8d4 100644 --- a/src/compile/nodes/Text.ts +++ b/src/compile/nodes/Text.ts @@ -31,8 +31,8 @@ export default class Text extends Node { data: string; shouldSkip: boolean; - constructor(compiler, parent, scope, info) { - super(compiler, parent, scope, info); + constructor(component, parent, scope, info) { + super(component, parent, scope, info); this.data = info.data; } @@ -74,6 +74,6 @@ export default class Text extends Node { // unless this Text node is inside a