UNPKG

@glimmer/compiler

Version:
1,600 lines (1,320 loc) 508 kB
define('@glimmer/compiler', ['exports', '@glimmer/syntax', '@glimmer/util'], function (exports, syntax, util) { 'use strict'; function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } var Template = /*#__PURE__*/function (_node$fields) { _inheritsLoose(Template, _node$fields); function Template() { return _node$fields.apply(this, arguments) || this; } return Template; }(syntax.node('Template').fields()); var InElement = /*#__PURE__*/function (_node$fields2) { _inheritsLoose(InElement, _node$fields2); function InElement() { return _node$fields2.apply(this, arguments) || this; } return InElement; }(syntax.node('InElement').fields()); var Not = /*#__PURE__*/function (_node$fields3) { _inheritsLoose(Not, _node$fields3); function Not() { return _node$fields3.apply(this, arguments) || this; } return Not; }(syntax.node('Not').fields()); var If = /*#__PURE__*/function (_node$fields4) { _inheritsLoose(If, _node$fields4); function If() { return _node$fields4.apply(this, arguments) || this; } return If; }(syntax.node('If').fields()); var IfInline = /*#__PURE__*/function (_node$fields5) { _inheritsLoose(IfInline, _node$fields5); function IfInline() { return _node$fields5.apply(this, arguments) || this; } return IfInline; }(syntax.node('IfInline').fields()); var Each = /*#__PURE__*/function (_node$fields6) { _inheritsLoose(Each, _node$fields6); function Each() { return _node$fields6.apply(this, arguments) || this; } return Each; }(syntax.node('Each').fields()); var With = /*#__PURE__*/function (_node$fields7) { _inheritsLoose(With, _node$fields7); function With() { return _node$fields7.apply(this, arguments) || this; } return With; }(syntax.node('With').fields()); var Let = /*#__PURE__*/function (_node$fields8) { _inheritsLoose(Let, _node$fields8); function Let() { return _node$fields8.apply(this, arguments) || this; } return Let; }(syntax.node('Let').fields()); var WithDynamicVars = /*#__PURE__*/function (_node$fields9) { _inheritsLoose(WithDynamicVars, _node$fields9); function WithDynamicVars() { return _node$fields9.apply(this, arguments) || this; } return WithDynamicVars; }(syntax.node('WithDynamicVars').fields()); var GetDynamicVar = /*#__PURE__*/function (_node$fields10) { _inheritsLoose(GetDynamicVar, _node$fields10); function GetDynamicVar() { return _node$fields10.apply(this, arguments) || this; } return GetDynamicVar; }(syntax.node('GetDynamicVar').fields()); var Log = /*#__PURE__*/function (_node$fields11) { _inheritsLoose(Log, _node$fields11); function Log() { return _node$fields11.apply(this, arguments) || this; } return Log; }(syntax.node('Log').fields()); var InvokeComponent = /*#__PURE__*/function (_node$fields12) { _inheritsLoose(InvokeComponent, _node$fields12); function InvokeComponent() { return _node$fields12.apply(this, arguments) || this; } return InvokeComponent; }(syntax.node('InvokeComponent').fields()); var NamedBlocks = /*#__PURE__*/function (_node$fields13) { _inheritsLoose(NamedBlocks, _node$fields13); function NamedBlocks() { return _node$fields13.apply(this, arguments) || this; } return NamedBlocks; }(syntax.node('NamedBlocks').fields()); var NamedBlock = /*#__PURE__*/function (_node$fields14) { _inheritsLoose(NamedBlock, _node$fields14); function NamedBlock() { return _node$fields14.apply(this, arguments) || this; } return NamedBlock; }(syntax.node('NamedBlock').fields()); var EndBlock = /*#__PURE__*/function (_node$fields15) { _inheritsLoose(EndBlock, _node$fields15); function EndBlock() { return _node$fields15.apply(this, arguments) || this; } return EndBlock; }(syntax.node('EndBlock').fields()); var AppendTrustedHTML = /*#__PURE__*/function (_node$fields16) { _inheritsLoose(AppendTrustedHTML, _node$fields16); function AppendTrustedHTML() { return _node$fields16.apply(this, arguments) || this; } return AppendTrustedHTML; }(syntax.node('AppendTrustedHTML').fields()); var AppendTextNode = /*#__PURE__*/function (_node$fields17) { _inheritsLoose(AppendTextNode, _node$fields17); function AppendTextNode() { return _node$fields17.apply(this, arguments) || this; } return AppendTextNode; }(syntax.node('AppendTextNode').fields()); var AppendComment = /*#__PURE__*/function (_node$fields18) { _inheritsLoose(AppendComment, _node$fields18); function AppendComment() { return _node$fields18.apply(this, arguments) || this; } return AppendComment; }(syntax.node('AppendComment').fields()); var Component = /*#__PURE__*/function (_node$fields19) { _inheritsLoose(Component, _node$fields19); function Component() { return _node$fields19.apply(this, arguments) || this; } return Component; }(syntax.node('Component').fields()); var StaticAttr = /*#__PURE__*/function (_node$fields20) { _inheritsLoose(StaticAttr, _node$fields20); function StaticAttr() { return _node$fields20.apply(this, arguments) || this; } return StaticAttr; }(syntax.node('StaticAttr').fields()); var DynamicAttr = /*#__PURE__*/function (_node$fields21) { _inheritsLoose(DynamicAttr, _node$fields21); function DynamicAttr() { return _node$fields21.apply(this, arguments) || this; } return DynamicAttr; }(syntax.node('DynamicAttr').fields()); var SimpleElement = /*#__PURE__*/function (_node$fields22) { _inheritsLoose(SimpleElement, _node$fields22); function SimpleElement() { return _node$fields22.apply(this, arguments) || this; } return SimpleElement; }(syntax.node('SimpleElement').fields()); var ElementParameters = /*#__PURE__*/function (_node$fields23) { _inheritsLoose(ElementParameters, _node$fields23); function ElementParameters() { return _node$fields23.apply(this, arguments) || this; } return ElementParameters; }(syntax.node('ElementParameters').fields()); var Yield = /*#__PURE__*/function (_node$fields24) { _inheritsLoose(Yield, _node$fields24); function Yield() { return _node$fields24.apply(this, arguments) || this; } return Yield; }(syntax.node('Yield').fields()); var Debugger = /*#__PURE__*/function (_node$fields25) { _inheritsLoose(Debugger, _node$fields25); function Debugger() { return _node$fields25.apply(this, arguments) || this; } return Debugger; }(syntax.node('Debugger').fields()); var CallExpression = /*#__PURE__*/function (_node$fields26) { _inheritsLoose(CallExpression, _node$fields26); function CallExpression() { return _node$fields26.apply(this, arguments) || this; } return CallExpression; }(syntax.node('CallExpression').fields()); var DeprecatedCallExpression = /*#__PURE__*/function (_node$fields27) { _inheritsLoose(DeprecatedCallExpression, _node$fields27); function DeprecatedCallExpression() { return _node$fields27.apply(this, arguments) || this; } return DeprecatedCallExpression; }(syntax.node('DeprecatedCallExpression').fields()); var Modifier = /*#__PURE__*/function (_node$fields28) { _inheritsLoose(Modifier, _node$fields28); function Modifier() { return _node$fields28.apply(this, arguments) || this; } return Modifier; }(syntax.node('Modifier').fields()); var InvokeBlock = /*#__PURE__*/function (_node$fields29) { _inheritsLoose(InvokeBlock, _node$fields29); function InvokeBlock() { return _node$fields29.apply(this, arguments) || this; } return InvokeBlock; }(syntax.node('InvokeBlock').fields()); var SplatAttr = /*#__PURE__*/function (_node$fields30) { _inheritsLoose(SplatAttr, _node$fields30); function SplatAttr() { return _node$fields30.apply(this, arguments) || this; } return SplatAttr; }(syntax.node('SplatAttr').fields()); var PathExpression = /*#__PURE__*/function (_node$fields31) { _inheritsLoose(PathExpression, _node$fields31); function PathExpression() { return _node$fields31.apply(this, arguments) || this; } return PathExpression; }(syntax.node('PathExpression').fields()); var GetWithResolver = /*#__PURE__*/function (_node$fields32) { _inheritsLoose(GetWithResolver, _node$fields32); function GetWithResolver() { return _node$fields32.apply(this, arguments) || this; } return GetWithResolver; }(syntax.node('GetWithResolver').fields()); var GetSymbol = /*#__PURE__*/function (_node$fields33) { _inheritsLoose(GetSymbol, _node$fields33); function GetSymbol() { return _node$fields33.apply(this, arguments) || this; } return GetSymbol; }(syntax.node('GetSymbol').fields()); var GetFreeWithContext = /*#__PURE__*/function (_node$fields34) { _inheritsLoose(GetFreeWithContext, _node$fields34); function GetFreeWithContext() { return _node$fields34.apply(this, arguments) || this; } return GetFreeWithContext; }(syntax.node('GetFreeWithContext').fields()); /** strict mode */ var GetFree = /*#__PURE__*/function (_node$fields35) { _inheritsLoose(GetFree, _node$fields35); function GetFree() { return _node$fields35.apply(this, arguments) || this; } return GetFree; }(syntax.node('GetFree').fields()); var Missing = /*#__PURE__*/function (_node$fields36) { _inheritsLoose(Missing, _node$fields36); function Missing() { return _node$fields36.apply(this, arguments) || this; } return Missing; }(syntax.node('Missing').fields()); var InterpolateExpression = /*#__PURE__*/function (_node$fields37) { _inheritsLoose(InterpolateExpression, _node$fields37); function InterpolateExpression() { return _node$fields37.apply(this, arguments) || this; } return InterpolateExpression; }(syntax.node('InterpolateExpression').fields()); var HasBlock = /*#__PURE__*/function (_node$fields38) { _inheritsLoose(HasBlock, _node$fields38); function HasBlock() { return _node$fields38.apply(this, arguments) || this; } return HasBlock; }(syntax.node('HasBlock').fields()); var HasBlockParams = /*#__PURE__*/function (_node$fields39) { _inheritsLoose(HasBlockParams, _node$fields39); function HasBlockParams() { return _node$fields39.apply(this, arguments) || this; } return HasBlockParams; }(syntax.node('HasBlockParams').fields()); var Curry = /*#__PURE__*/function (_node$fields40) { _inheritsLoose(Curry, _node$fields40); function Curry() { return _node$fields40.apply(this, arguments) || this; } return Curry; }(syntax.node('Curry').fields()); var Positional = /*#__PURE__*/function (_node$fields41) { _inheritsLoose(Positional, _node$fields41); function Positional() { return _node$fields41.apply(this, arguments) || this; } return Positional; }(syntax.node('Positional').fields()); var NamedArguments = /*#__PURE__*/function (_node$fields42) { _inheritsLoose(NamedArguments, _node$fields42); function NamedArguments() { return _node$fields42.apply(this, arguments) || this; } return NamedArguments; }(syntax.node('NamedArguments').fields()); var NamedArgument = /*#__PURE__*/function (_node$fields43) { _inheritsLoose(NamedArgument, _node$fields43); function NamedArgument() { return _node$fields43.apply(this, arguments) || this; } return NamedArgument; }(syntax.node('NamedArgument').fields()); var Args = /*#__PURE__*/function (_node$fields44) { _inheritsLoose(Args, _node$fields44); function Args() { return _node$fields44.apply(this, arguments) || this; } return Args; }(syntax.node('Args').fields()); var Tail = /*#__PURE__*/function (_node$fields45) { _inheritsLoose(Tail, _node$fields45); function Tail() { return _node$fields45.apply(this, arguments) || this; } return Tail; }(syntax.node('Tail').fields()); function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } var PresentList = /*#__PURE__*/function () { function PresentList(list) { this.list = list; } var _proto = PresentList.prototype; _proto.toArray = function toArray() { return this.list; }; _proto.map = function map(callback) { var result = util.mapPresent(this.list, callback); return new PresentList(result); }; _proto.filter = function filter(predicate) { var out = []; for (var _iterator = _createForOfIteratorHelperLoose(this.list), _step; !(_step = _iterator()).done;) { var item = _step.value; if (predicate(item)) { out.push(item); } } return OptionalList(out); }; _proto.toPresentArray = function toPresentArray() { return this.list; }; _proto.into = function into(_ref) { var ifPresent = _ref.ifPresent; return ifPresent(this); }; return PresentList; }(); var EmptyList = /*#__PURE__*/function () { function EmptyList() { this.list = []; } var _proto2 = EmptyList.prototype; _proto2.map = function map(_callback) { return new EmptyList(); }; _proto2.filter = function filter(_predicate) { return new EmptyList(); }; _proto2.toArray = function toArray() { return this.list; }; _proto2.toPresentArray = function toPresentArray() { return null; }; _proto2.into = function into(_ref2) { var ifEmpty = _ref2.ifEmpty; return ifEmpty(); }; return EmptyList; }(); // export type OptionalList<T> = PresentList<T> | EmptyList<T>; function OptionalList(value) { if (util.isPresent(value)) { return new PresentList(value); } else { return new EmptyList(); } } function _inheritsLoose$1(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } var ResultImpl = /*#__PURE__*/function () { function ResultImpl() {} ResultImpl.all = function all() { var out = []; for (var _len = arguments.length, results = new Array(_len), _key = 0; _key < _len; _key++) { results[_key] = arguments[_key]; } for (var _i = 0, _results = results; _i < _results.length; _i++) { var result = _results[_i]; if (result.isErr) { return result.cast(); } else { out.push(result.value); } } return Ok(out); }; return ResultImpl; }(); var Result = ResultImpl; var OkImpl = /*#__PURE__*/function (_ResultImpl) { _inheritsLoose$1(OkImpl, _ResultImpl); function OkImpl(value) { var _this; _this = _ResultImpl.call(this) || this; _this.value = value; _this.isOk = true; _this.isErr = false; return _this; } var _proto = OkImpl.prototype; _proto.expect = function expect(_message) { return this.value; }; _proto.ifOk = function ifOk(callback) { callback(this.value); return this; }; _proto.andThen = function andThen(callback) { return callback(this.value); }; _proto.mapOk = function mapOk(callback) { return Ok(callback(this.value)); }; _proto.ifErr = function ifErr(_callback) { return this; }; _proto.mapErr = function mapErr(_callback) { return this; }; return OkImpl; }(ResultImpl); var ErrImpl = /*#__PURE__*/function (_ResultImpl2) { _inheritsLoose$1(ErrImpl, _ResultImpl2); function ErrImpl(reason) { var _this2; _this2 = _ResultImpl2.call(this) || this; _this2.reason = reason; _this2.isOk = false; _this2.isErr = true; return _this2; } var _proto2 = ErrImpl.prototype; _proto2.expect = function expect(message) { throw new Error(message || 'expected an Ok, got Err'); }; _proto2.andThen = function andThen(_callback) { return this.cast(); }; _proto2.mapOk = function mapOk(_callback) { return this.cast(); }; _proto2.ifOk = function ifOk(_callback) { return this; }; _proto2.mapErr = function mapErr(callback) { return Err(callback(this.reason)); }; _proto2.ifErr = function ifErr(callback) { callback(this.reason); return this; }; _proto2.cast = function cast() { return this; }; return ErrImpl; }(ResultImpl); function Ok(value) { return new OkImpl(value); } function Err(reason) { return new ErrImpl(reason); } var ResultArray = /*#__PURE__*/function () { function ResultArray(items) { if (items === void 0) { items = []; } this.items = items; } var _proto4 = ResultArray.prototype; _proto4.add = function add(item) { this.items.push(item); }; _proto4.toArray = function toArray() { var err = this.items.filter(function (item) { return item instanceof ErrImpl; })[0]; if (err !== undefined) { return err.cast(); } else { return Ok(this.items.map(function (item) { return item.value; })); } }; _proto4.toOptionalList = function toOptionalList() { return this.toArray().mapOk(function (arr) { return OptionalList(arr); }); }; return ResultArray; }(); function _createForOfIteratorHelperLoose$1(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); } function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); } function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } var KeywordImpl = /*#__PURE__*/function () { function KeywordImpl(keyword, type, delegate) { this.keyword = keyword; this.delegate = delegate; var nodes = new Set(); for (var _iterator = _createForOfIteratorHelperLoose$1(KEYWORD_NODES[type]), _step; !(_step = _iterator()).done;) { var nodeType = _step.value; nodes.add(nodeType); } this.types = nodes; } var _proto = KeywordImpl.prototype; _proto.match = function match(node) { if (!this.types.has(node.type)) { return false; } var path = getCalleeExpression(node); if (path !== null && path.type === 'Path' && path.ref.type === 'Free') { if (path.tail.length > 0) { if (path.ref.resolution.serialize() === 'Loose') { // cannot be a keyword reference, keywords do not allow paths (must be // relying on implicit this fallback) return false; } } return path.ref.name === this.keyword; } else { return false; } }; _proto.translate = function translate(node, state) { var _this = this; if (this.match(node)) { var path = getCalleeExpression(node); if (path !== null && path.type === 'Path' && path.tail.length > 0) { return Err(syntax.generateSyntaxError("The `" + this.keyword + "` keyword was used incorrectly. It was used as `" + path.loc.asString() + "`, but it cannot be used with additional path segments. \n\nError caused by", node.loc)); } var param = this.delegate.assert(node, state); return param.andThen(function (param) { return _this.delegate.translate({ node: node, state: state }, param); }); } else { return null; } }; return KeywordImpl; }(); var KEYWORD_NODES = { Call: ['Call'], Block: ['InvokeBlock'], Append: ['AppendContent'], Modifier: ['ElementModifier'] }; function keyword(keyword, type, delegate) { return new KeywordImpl(keyword, type, delegate); } function getCalleeExpression(node) { switch (node.type) { // This covers the inside of attributes and expressions, as well as the callee // of call nodes case 'Path': return node; case 'AppendContent': return getCalleeExpression(node.value); case 'Call': case 'InvokeBlock': case 'ElementModifier': return node.callee; default: return null; } } var Keywords = /*#__PURE__*/function () { function Keywords(type) { this._keywords = []; this._type = type; } var _proto2 = Keywords.prototype; _proto2.kw = function kw(name, delegate) { this._keywords.push(keyword(name, this._type, delegate)); return this; }; _proto2.translate = function translate(node, state) { for (var _iterator2 = _createForOfIteratorHelperLoose$1(this._keywords), _step2; !(_step2 = _iterator2()).done;) { var _keyword = _step2.value; var result = _keyword.translate(node, state); if (result !== null) { return result; } } var path = getCalleeExpression(node); if (path && path.type === 'Path' && path.ref.type === 'Free' && syntax.isKeyword(path.ref.name)) { var name = path.ref.name; var usedType = this._type; var validTypes = syntax.KEYWORDS_TYPES[name]; if (validTypes.indexOf(usedType) === -1) { return Err(syntax.generateSyntaxError("The `" + name + "` keyword was used incorrectly. It was used as " + typesToReadableName[usedType] + ", but its valid usages are:\n\n" + generateTypesMessage(name, validTypes) + "\n\nError caused by", node.loc)); } } return null; }; return Keywords; }(); var typesToReadableName = { Append: 'an append statement', Block: 'a block statement', Call: 'a call expression', Modifier: 'a modifier' }; function generateTypesMessage(name, types) { return types.map(function (type) { switch (type) { case 'Append': return "- As an append statement, as in: {{" + name + "}}"; case 'Block': return "- As a block statement, as in: {{#" + name + "}}{{/" + name + "}}"; case 'Call': return "- As an expression, as in: (" + name + ")"; case 'Modifier': return "- As a modifier, as in: <div {{" + name + "}}></div>"; default: return util.exhausted(type); } }).join('\n\n'); } /** * This function builds keyword definitions for a particular type of AST node (`KeywordType`). * * You can build keyword definitions for: * * - `Expr`: A `SubExpression` or `PathExpression` * - `Block`: A `BlockStatement` * - A `BlockStatement` is a keyword candidate if its head is a * `PathExpression` * - `Append`: An `AppendStatement` * * A node is a keyword candidate if: * * - A `PathExpression` is a keyword candidate if it has no tail, and its * head expression is a `LocalVarHead` or `FreeVarHead` whose name is * the keyword's name. * - A `SubExpression`, `AppendStatement`, or `BlockStatement` is a keyword * candidate if its head is a keyword candidate. * * The keyword infrastructure guarantees that: * * - If a node is not a keyword candidate, it is never passed to any keyword's * `assert` method. * - If a node is not the `KeywordType` for a particular keyword, it will not * be passed to the keyword's `assert` method. * * `Expr` keywords are used in expression positions and should return HIR * expressions. `Block` and `Append` keywords are used in statement * positions and should return HIR statements. * * A keyword definition has two parts: * * - `match`, which determines whether an AST node matches the keyword, and can * optionally return some information extracted from the AST node. * - `translate`, which takes a matching AST node as well as the extracted * information and returns an appropriate HIR instruction. * * # Example * * This keyword: * * - turns `(hello)` into `"hello"` * - as long as `hello` is not in scope * - makes it an error to pass any arguments (such as `(hello world)`) * * ```ts * keywords('SubExpr').kw('hello', { * assert(node: ExprKeywordNode): Result<void> | false { * // we don't want to transform `hello` as a `PathExpression` * if (node.type !== 'SubExpression') { * return false; * } * * // node.head would be `LocalVarHead` if `hello` was in scope * if (node.head.type !== 'FreeVarHead') { * return false; * } * * if (node.params.length || node.hash) { * return Err(generateSyntaxError(`(hello) does not take any arguments`), node.loc); * } else { * return Ok(); * } * }, * * translate(node: ASTv2.SubExpression): hir.Expression { * return ASTv2.builders.literal("hello", node.loc) * } * }) * ``` * * The keyword infrastructure checks to make sure that the node is the right * type before calling `assert`, so you only need to consider `SubExpression` * and `PathExpression` here. It also checks to make sure that the node passed * to `assert` has the keyword name in the right place. * * Note the important difference between returning `false` from `assert`, * which just means that the node didn't match, and returning `Err`, which * means that the node matched, but there was a keyword-specific syntax * error. */ function keywords(type) { return new Keywords(type); } function hasPath(node) { return node.callee.type === 'Path'; } function isHelperInvocation(node) { if (!hasPath(node)) { return false; } return !node.args.isEmpty(); } function isSimplePath(path) { if (path.type === 'Path') { var head = path.ref, parts = path.tail; return head.type === 'Free' && head.resolution !== syntax.ASTv2.STRICT_RESOLUTION && parts.length === 0; } else { return false; } } function isStrictHelper(expr) { if (expr.callee.type !== 'Path') { return true; } if (expr.callee.ref.type !== 'Free') { return true; } return expr.callee.ref.resolution === syntax.ASTv2.STRICT_RESOLUTION; } function assertIsValidModifier(helper) { if (isStrictHelper(helper) || isSimplePath(helper.callee)) { return; } throw syntax.generateSyntaxError("`" + printPath(helper.callee) + "` is not a valid name for a modifier", helper.loc); } function printPath(path) { switch (path.type) { case 'Literal': return JSON.stringify(path.value); case 'Path': { var printedPath = [printPathHead(path.ref)]; printedPath.push.apply(printedPath, path.tail.map(function (t) { return t.chars; })); return printedPath.join('.'); } case 'Call': return "(" + printPath(path.callee) + " ...)"; case 'DeprecatedCall': return "" + path.callee.name; case 'Interpolate': throw util.unreachable('a concat statement cannot appear as the head of an expression'); } } function printPathHead(head) { switch (head.type) { case 'Arg': return head.name.chars; case 'Free': case 'Local': return head.name; case 'This': return 'this'; } } var NormalizeExpressions = /*#__PURE__*/function () { function NormalizeExpressions() {} var _proto = NormalizeExpressions.prototype; _proto.visit = function visit(node, state) { switch (node.type) { case 'Literal': return Ok(this.Literal(node)); case 'Interpolate': return this.Interpolate(node, state); case 'Path': return this.PathExpression(node); case 'Call': var translated = CALL_KEYWORDS.translate(node, state); if (translated !== null) { return translated; } return this.CallExpression(node, state); case 'DeprecatedCall': return this.DeprecaedCallExpression(node, state); } }; _proto.visitList = function visitList(nodes, state) { return new ResultArray(nodes.map(function (e) { return VISIT_EXPRS.visit(e, state); })).toOptionalList(); } /** * Normalize paths into `hir.Path` or a `hir.Expr` that corresponds to the ref. * * TODO since keywords don't support tails anyway, distinguish PathExpression from * VariableReference in ASTv2. */ ; _proto.PathExpression = function PathExpression$1(path) { var ref = this.VariableReference(path.ref); var tail = path.tail; if (util.isPresent(tail)) { var tailLoc = tail[0].loc.extend(tail[tail.length - 1].loc); return Ok(new PathExpression({ loc: path.loc, head: ref, tail: new Tail({ loc: tailLoc, members: tail }) })); } else { return Ok(ref); } }; _proto.VariableReference = function VariableReference(ref) { return ref; }; _proto.Literal = function Literal(literal) { return literal; }; _proto.Interpolate = function Interpolate(expr, state) { var parts = expr.parts.map(convertPathToCallIfKeyword); return VISIT_EXPRS.visitList(parts, state).mapOk(function (parts) { return new InterpolateExpression({ loc: expr.loc, parts: parts }); }); }; _proto.CallExpression = function CallExpression$1(expr, state) { if (!hasPath(expr)) { throw new Error("unimplemented subexpression at the head of a subexpression"); } else { return Result.all(VISIT_EXPRS.visit(expr.callee, state), VISIT_EXPRS.Args(expr.args, state)).mapOk(function (_ref) { var callee = _ref[0], args = _ref[1]; return new CallExpression({ loc: expr.loc, callee: callee, args: args }); }); } }; _proto.DeprecaedCallExpression = function DeprecaedCallExpression(_ref2, _state) { var arg = _ref2.arg, callee = _ref2.callee, loc = _ref2.loc; return Ok(new DeprecatedCallExpression({ loc: loc, arg: arg, callee: callee })); }; _proto.Args = function Args$1(_ref3, state) { var positional = _ref3.positional, named = _ref3.named, loc = _ref3.loc; return Result.all(this.Positional(positional, state), this.NamedArguments(named, state)).mapOk(function (_ref4) { var positional = _ref4[0], named = _ref4[1]; return new Args({ loc: loc, positional: positional, named: named }); }); }; _proto.Positional = function Positional$1(positional, state) { return VISIT_EXPRS.visitList(positional.exprs, state).mapOk(function (list) { return new Positional({ loc: positional.loc, list: list }); }); }; _proto.NamedArguments = function NamedArguments$1(named, state) { var pairs = named.entries.map(function (arg) { var value = convertPathToCallIfKeyword(arg.value); return VISIT_EXPRS.visit(value, state).mapOk(function (value) { return new NamedArgument({ loc: arg.loc, key: arg.name, value: value }); }); }); return new ResultArray(pairs).toOptionalList().mapOk(function (pairs) { return new NamedArguments({ loc: named.loc, entries: pairs }); }); }; return NormalizeExpressions; }(); function convertPathToCallIfKeyword(path) { if (path.type === 'Path' && path.ref.type === 'Free' && path.ref.name in syntax.KEYWORDS_TYPES) { return new syntax.ASTv2.CallExpression({ callee: path, args: syntax.ASTv2.Args.empty(path.loc), loc: path.loc }); } return path; } var VISIT_EXPRS = new NormalizeExpressions(); var _CurriedTypeToReadabl; var CurriedTypeToReadableType = (_CurriedTypeToReadabl = {}, _CurriedTypeToReadabl[0 /* Component */ ] = 'component', _CurriedTypeToReadabl[1 /* Helper */ ] = 'helper', _CurriedTypeToReadabl[2 /* Modifier */ ] = 'modifier', _CurriedTypeToReadabl); function assertCurryKeyword(curriedType) { return function (node, state) { var readableType = CurriedTypeToReadableType[curriedType]; var stringsAllowed = curriedType === 0 /* Component */ ; var args = node.args; var definition = args.nth(0); if (definition === null) { return Err(syntax.generateSyntaxError("(" + readableType + ") requires a " + readableType + " definition or identifier as its first positional parameter, did not receive any parameters.", args.loc)); } if (definition.type === 'Literal') { if (stringsAllowed && state.isStrict) { return Err(syntax.generateSyntaxError("(" + readableType + ") cannot resolve string values in strict mode templates", node.loc)); } else if (!stringsAllowed) { return Err(syntax.generateSyntaxError("(" + readableType + ") cannot resolve string values, you must pass a " + readableType + " definition directly", node.loc)); } } args = new syntax.ASTv2.Args({ positional: new syntax.ASTv2.PositionalArguments({ exprs: args.positional.exprs.slice(1), loc: args.positional.loc }), named: args.named, loc: args.loc }); return Ok({ definition: definition, args: args }); }; } function translateCurryKeyword(curriedType) { return function (_ref, _ref2) { var node = _ref.node, state = _ref.state; var definition = _ref2.definition, args = _ref2.args; var definitionResult = VISIT_EXPRS.visit(definition, state); var argsResult = VISIT_EXPRS.Args(args, state); return Result.all(definitionResult, argsResult).mapOk(function (_ref3) { var definition = _ref3[0], args = _ref3[1]; return new Curry({ loc: node.loc, curriedType: curriedType, definition: definition, args: args }); }); }; } function curryKeyword(curriedType) { return { assert: assertCurryKeyword(curriedType), translate: translateCurryKeyword(curriedType) }; } function assertGetDynamicVarKeyword(node) { var call = node.type === 'AppendContent' ? node.value : node; var named = call.type === 'Call' ? call.args.named : null; var positionals = call.type === 'Call' ? call.args.positional : null; if (named && !named.isEmpty()) { return Err(syntax.generateSyntaxError("(-get-dynamic-vars) does not take any named arguments", node.loc)); } var varName = positionals === null || positionals === void 0 ? void 0 : positionals.nth(0); if (!varName) { return Err(syntax.generateSyntaxError("(-get-dynamic-vars) requires a var name to get", node.loc)); } if (positionals && positionals.size > 1) { return Err(syntax.generateSyntaxError("(-get-dynamic-vars) only receives one positional arg", node.loc)); } return Ok(varName); } function translateGetDynamicVarKeyword(_ref, name) { var node = _ref.node, state = _ref.state; return VISIT_EXPRS.visit(name, state).mapOk(function (name) { return new GetDynamicVar({ name: name, loc: node.loc }); }); } var getDynamicVarKeyword = { assert: assertGetDynamicVarKeyword, translate: translateGetDynamicVarKeyword }; function assertHasBlockKeyword(type) { return function (node) { var call = node.type === 'AppendContent' ? node.value : node; var named = call.type === 'Call' ? call.args.named : null; var positionals = call.type === 'Call' ? call.args.positional : null; if (named && !named.isEmpty()) { return Err(syntax.generateSyntaxError("(" + type + ") does not take any named arguments", call.loc)); } if (!positionals || positionals.isEmpty()) { return Ok(syntax.SourceSlice.synthetic('default')); } else if (positionals.exprs.length === 1) { var positional = positionals.exprs[0]; if (syntax.ASTv2.isLiteral(positional, 'string')) { return Ok(positional.toSlice()); } else { return Err(syntax.generateSyntaxError("(" + type + ") can only receive a string literal as its first argument", call.loc)); } } else { return Err(syntax.generateSyntaxError("(" + type + ") only takes a single positional argument", call.loc)); } }; } function translateHasBlockKeyword(type) { return function (_ref, target) { var node = _ref.node, scope = _ref.state.scope; var block = type === 'has-block' ? new HasBlock({ loc: node.loc, target: target, symbol: scope.allocateBlock(target.chars) }) : new HasBlockParams({ loc: node.loc, target: target, symbol: scope.allocateBlock(target.chars) }); return Ok(block); }; } function hasBlockKeyword(type) { return { assert: assertHasBlockKeyword(type), translate: translateHasBlockKeyword(type) }; } function assertIfUnlessInlineKeyword(type) { return function (originalNode) { var _a; var inverted = type === 'unless'; var node = originalNode.type === 'AppendContent' ? originalNode.value : originalNode; var named = node.type === 'Call' ? node.args.named : null; var positional = node.type === 'Call' ? node.args.positional : null; if (named && !named.isEmpty()) { return Err(syntax.generateSyntaxError("(" + type + ") cannot receive named parameters, received " + named.entries.map(function (e) { return e.name.chars; }).join(', '), originalNode.loc)); } var condition = positional === null || positional === void 0 ? void 0 : positional.nth(0); if (!positional || !condition) { return Err(syntax.generateSyntaxError("When used inline, (" + type + ") requires at least two parameters 1. the condition that determines the state of the (" + type + "), and 2. the value to return if the condition is " + (inverted ? 'false' : 'true') + ". Did not receive any parameters", originalNode.loc)); } var truthy = positional.nth(1); var falsy = positional.nth(2); if (truthy === null) { return Err(syntax.generateSyntaxError("When used inline, (" + type + ") requires at least two parameters 1. the condition that determines the state of the (" + type + "), and 2. the value to return if the condition is " + (inverted ? 'false' : 'true') + ". Received only one parameter, the condition", originalNode.loc)); } if (positional.size > 3) { return Err(syntax.generateSyntaxError("When used inline, (" + type + ") can receive a maximum of three positional parameters 1. the condition that determines the state of the (" + type + "), 2. the value to return if the condition is " + (inverted ? 'false' : 'true') + ", and 3. the value to return if the condition is " + (inverted ? 'true' : 'false') + ". Received " + ((_a = positional === null || positional === void 0 ? void 0 : positional.size) !== null && _a !== void 0 ? _a : 0) + " parameters", originalNode.loc)); } return Ok({ condition: condition, truthy: truthy, falsy: falsy }); }; } function translateIfUnlessInlineKeyword(type) { var inverted = type === 'unless'; return function (_ref, _ref2) { var node = _ref.node, state = _ref.state; var condition = _ref2.condition, truthy = _ref2.truthy, falsy = _ref2.falsy; var conditionResult = VISIT_EXPRS.visit(condition, state); var truthyResult = VISIT_EXPRS.visit(truthy, state); var falsyResult = falsy ? VISIT_EXPRS.visit(falsy, state) : Ok(null); return Result.all(conditionResult, truthyResult, falsyResult).mapOk(function (_ref3) { var condition = _ref3[0], truthy = _ref3[1], falsy = _ref3[2]; if (inverted) { condition = new Not({ value: condition, loc: node.loc }); } return new IfInline({ loc: node.loc, condition: condition, truthy: truthy, falsy: falsy }); }); }; } function ifUnlessInlineKeyword(type) { return { assert: assertIfUnlessInlineKeyword(type), translate: translateIfUnlessInlineKeyword(type) }; } function assertLogKeyword(node) { var _node$args = node.args, named = _node$args.named, positional = _node$args.positional; if (named && !named.isEmpty()) { return Err(syntax.generateSyntaxError("(log) does not take any named arguments", node.loc)); } return Ok(positional); } function translateLogKeyword(_ref, positional) { var node = _ref.node, state = _ref.state; return VISIT_EXPRS.Positional(positional, state).mapOk(function (positional) { return new Log({ positional: positional, loc: node.loc }); }); } var logKeyword = { assert: assertLogKeyword, translate: translateLogKeyword }; var CALL_KEYWORDS = keywords('Call').kw('has-block', hasBlockKeyword('has-block')).kw('has-block-params', hasBlockKeyword('has-block-params')).kw('-get-dynamic-var', getDynamicVarKeyword).kw('log', logKeyword).kw('if', ifUnlessInlineKeyword('if')).kw('unless', ifUnlessInlineKeyword('unless')).kw('component', curryKeyword(0 /* Component */ )).kw('helper', curryKeyword(1 /* Helper */ )).kw('modifier', curryKeyword(2 /* Modifier */ )); function toAppend(_ref) { var assert = _ref.assert, _translate = _ref.translate; return { assert: assert, translate: function translate(_ref2, value) { var node = _ref2.node, state = _ref2.state; var result = _translate({ node: node, state: state }, value); return result.mapOk(function (text) { return new AppendTextNode({ text: text, loc: node.loc }); }); } }; } var APPEND_KEYWORDS = keywords('Append').kw('has-block', toAppend(hasBlockKeyword('has-block'))).kw('has-block-params', toAppend(hasBlockKeyword('has-block-params'))).kw('-get-dynamic-var', toAppend(getDynamicVarKeyword)).kw('log', toAppend(logKeyword)).kw('if', toAppend(ifUnlessInlineKeyword('if'))).kw('unless', toAppend(ifUnlessInlineKeyword('unless'))).kw('yield', { assert: function assert(node) { var args = node.args; if (args.named.isEmpty()) { return Ok({ target: syntax.SourceSpan.synthetic('default').toSlice(), positional: args.positional }); } else { var target = args.named.get('to'); if (args.named.size > 1 || target === null) { return Err(syntax.generateSyntaxError("yield only takes a single named argument: 'to'", args.named.loc)); } if (syntax.ASTv2.isLiteral(target, 'string')) { return Ok({ target: target.toSlice(), positional: args.positional }); } else { return Err(syntax.generateSyntaxError("you can only yield to a literal string value", target.loc)); } } }, translate: function translate(_ref, _ref2) { var node = _ref.node, state = _ref.state; var target = _ref2.target, positional = _ref2.positional; return VISIT_EXPRS.Positional(positional, state).mapOk(function (positional) { return new Yield({ loc: node.loc, target: target, to: state.scope.allocateBlock(target.chars), positional: positional }); }); } }).kw('debugger', { assert: function assert(node) { var args = node.args; var positional = args.positional; if (args.isEmpty()) { return Ok(undefined); } else { if (positional.isEmpty()) { return Err(syntax.generateSyntaxError("debugger does not take any named arguments", node.loc)); } else { return Err(syntax.generateSyntaxError("debugger does not take any positional arguments", node.loc)); } } }, translate: function translate(_ref3) { var node = _ref3.node, scope = _ref3.state.scope; scope.setHasEval(); return Ok(new Debugger({ loc: node.loc, scope: scope })); } }).kw('component', { assert: assertCurryKeyword(0 /* Component */ ), translate: function translate(_ref4, _ref5) { var node = _ref4.node, state = _ref4.state; var definition = _ref5.definition, args = _ref5.args; var definitionResult = VISIT_EXPRS.visit(definition, state); var argsResult = VISIT_EXPRS.Args(args, state); return Result.all(definitionResult, argsResult).mapOk(function (_ref6) { var definition = _ref6[0], args = _ref6[1]; return new InvokeComponent({ loc: node.loc, definition: definition, args: args, blocks: null }); }); } }).kw('helper', { assert: assertCurryKeyword(1 /* Helper */ ), translate: function translate(_ref7, _ref8) { var node = _ref7.node, state = _ref7.state; var definition = _ref8.definition, args = _ref8.args; var definitionResult = VISIT_EXPRS.visit(definition, state); var argsResult = VISIT_EXPRS.Args(args, state); return Result.all(definitionResult, argsResult).mapOk(function (_ref9) { var definition = _ref9[0], args = _ref9[1]; var text = new CallExpression({ callee: definition, args: args, loc: node.loc }); return new AppendTextNode({ loc: node.loc, text: text }); }); } }); var BLOCK_KEYWORDS = keywords('Block').kw('in-element', { assert: function assert(node) { var args = node.args; var guid = args.get('guid'); if (guid) { return Err(syntax.generateSyntaxError("Cannot pass `guid` to `{{#in-element}}`", guid.loc)); } var insertBefore = args.get('insertBefore'); var destination = args.nth(0); if (destination === null) { return Err(syntax.generateSyntaxError("{{#in-element}} requires a target element as its first positional parameter", args.loc)); } // TODO Better syntax checks return Ok({ insertBefore: insertBefore, destination: destination }); }, translate: function translate(_ref, _ref2) { var node = _ref.node, state = _ref.state; var insertBefore = _ref2.insertBefore, destination = _ref2.destination; var named = node.blocks.get('default'); var body = VISIT_STMTS.NamedBlock(named, state); var destinationResult = VISIT_EXPRS.visit(destination, state); return Result.all(body,