Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 51 additions & 27 deletions packages/babel-plugin-wallace/src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@
import * as t from "@babel/types";
import { wallaceConfig, FlagValue } from "./config";
import { ERROR_MESSAGES, error } from "./errors";
import { Directive, TagNode, NodeValue, Qualifier } from "./models";
import {
Directive,
TagNode,
NodeValue,
Qualifier,
ValueMode,
QualifierMode
} from "./models";
import {
WATCH_CALLBACK_ARGS,
SPECIAL_SYMBOLS,
Expand All @@ -19,8 +26,8 @@ import {

class ApplyDirective extends Directive {
static attributeName = "apply";
static allowNull = true;
static allowString = false;
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
static mayAccessElement = true;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.addWatch(SPECIAL_SYMBOLS.noLookup, value.expression);
Expand All @@ -29,16 +36,17 @@ class ApplyDirective extends Directive {

class BindDirective extends Directive {
static attributeName = "bind";
static allowQualifier = true;
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.Optional;
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, _base: string) {
node.setBindInstruction(value.expression, qualifier);
}
}

class ClassDirective extends Directive {
static attributeName = "class";
static allowString = true;
static allowQualifier = true;
static valueMode: ValueMode = ValueMode.EitherRequired;
static qualifierMode: QualifierMode = QualifierMode.Optional;
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, base: string) {
if (qualifier) {
node.addClassToggleTarget(
Expand All @@ -58,6 +66,8 @@ class ClassDirective extends Directive {

class CssDirective extends Directive {
static attributeName = "css";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
static mayAccessComponent = false;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.addStaticAttribute("class", value.expression);
Expand All @@ -66,6 +76,8 @@ class CssDirective extends Directive {

class CtrlDirective extends Directive {
static attributeName = "ctrl";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
static allowOnNested = true;
static allowOnRepeated = true;
static allowOnNormalElement = false;
Expand Down Expand Up @@ -96,9 +108,8 @@ class ValueAsDateDirective extends Directive {

class EventDirective extends Directive {
static attributeName = "event";
static allowExpression = false;
static allowNull = true;
static requireQualifier = true;
static valueMode: ValueMode = ValueMode.StringRequired;
static qualifierMode: QualifierMode = QualifierMode.SetsValue;
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, _base: string) {
const eventName = qualifier || value.value;
if (!DOM_EVENTS_LOWERCASE.includes(eventName)) {
Expand All @@ -110,7 +121,8 @@ class EventDirective extends Directive {

class FixedDirective extends Directive {
static attributeName = "fixed";
static requireQualifier = true;
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.Required;
static mayAccessComponent = false;
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, _base: string) {
node.addStaticAttribute(qualifier, value.expression);
Expand All @@ -119,20 +131,26 @@ class FixedDirective extends Directive {

class HideDirective extends Directive {
static attributeName = "hide";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.setVisibilityToggle(value.expression, true, false);
}
}

class HtmlDirective extends Directive {
static attributeName = "html";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.watchAttribute("innerHTML", value.expression);
}
}

class IfDirective extends Directive {
static attributeName = "if";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
static allowOnNested = true;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.setVisibilityToggle(value.expression, false, true);
Expand All @@ -141,17 +159,20 @@ class IfDirective extends Directive {

class KeyDirective extends Directive {
static attributeName = "key";
static allowString = true;
static valueMode: ValueMode = ValueMode.EitherRequired;
static qualifierMode: QualifierMode = QualifierMode.SetsValue;
static allowOnRepeated = true;
static allowOnNormalElement = false;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.setRepeatKey(value.expression || value.value);
}
}

// TODO: change to be on:click
class OnEventDirective extends Directive {
static attributeName = "on*";
static allowString = true;
static valueMode: ValueMode = ValueMode.EitherRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
static mayAccessElement = true;
static mayAccessEvent = true;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, base: string) {
Expand All @@ -165,19 +186,20 @@ class OnEventDirective extends Directive {

class PartDirective extends Directive {
static attributeName = "part";
static valueMode: ValueMode = ValueMode.StringRequired;
static qualifierMode: QualifierMode = QualifierMode.SetsValue;
static allowOnNested = true;
static allowOnRepeated = true;
static allowNull = true;
static allowExpression = false;
static requireQualifier = true;
apply(node: TagNode, _value: NodeValue, qualifier: Qualifier, _base: string) {
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, _base: string) {
wallaceConfig.ensureFlagIstrue(node.path, FlagValue.allowParts);
node.setPart(qualifier);
node.setPart(qualifier || value.value);
}
}

class PropsDirective extends Directive {
static attributeName = "props";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
static allowOnNested = true;
static allowOnRepeated = true;
static allowOnNormalElement = false;
Expand All @@ -188,26 +210,27 @@ class PropsDirective extends Directive {

class RefDirective extends Directive {
static attributeName = "ref";
static valueMode: ValueMode = ValueMode.StringRequired;
static qualifierMode: QualifierMode = QualifierMode.SetsValue;
static allowOnNested = true;
static allowNull = true;
static allowExpression = false;
static requireQualifier = true;
apply(node: TagNode, _value: NodeValue, qualifier: Qualifier, _base: string) {
node.setRef(qualifier);
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, _base: string) {
node.setRef(qualifier || value.value);
}
}

class ShowDirective extends Directive {
static attributeName = "show";
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
apply(node: TagNode, value: NodeValue, _qualifier: Qualifier, _base: string) {
node.setVisibilityToggle(value.expression, false, false);
}
}

class StyleDirective extends Directive {
static attributeName = "style";
static allowString = true;
static allowQualifier = true;
static valueMode: ValueMode = ValueMode.EitherRequired;
static qualifierMode: QualifierMode = QualifierMode.Optional;
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, base: string) {
if (qualifier) {
if (value.type === "string") {
Expand All @@ -230,7 +253,8 @@ class StyleDirective extends Directive {

class ToggleDirective extends Directive {
static attributeName = "toggle";
static requireQualifier = true;
static valueMode: ValueMode = ValueMode.ExpressionRequired;
static qualifierMode: QualifierMode = QualifierMode.Required;
apply(node: TagNode, value: NodeValue, qualifier: Qualifier, _base: string) {
if (!qualifier) {
throw new Error("Toggle must have a qualifier");
Expand All @@ -241,8 +265,8 @@ class ToggleDirective extends Directive {

class UniqueDirective extends Directive {
static attributeName = "unique";
static allowExpression = false;
static allowNull = true;
static valueMode: ValueMode = ValueMode.NotAllowed;
static qualifierMode: QualifierMode = QualifierMode.NotAllowed;
apply(node: TagNode, _value: NodeValue, _qualifier: Qualifier, _base: string) {
node.component.unique = true;
}
Expand Down
32 changes: 20 additions & 12 deletions packages/babel-plugin-wallace/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,38 @@ export const ERROR_MESSAGES = {
CLASS_METHOD_MUST_BE_PROPERTY_JSX:
"Function returning JSX in a class must be assigned to property 'jsx'",
CAPITALISED_COMPONENT_NAME: "Component name must be capitalized.",
// TODO: remove
CANNOT_USE_IF_ON_ROOT_ELEMENT: "Cannot use `if` directive on root element.",
CANNOT_USE_DIRECTIVE_ON_NESTED_ELEMENT: (directive: string) => {
DIRECTIVE_NOT_ALLOWED_ON_NESTED_ELEMENT: (directive: string) => {
return `The \`${directive}\` directive may not be used on nested elements.`;
},
CANNOT_USE_DIRECTIVE_ON_REPEATED_ELEMENT: (directive: string) => {
DIRECTIVE_NOT_ALLOWED_ON_REPEATED_ELEMENT: (directive: string) => {
return `The \`${directive}\` directive may not be used on repeated elements.`;
},
CANNOT_USE_DIRECTIVE_WITHOUT_QUALIFIER: (directive: string) => {
DIRECTIVE_ALREADY_DEFINED: (directive: string) => {
return `The \`${directive}\` directive has already been defined on this node.`;
},
DIRECTIVE_REQUIRES_QUALIFIER: (directive: string) => {
return `The \`${directive}\` directive must have a qualifier.`;
},
CANNOT_USE_DIRECTIVE_WITH_QUALIFIER: (directive: string) => {
DIRECTIVE_DISALLOWS_QUALIFIER: (directive: string) => {
return `The \`${directive}\` directive may not have a qualifier.`;
},
DIRECTIVE_ALREADY_DEFINED: (directive: string) => {
return `The \`${directive}\` directive has already been defined on this node.`;
},
DIRECTIVE_MAY_NOT_ACCESS_SCOPE_VAR: (directive: string, name: string) => {
return `The \`${directive}\` directive may not access scoped variable \`${name}\`.`;
},
DIRECTIVE_REQUIRES_QUALIFIER_OR_VALUE: (directive: string) => {
return `The \`${directive}\` directive requires a qualifier or value, not both.`;
},
DIRECTIVE_EITHER_VALUE_REQUIRED: (directive: string) => {
return `The \`${directive}\` directive requires a value.`;
},
DIRECTIVE_VALUE_REQUIRED: (type: string, directive: string) => {
return `The \`${directive}\` directive requires a value of type \`${type}\`.`;
},
DIRECTIVE_NO_VALUE_ALLOWED: (directive: string) => {
return `The \`${directive}\` directive does not allow a value.`;
},
EVENT_USED_WITHOUT_BIND:
"The `event` directive must be used with the `bind` directive.",
FLAG_REQUIRED: (flag: string) => {
Expand All @@ -43,11 +56,6 @@ export const ERROR_MESSAGES = {
INVALID_EVENT_NAME: (event: string) =>
`\`${event}\` is not a valid event. Must be lowercase without \`on\` prefix. E.g. \`event:keyup\`.`,
NESTED_COMPONENT_MUST_BE_CAPTIALIZED: "Nested component must be capitalized.",
DIRECTIVE_INVALID_TYPE: (directive: string, allowed: string[], actual: string) => {
return allowed.length
? `The \`${directive}\` directive value must be of type ${allowed.join(" or ")}. Found: ${actual}.`
: `The \`${directive}\` directive value must be of type ${allowed[0]}. Found: ${actual}.`;
},
PLACEHOLDER_MAY_NOT_BE_LITERAL_OBJECT:
"Literal objects in placeholders not allowed as they will become constants.",
JSX_ELEMENTS_NOT_ALLOWED_IN_EXPRESSIONS: "JSX elements are not allowed in expressions.",
Expand Down
9 changes: 3 additions & 6 deletions packages/babel-plugin-wallace/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import "source-map-support/register.js"; // Ensures correct line numbers in stack traces.

import * as constants from "./constants";
import { wallaceConfig } from "./config";
import { Directive, NodeValue } from "./models";
export { wallaceConfig } from "./config";
export { Directive, NodeValue, QualifierMode, ValueMode } from "./models";
import { wallacePlugin } from "./visitors/main";

export default wallacePlugin;
/**
* These exports are for custom plugin development.
*/
export { wallaceConfig, Directive, NodeValue, constants };
export { constants };
Loading
Loading