From 6b58a1d2f6a5f8430abdade6044077dbfe96d7ed Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Sun, 9 Jun 2019 17:41:42 -0700 Subject: [PATCH] Events for DOM methods --- src/compiler/compile/Component.ts | 388 ++++++++++++------ .../wrappers/shared/add_event_handlers.ts | 37 +- src/runtime/internal/Component.ts | 17 - src/runtime/internal/dev.ts | 85 ++++ src/runtime/internal/dom.ts | 4 - src/runtime/internal/index.ts | 1 + 6 files changed, 368 insertions(+), 164 deletions(-) create mode 100644 src/runtime/internal/dev.ts diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 5b08b795ce..5b7acd38ba 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -6,7 +6,12 @@ import Stats from '../Stats'; import { globals, reserved } from '../utils/names'; import { namespaces, valid_namespaces } from '../utils/namespaces'; import create_module from './create_module'; -import { create_scopes, extract_names, Scope, extract_identifiers } from './utils/scope'; +import { + create_scopes, + extract_names, + Scope, + extract_identifiers, +} from './utils/scope'; import Stylesheet from './css/Stylesheet'; import { test } from '../config'; import Fragment from './nodes/Fragment'; @@ -39,7 +44,13 @@ childKeys.EachBlock = childKeys.IfBlock = ['children', 'else']; childKeys.Attribute = ['value']; childKeys.ExportNamedDeclaration = ['declaration', 'specifiers']; -function remove_node(code: MagicString, start: number, end: number, body: Node, node: Node) { +function remove_node( + code: MagicString, + start: number, + end: number, + body: Node, + node: Node +) { const i = body.indexOf(node); if (i === -1) throw new Error('node not in list'); @@ -97,7 +108,12 @@ export default class Component { node_for_declaration: Map = new Map(); partly_hoisted: string[] = []; fully_hoisted: string[] = []; - reactive_declarations: Array<{ assignees: Set; dependencies: Set; node: Node; declaration: Node }> = []; + reactive_declarations: Array<{ + assignees: Set; + dependencies: Set; + node: Node; + declaration: Node; + }> = []; reactive_declaration_nodes: Set = new Set(); has_reactive_assignments = false; injected_reactive_declaration_vars: Set = new Set(); @@ -110,7 +126,10 @@ export default class Component { locate: (c: number) => { line: number; column: number }; // TODO this does the same as component.locate! remove one or the other - locator: (search: number, startIndex?: number) => { + locator: ( + search: number, + startIndex?: number + ) => { line: number; column: number; }; @@ -140,27 +159,46 @@ export default class Component { this.source = source; this.compile_options = compile_options; - this.file = compile_options.filename && ( + this.file = + compile_options.filename && // eslint-disable-next-line no-useless-escape - typeof process !== 'undefined' ? compile_options.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : compile_options.filename - ); + (typeof process !== 'undefined' + ? compile_options.filename + .replace(process.cwd(), '') + .replace(/^[\/\\]/, '') + : compile_options.filename); this.locate = getLocator(this.source); this.code = new MagicString(source); // styles - this.stylesheet = new Stylesheet(source, ast, compile_options.filename, compile_options.dev); + this.stylesheet = new Stylesheet( + source, + ast, + compile_options.filename, + compile_options.dev + ); this.stylesheet.validate(this); - this.component_options = process_component_options(this, this.ast.html.children); - this.namespace = namespaces[this.component_options.namespace] || this.component_options.namespace; + this.component_options = process_component_options( + this, + this.ast.html.children + ); + this.namespace = + namespaces[this.component_options.namespace] || + this.component_options.namespace; if (compile_options.customElement) { - if (this.component_options.tag === undefined && compile_options.tag === undefined) { - const svelteOptions = ast.html.children.find(child => child.name === 'svelte:options') || { start: 0, end: 0 }; + if ( + this.component_options.tag === undefined && + compile_options.tag === undefined + ) { + const svelteOptions = ast.html.children.find( + child => child.name === 'svelte:options' + ) || { start: 0, end: 0 }; this.warn(svelteOptions, { code: 'custom-element-no-tag', - message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use ` + message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. . To hide this warning, use `, }); } this.tag = this.component_options.tag || compile_options.tag; @@ -195,7 +233,7 @@ export default class Component { this.add_var({ name, injected: true, - referenced: true + referenced: true, }); } else if (name[0] === '$') { this.add_var({ @@ -203,7 +241,7 @@ export default class Component { injected: true, referenced: true, mutated: true, - writable: true + writable: true, }); const subscribable_name = name.slice(1); @@ -253,35 +291,52 @@ export default class Component { const { compile_options, name } = this; const { format = 'esm' } = compile_options; - const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${"__VERSION__"} */`; + const banner = `/* ${ + this.file ? `${this.file} ` : `` + }generated by Svelte v${'__VERSION__'} */`; result = result .replace(/__svelte:self__/g, this.name) - .replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (_match: string, sigil: string, name: string) => { - if (sigil === '@') { - if (name[0] === '_') { - return this.global(name.slice(1)); - } + .replace( + compile_options.generate === 'ssr' + ? /(@+|#+)(\w*(?:-\w*)?)/g + : /(@+)(\w*(?:-\w*)?)/g, + (_match: string, sigil: string, name: string) => { + if (sigil === '@') { + if (name[0] === '_') { + return this.global(name.slice(1)); + } - if (!internal_exports.has(name)) { - throw new Error(`compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'`); - } + if (!internal_exports.has(name)) { + throw new Error( + `compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'` + ); + } + + if (compile_options.dev) { + if (internal_exports.has(`${name}_dev`)) name = `${name}_dev`; + else if (internal_exports.has(`${name}Dev`)) + name = `${name}Dev`; + } - if (compile_options.dev && internal_exports.has(`${name}Dev`)) { - name = `${name}Dev`; + return this.helper(name); } - return this.helper(name); + return sigil.slice(1) + name; } + ); - return sigil.slice(1) + name; - }); - - const referenced_globals = Array.from(this.globals, ([name, alias]) => name !== alias && ({ name, alias })).filter(Boolean); + const referenced_globals = Array.from( + this.globals, + ([name, alias]) => name !== alias && { name, alias } + ).filter(Boolean); if (referenced_globals.length) { this.helper('globals'); } - const imported_helpers = Array.from(this.helpers, ([name, alias]) => ({ name, alias })); + const imported_helpers = Array.from(this.helpers, ([name, alias]) => ({ + name, + alias, + })); const module = create_module( result, @@ -292,10 +347,12 @@ export default class Component { imported_helpers, referenced_globals, this.imports, - this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({ - name: variable.name, - as: variable.export_name - })), + this.vars + .filter(variable => variable.module && variable.export_name) + .map(variable => ({ + name: variable.name, + as: variable.export_name, + })), this.source ); @@ -339,16 +396,16 @@ export default class Component { add_string(final_chunk); - css = compile_options.customElement ? - { code: null, map: null } : - this.stylesheet.render(compile_options.cssOutputFilename, true); + css = compile_options.customElement + ? { code: null, map: null } + : this.stylesheet.render(compile_options.cssOutputFilename, true); js = { code: compiled.toString(), map: compiled.generateMap({ includeContent: true, file: compile_options.outputFilename, - }) + }), }; } @@ -357,17 +414,19 @@ export default class Component { css, ast: this.ast, warnings: this.warnings, - vars: this.vars.filter(v => !v.global && !v.internal).map(v => ({ - name: v.name, - export_name: v.export_name || null, - injected: v.injected || false, - module: v.module || false, - mutated: v.mutated || false, - reassigned: v.reassigned || false, - referenced: v.referenced || false, - writable: v.writable || false - })), - stats: this.stats.render() + vars: this.vars + .filter(v => !v.global && !v.internal) + .map(v => ({ + name: v.name, + export_name: v.export_name || null, + injected: v.injected || false, + module: v.module || false, + mutated: v.mutated || false, + reassigned: v.reassigned || false, + referenced: v.referenced || false, + writable: v.writable || false, + })), + stats: this.stats.render(), }; } @@ -402,8 +461,7 @@ export default class Component { let alias = name; for ( let i = 1; - this.used_names.has(alias) || - local_used_names.has(alias); + this.used_names.has(alias) || local_used_names.has(alias); alias = `${name}_${i++}` ); local_used_names.add(alias); @@ -428,7 +486,7 @@ export default class Component { source: this.source, start: pos.start, end: pos.end, - filename: this.compile_options.filename + filename: this.compile_options.filename, }); } @@ -459,7 +517,8 @@ export default class Component { end, pos: pos.start, filename: this.compile_options.filename, - toString: () => `${warning.message} (${start.line + 1}:${start.column})\n${frame}`, + toString: () => + `${warning.message} (${start.line + 1}:${start.column})\n${frame}`, }); } @@ -482,7 +541,7 @@ export default class Component { if (node.type === 'ExportDefaultDeclaration') { this.error(node, { code: `default-export`, - message: `A component cannot have a default export` + message: `A component cannot have a default export`, }); } @@ -490,7 +549,7 @@ export default class Component { if (node.source) { this.error(node, { code: `not-implemented`, - message: `A component currently cannot have an export ... from` + message: `A component currently cannot have an export ... from`, }); } if (node.declaration) { @@ -530,7 +589,8 @@ export default class Component { if (this.hoistable_nodes.has(node)) return false; if (this.reactive_declaration_nodes.has(node)) return false; if (node.type === 'ImportDeclaration') return false; - if (node.type === 'ExportDeclaration' && node.specifiers.length > 0) return false; + if (node.type === 'ExportDeclaration' && node.specifiers.length > 0) + return false; return true; }); @@ -543,8 +603,11 @@ export default class Component { let result = ''; - script.content.body.forEach((node) => { - if (this.hoistable_nodes.has(node) || this.reactive_declaration_nodes.has(node)) { + script.content.body.forEach(node => { + if ( + this.hoistable_nodes.has(node) || + this.reactive_declaration_nodes.has(node) + ) { if (a !== b) result += `[✂${a}-${b}✂]`; a = node.end; } @@ -572,10 +635,10 @@ export default class Component { if (node.type === 'LabeledStatement' && node.label.name === '$') { component.warn(node, { code: 'module-script-reactive-declaration', - message: '$: has no effect in a module script' + message: '$: has no effect in a module script', }); } - } + }, }); this.add_sourcemap_locations(script.content); @@ -587,7 +650,7 @@ export default class Component { if (name[0] === '$') { this.error(node, { code: 'illegal-declaration', - message: `The $ prefix is reserved, and cannot be used for variable and import names` + message: `The $ prefix is reserved, and cannot be used for variable and import names`, }); } @@ -595,7 +658,7 @@ export default class Component { name, module: true, hoistable: true, - writable: node.kind === 'var' || node.kind === 'let' + writable: node.kind === 'var' || node.kind === 'let', }); }); @@ -603,12 +666,12 @@ export default class Component { if (name[0] === '$') { this.error(node, { code: 'illegal-subscription', - message: `Cannot reference store value inside