|
|
|
@ -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;
|
|
|
|
|
}
|
|
|
|
|