Added types to Node subclasses (#5755)

pull/5822/head
Andreas Ehrencrona 5 years ago committed by GitHub
parent 68538c61eb
commit 9d9d7bc355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,8 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
export default class Action extends Node {
type: 'Action';
@ -8,7 +10,7 @@ export default class Action extends Node {
expression: Expression;
uses_context: boolean;
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
const object = info.name.split('.')[0];

@ -1,13 +1,17 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Element from './Element';
import EachBlock from './EachBlock';
export default class Animation extends Node {
type: 'Animation';
name: string;
expression: Expression;
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Element, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
component.warn_if_undefined(info.name, info, scope);
@ -31,7 +35,7 @@ export default class Animation extends Node {
});
}
block.has_animation = true;
(block as EachBlock).has_animation = true;
this.expression = info.expression
? new Expression(component, this, scope, info.expression, true)

@ -7,6 +7,7 @@ import Text from './Text';
import Expression from './shared/Expression';
import TemplateScope from './shared/TemplateScope';
import { x } from 'code-red';
import { TemplateNode } from '../../interfaces';
export default class Attribute extends Node {
type: 'Attribute' | 'Spread';
@ -24,7 +25,7 @@ export default class Attribute extends Node {
chunks: Array<Text | Expression>;
dependencies: Set<string>;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.scope = scope;

@ -23,7 +23,7 @@ export default class AwaitBlock extends Node {
then: ThenBlock;
catch: CatchBlock;
constructor(component: Component, parent, scope: TemplateScope, info: TemplateNode) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.expression = new Expression(component, this, scope, info.expression);

@ -5,6 +5,10 @@ import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import {dimensions} from '../../utils/patterns';
import { Node as ESTreeNode } from 'estree';
import { TemplateNode } from '../../interfaces';
import Element from './Element';
import InlineComponent from './InlineComponent';
import Window from './Window';
// TODO this should live in a specific binding
const read_only_media_attributes = new Set([
@ -26,7 +30,7 @@ export default class Binding extends Node {
is_contextual: boolean;
is_readonly: boolean;
constructor(component: Component, parent, scope: TemplateScope, info) {
constructor(component: Component, parent: Element | InlineComponent | Window, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
if (info.expression.type !== 'Identifier' && info.expression.type !== 'MemberExpression') {
@ -68,7 +72,7 @@ export default class Binding extends Node {
const variable = component.var_lookup.get(name);
if (!variable || variable.global) {
component.error(this.expression.node, {
component.error(this.expression.node as any, {
code: 'binding-undeclared',
message: `${name} is not declared`
});
@ -77,7 +81,7 @@ export default class Binding extends Node {
variable[this.expression.node.type === 'MemberExpression' ? 'mutated' : 'reassigned'] = true;
if (info.expression.type === 'Identifier' && !variable.writable) {
component.error(this.expression.node, {
component.error(this.expression.node as any, {
code: 'invalid-binding',
message: 'Cannot bind to a variable which is not writable'
});
@ -86,14 +90,18 @@ export default class Binding extends Node {
const type = parent.get_static_attribute_value('type');
this.is_readonly = (
this.is_readonly =
dimensions.test(this.name) ||
(parent.is_media_node && parent.is_media_node() && read_only_media_attributes.has(this.name)) ||
(parent.name === 'input' && type === 'file') // TODO others?
);
(isElement(parent) &&
((parent.is_media_node() && read_only_media_attributes.has(this.name)) ||
(parent.name === 'input' && type === 'file')) /* TODO others? */);
}
is_readonly_media_attribute() {
return read_only_media_attributes.has(this.name);
}
}
function isElement(node: Node): node is Element {
return !!(node as any).is_media_node;
}

@ -1,16 +1,19 @@
import Node from './shared/Node';
import EventHandler from './EventHandler';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
export default class Body extends Node {
type: 'Body';
handlers: EventHandler[];
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.handlers = [];
info.attributes.forEach(node => {
info.attributes.forEach((node: Node) => {
if (node.type === 'EventHandler') {
this.handlers.push(new EventHandler(component, this, scope, node));
} else {

@ -1,12 +1,15 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import { TemplateNode } from '../../interfaces';
import TemplateScope from './shared/TemplateScope';
import Component from '../Component';
export default class Class extends Node {
type: 'Class';
name: string;
expression: Expression;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.name = info.name;

@ -1,4 +1,7 @@
import { TemplateNode } from '../../interfaces';
import Component from '../Component';
import Node from './shared/Node';
import TemplateScope from './shared/TemplateScope';
const pattern = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m;
@ -7,7 +10,7 @@ export default class Comment extends Node {
data: string;
ignores: string[];
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.data = info.data;

@ -1,14 +1,19 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import { INode } from './interfaces';
import { Node as EsTreeNode } from 'estree';
export default class DebugTag extends Node {
type: 'DebugTag';
expressions: Expression[];
constructor(component, parent, scope, info) {
constructor(component: Component, parent: INode, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.expressions = info.identifiers.map(node => {
this.expressions = info.identifiers.map((node: EsTreeNode) => {
return new Expression(component, parent, scope, node);
});
}

@ -6,6 +6,8 @@ import AbstractBlock from './shared/AbstractBlock';
import Element from './Element';
import { Context, unpack_destructuring } from './shared/Context';
import { Node } from 'estree';
import Component from '../Component';
import { TemplateNode } from '../../interfaces';
export default class EachBlock extends AbstractBlock {
type: 'EachBlock';
@ -25,7 +27,7 @@ export default class EachBlock extends AbstractBlock {
else?: ElseBlock;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.expression = new Expression(component, this, scope, info.expression);

@ -125,11 +125,11 @@ export default class Element extends Node {
namespace: string;
needs_manual_style_scoping: boolean;
constructor(component: Component, parent, scope, info: any) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: any) {
super(component, parent, scope, info);
this.name = info.name;
this.namespace = get_namespace(parent, this, component.namespace);
this.namespace = get_namespace(parent as Element, this, component.namespace);
if (this.name === 'textarea') {
if (info.children.length > 0) {
@ -850,7 +850,7 @@ export default class Element extends Node {
type: 'Text',
data: ` ${id}`,
synthetic: true
})
} as any)
);
}
} else {
@ -859,7 +859,7 @@ export default class Element extends Node {
type: 'Attribute',
name: 'class',
value: [{ type: 'Text', data: id, synthetic: true }]
})
} as any)
);
}
}

@ -1,11 +1,14 @@
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Node from './shared/Node';
export default class ElseBlock extends AbstractBlock {
type: 'ElseBlock';
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.children = map_children(component, this, scope, info.children);

@ -3,6 +3,8 @@ import Expression from './shared/Expression';
import Component from '../Component';
import { sanitize } from '../../utils/names';
import { Identifier } from 'estree';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
export default class EventHandler extends Node {
type: 'EventHandler';
@ -13,7 +15,7 @@ export default class EventHandler extends Node {
uses_context = false;
can_make_passive = false;
constructor(component: Component, parent, template_scope, info) {
constructor(component: Component, parent: Node, template_scope: TemplateScope, info: TemplateNode) {
super(component, parent, template_scope, info);
this.name = info.name;

@ -4,6 +4,7 @@ import map_children from './shared/map_children';
import Block from '../render_dom/Block';
import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces';
import { TemplateNode } from '../../interfaces';
export default class Fragment extends Node {
type: 'Fragment';
@ -11,7 +12,7 @@ export default class Fragment extends Node {
children: INode[];
scope: TemplateScope;
constructor(component: Component, info: any) {
constructor(component: Component, info: TemplateNode) {
const scope = new TemplateScope();
super(component, null, scope, info);

@ -1,13 +1,16 @@
import Node from './shared/Node';
import map_children from './shared/map_children';
import hash from '../utils/hash';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
export default class Head extends Node {
type: 'Head';
children: any[]; // TODO
id: string;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
if (info.attributes.length) {

@ -2,13 +2,17 @@ import ElseBlock from './ElseBlock';
import Expression from './shared/Expression';
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Node from './shared/Node';
export default class IfBlock extends AbstractBlock {
type: 'IfBlock';
expression: Expression;
else: ElseBlock;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.expression = new Expression(component, this, scope, info.expression);

@ -8,6 +8,7 @@ import Component from '../Component';
import Let from './Let';
import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces';
import { TemplateNode } from '../../interfaces';
export default class InlineComponent extends Node {
type: 'InlineComponent';
@ -20,7 +21,7 @@ export default class InlineComponent extends Node {
children: INode[];
scope: TemplateScope;
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
if (info.name !== 'svelte:component' && info.name !== 'svelte:self') {

@ -1,13 +1,17 @@
import Expression from './shared/Expression';
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Node from './shared/Node';
export default class KeyBlock extends AbstractBlock {
type: 'KeyBlock';
expression: Expression;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.expression = new Expression(component, this, scope, info.expression);

@ -2,6 +2,8 @@ import Node from './shared/Node';
import Component from '../Component';
import { walk } from 'estree-walker';
import { BasePattern, Identifier } from 'estree';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
const applicable = new Set(['Identifier', 'ObjectExpression', 'ArrayExpression', 'Property']);
@ -11,7 +13,7 @@ export default class Let extends Node {
value: Identifier;
names: string[] = [];
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.name = { type: 'Identifier', name: info.name };

@ -1,9 +1,13 @@
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Node from './shared/Node';
export default class PendingBlock extends AbstractBlock {
type: 'PendingBlock';
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.children = map_children(component, parent, scope, info.children);

@ -3,6 +3,7 @@ import Attribute from './Attribute';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces';
import { TemplateNode } from '../../interfaces';
export default class Slot extends Element {
type: 'Element';
@ -11,7 +12,7 @@ export default class Slot extends Element {
slot_name: string;
values: Map<string, Attribute> = new Map();
constructor(component: Component, parent: INode, scope: TemplateScope, info: any) {
constructor(component: Component, parent: INode, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
info.attributes.forEach(attr => {

@ -2,6 +2,7 @@ import Node from './shared/Node';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces';
import { TemplateNode } from '../../interfaces';
// Whitespace inside one of these elements will not result in
// a whitespace node being created in any circumstances. (This
@ -20,7 +21,7 @@ export default class Text extends Node {
data: string;
synthetic: boolean;
constructor(component: Component, parent: INode, scope: TemplateScope, info: any) {
constructor(component: Component, parent: INode, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.data = info.data;
this.synthetic = info.synthetic || false;

@ -1,13 +1,15 @@
import Node from './shared/Node';
import map_children, { Children } from './shared/map_children';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
export default class Title extends Node {
type: 'Title';
children: Children;
should_cache: boolean;
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.children = map_children(component, parent, scope, info.children);

@ -1,6 +1,9 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Element from './Element';
export default class Transition extends Node {
type: 'Transition';
@ -9,7 +12,7 @@ export default class Transition extends Node {
expression: Expression;
is_local: boolean;
constructor(component: Component, parent, scope, info) {
constructor(component: Component, parent: Element, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
component.warn_if_undefined(info.name, info, scope);

@ -5,6 +5,9 @@ import flatten_reference from '../utils/flatten_reference';
import fuzzymatch from '../../utils/fuzzymatch';
import list from '../../utils/list';
import Action from './Action';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
const valid_bindings = [
'innerWidth',
@ -22,7 +25,7 @@ export default class Window extends Node {
bindings: Binding[] = [];
actions: Action[] = [];
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
info.attributes.forEach(node => {

@ -22,7 +22,7 @@ export default class Expression {
type: 'Expression' = 'Expression';
component: Component;
owner: Owner;
node: any;
node: Node;
references: Set<string> = new Set();
dependencies: Set<string> = new Set();
contextual_dependencies: Set<string> = new Set();
@ -36,7 +36,7 @@ export default class Expression {
manipulated: Node;
constructor(component: Component, owner: Owner, template_scope: TemplateScope, info, lazy?: boolean) {
constructor(component: Component, owner: Owner, template_scope: TemplateScope, info: Node, lazy?: boolean) {
// TODO revert to direct property access in prod?
Object.defineProperties(this, {
component: {
@ -314,7 +314,7 @@ export default class Expression {
block.renderer.add_to_context(func_id.name, true);
// rename #ctx -> child_ctx;
walk(func_expression, {
enter(node) {
enter(node: Node) {
if (node.type === 'Identifier' && node.name === '#ctx') {
node.name = 'child_ctx';
}

@ -2,6 +2,7 @@ import Attribute from '../Attribute';
import Component from '../../Component';
import { INode } from '../interfaces';
import Text from '../Text';
import { TemplateNode } from '../../../interfaces';
export default class Node {
readonly start: number;
@ -17,7 +18,7 @@ export default class Node {
var: string;
attributes: Attribute[];
constructor(component: Component, parent, _scope, info: any) {
constructor(component: Component, parent: Node, _scope, info: TemplateNode) {
this.start = info.start;
this.end = info.end;
this.type = info.type;

@ -56,12 +56,12 @@ export default class DebugTagWrapper extends Wrapper {
const contextual_identifiers = this.node.expressions
.filter(e => {
const variable = var_lookup.get(e.node.name);
const variable = var_lookup.get((e.node as Identifier).name);
return !(variable && variable.hoistable);
})
.map(e => e.node.name);
.map(e => (e.node as Identifier).name);
const logged_identifiers = this.node.expressions.map(e => p`${e.node.name}`);
const logged_identifiers = this.node.expressions.map(e => p`${(e.node as Identifier).name}`);
const debug_statements = b`
${contextual_identifiers.map(name => b`const ${name} = ${renderer.reference(name)};`)}

@ -57,8 +57,8 @@ export default class EachBlockWrapper extends Wrapper {
get_each_context: Identifier;
iterations: Identifier;
fixed_length: number;
data_length: string;
view_length: string;
data_length: Node|number;
view_length: Node|number;
}
context_props: Array<Node | Node[]>;

@ -52,12 +52,15 @@ export default class WindowWrapper extends Wrapper {
add_event_handlers(block, '@_window', this.handlers);
this.node.bindings.forEach(binding => {
// TODO: what if it's a MemberExpression?
const binding_name = (binding.expression.node as Identifier).name;
// in dev mode, throw if read-only values are written to
if (readonly.has(binding.name)) {
renderer.readonly.add(binding.expression.node.name);
renderer.readonly.add(binding_name);
}
bindings[binding.name] = binding.expression.node.name;
bindings[binding.name] = binding_name;
// bind:online is a special case, we need to listen for two separate events
if (binding.name === 'online') return;
@ -67,7 +70,7 @@ export default class WindowWrapper extends Wrapper {
if (!events[associated_event]) events[associated_event] = [];
events[associated_event].push({
name: binding.expression.node.name,
name: binding_name,
value: property
});
});

@ -1,6 +1,7 @@
import DebugTag from '../../nodes/DebugTag';
import Renderer, { RenderOptions } from '../Renderer';
import { x, p } from 'code-red';
import { Identifier } from 'estree';
export default function(node: DebugTag, renderer: Renderer, options: RenderOptions) {
if (!options.dev) return;
@ -9,7 +10,7 @@ export default function(node: DebugTag, renderer: Renderer, options: RenderOptio
const { line, column } = options.locate(node.start + 1);
const obj = x`{
${node.expressions.map(e => p`${e.node.name}`)}
${node.expressions.map(e => p`${(e.node as Identifier).name}`)}
}`;
renderer.add_expression(x`@debug(${filename ? x`"${filename}"` : x`null`}, ${line - 1}, ${column}, ${obj})`);

@ -1,6 +1,7 @@
import Renderer, { RenderOptions } from '../Renderer';
import RawMustacheTag from '../../nodes/RawMustacheTag';
import { Expression } from 'estree';
export default function(node: RawMustacheTag, renderer: Renderer, _options: RenderOptions) {
renderer.add_expression(node.expression.node);
renderer.add_expression(node.expression.node as Expression);
}

Loading…
Cancel
Save