UNPKG

marko

Version:

UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.

309 lines (252 loc) • 9.08 kB
"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");exports.__esModule = true;exports.default = void 0;var _compiler = require("@marko/compiler"); var _babelUtils = require("@marko/compiler/babel-utils"); var _path = _interopRequireDefault(require("path")); var _keyManager = require("../util/key-manager"); var _optimizeVdomCreate = require("../util/optimize-vdom-create"); var _pluginHooks = require("../util/plugin-hooks"); var _attribute = _interopRequireDefault(require("./attribute")); var _attributeTag = _interopRequireWildcard(require("./attribute-tag")); var _customTag = _interopRequireDefault(require("./custom-tag")); var _dynamicTag = _interopRequireDefault(require("./dynamic-tag")); var _macroTag = _interopRequireDefault(require("./macro-tag")); var _nativeTag = _interopRequireDefault(require("./native-tag"));function _interopRequireWildcard(e, t) {if ("function" == typeof WeakMap) var r = new WeakMap(),n = new WeakMap();return (_interopRequireWildcard = function (e, t) {if (!t && e && e.__esModule) return e;var o,i,f = { __proto__: null, default: e };if (null === e || "object" != typeof e && "function" != typeof e) return f;if (o = t ? n : r) {if (o.has(e)) return o.get(e);o.set(e, f);}for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]);return f;})(e, t);}var _default = exports.default = { enter(path) { const tagDef = (0, _babelUtils.getTagDef)(path); if (tagDef && tagDef.translator) { const { node } = path; (0, _pluginHooks.enter)(tagDef.translator.hook, path, _compiler.types); if (path.node !== node) { return; } } (0, _babelUtils.assertNoVar)(path); for (const attr of path.get("attributes")) { if (attr.isMarkoAttribute()) { const { node } = path; _attribute.default.enter(attr); if (path.node !== node) { return; } } } if (!(0, _babelUtils.isAttributeTag)(path)) { if ( !tagDef && path.hub.file.markoOpts.ignoreUnrecognizedTags && ( path.node.attributeTags.length || path.node.body.attributeTags) && !(0, _babelUtils.isDynamicTag)(path)) { moveIgnoredAttrTags(path); } if ((0, _babelUtils.isNativeTag)(path)) { if (tagDef && tagDef.name === "body") { path. get("body"). pushContainer("body", [ _compiler.types.markoTag( _compiler.types.stringLiteral("init-components"), [], _compiler.types.markoTagBody() ), _compiler.types.markoTag( _compiler.types.stringLiteral("await-reorderer"), [], _compiler.types.markoTagBody() ), _compiler.types.markoTag( _compiler.types.stringLiteral("_preferred-script-location"), [], _compiler.types.markoTagBody() )] ); } } else if (!(0, _babelUtils.isMacroTag)(path)) { (0, _attributeTag.analyzeAttributeTags)(path); } (0, _keyManager.getKeyManager)(path).resolveKey(path); } (0, _optimizeVdomCreate.optimizeStaticVDOM)(path); }, exit(path) { let isUnknownDynamic = false; let isDynamicNullable = false; if ((0, _babelUtils.isDynamicTag)(path)) { const name = path.get("name"); const types = findDynamicTagTypes(name); if (types && !(types.string && types.component)) { if (!name.isIdentifier()) { const tagIdentifier = path.scope.generateUidIdentifier(`tagName`); path.insertBefore( _compiler.types.variableDeclaration("const", [ _compiler.types.variableDeclarator(tagIdentifier, name.node)] ) ); name.replaceWith(tagIdentifier); } isDynamicNullable = types.empty; path.node._isDynamicString = types.string; } else { isUnknownDynamic = true; } } for (const attr of path.get("attributes")) { if (attr.isMarkoAttribute()) { const { node } = path; _attribute.default.exit(attr); if (path.node !== node) { return; } } } if (isUnknownDynamic) { return (0, _dynamicTag.default)(path); } if ((0, _babelUtils.isAttributeTag)(path)) { return (0, _attributeTag.default)(path); } if ((0, _babelUtils.isMacroTag)(path)) { return (0, _macroTag.default)(path); } const tagDef = (0, _babelUtils.getTagDef)(path); if (tagDef && tagDef.translator) { const { node } = path; (0, _pluginHooks.exit)(tagDef.translator.hook, path, _compiler.types); if (path.node !== node) { return; } } if ((0, _babelUtils.isNativeTag)(path)) { return (0, _nativeTag.default)(path, isDynamicNullable); } else { return (0, _customTag.default)(path, isDynamicNullable); } } }; const HANDLE_BINDINGS = ["module", "var", "let", "const"]; function findDynamicTagTypes(root) { const pending = [root]; const types = { string: false, empty: false, component: false }; let tagNameImported; let path; while (path = pending.pop()) { switch (path.type) { case "ConditionalExpression": pending.push(path.get("consequent")); if (path.get("alternate").node) { pending.push(path.get("alternate")); } break; case "LogicalExpression": if (path.get("operator").node === "||") { pending.push(path.get("left")); } else { types.empty = true; } pending.push(path.get("right")); break; case "AssignmentExpression": pending.push(path.get("right")); break; case "BinaryExpression": if (path.get("operator").node !== "+") { return false; } types.string = true; break; case "StringLiteral": case "TemplateLiteral": types.string = true; break; case "NullLiteral": types.empty = true; break; case "Identifier": if (path.get("name").node === "undefined") { types.empty = true; } else { const binding = path.scope.getBinding(path.node.name); if (!binding || !HANDLE_BINDINGS.includes(binding.kind)) { return false; } if (binding.kind === "module") { const importSource = binding.path.parent.source; if ( _compiler.types.isStringLiteral(importSource) && isMarkoFile(importSource.value)) { const resolvedImport = (0, _babelUtils.resolveTagImport)(root.parentPath, importSource.value) || importSource.value; if (tagNameImported === undefined) { tagNameImported = resolvedImport; } else if ( tagNameImported && tagNameImported !== resolvedImport) { tagNameImported = null; } types.component = true; } else { return false; } } else { const initialValue = binding.path.get("init"); if (initialValue.node) { pending.push(initialValue); } else { types.empty = true; } const assignments = binding.constantViolations; if (assignments && assignments.length) { for (const assignment of assignments) { const operator = assignment.get("operator").node; if (operator === "=") { pending.push(assignment.get("right")); } else if (operator === "+=") { types.string = true; } else { return false; } } } } } break; default: return false; } } if (tagNameImported && !types.string) { (root.parent.extra ??= {}).tagNameImported = tagNameImported; } return types; } function isMarkoFile(request) { return _path.default.extname(request) === ".marko" || /^<.*>$/.test(request); } function moveIgnoredAttrTags(parentTag) { const attrTags = parentTag.node.body.attributeTags ? parentTag.get("body").get("body") : parentTag.get("attributeTags"); if (!attrTags.length) return; for (const attrTag of attrTags) { if (attrTag.isMarkoTag()) { if ((0, _babelUtils.isAttributeTag)(attrTag)) { attrTag.set( "name", _compiler.types.stringLiteral(`at_${attrTag.get("name.value").node.slice(1)}`) ); } moveIgnoredAttrTags(attrTag); } } parentTag.node.body.body = parentTag.node.attributeTags.concat( parentTag.node.body.body ); parentTag.node.attributeTags = []; }