marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
309 lines (252 loc) • 9.08 kB
JavaScript
"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 = [];
}