UNPKG

marko

Version:

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

149 lines (120 loc) 4.04 kB
"use strict";exports.__esModule = true;exports.analyzeAttributeTags = analyzeAttributeTags;exports.default = translateAttributeTag;var _compiler = require("@marko/compiler"); var _babelUtils = require("@marko/compiler/babel-utils"); var _util = require("./util"); const attributeTagsForTag = new WeakMap(); const contentTypeCache = new WeakMap(); const ContentType = { attribute: 0, render: 1, mixed: 2 }; function analyzeAttributeTags(rootTag) { const visit = [rootTag]; const parentTags = [rootTag]; let i = 0; let attributeTags; while (i < visit.length) { const tag = visit[i++]; const attrTags = tag.node.body.attributeTags ? tag.get("body").get("body") : tag.get("attributeTags"); for (const child of attrTags) { if ((0, _babelUtils.isAttributeTag)(child)) { (0, _babelUtils.assertNoArgs)(child); const tagDef = (0, _babelUtils.getTagDef)(child) || {}; const name = (0, _babelUtils.getFullyResolvedTagName)(child); let { targetProperty = child.node.name.value.slice(1), isRepeated = false } = tagDef; const preserveName = tagDef.preserveName === true || tagDef.removeDashes === false; if (!preserveName) { targetProperty = removeDashes(targetProperty); } const attrTagMeta = (attributeTags ||= {})[name] ||= { targetProperty, isRepeated }; (child.node.extra ||= {}).attributeTag = attrTagMeta; const parentTag = (0, _babelUtils.findParentTag)(child); const parentTagExtra = parentTag.node.extra ||= {}; const parentSeenAttributeTagProperties = attributeTagsForTag.get(parentTag); let hasAttributeTags = false; if (!parentSeenAttributeTagProperties) { parentTagExtra.hasAttributeTags = true; attributeTagsForTag.set(parentTag, new Set([targetProperty])); } else if (parentSeenAttributeTagProperties.has(targetProperty)) { hasAttributeTags = true; } else { parentSeenAttributeTagProperties.add(targetProperty); } if (!hasAttributeTags) { if ( parentTag. get("attributes"). some( (attr) => attr.isMarkoSpreadAttribute() || attr.node.name === targetProperty )) { parentTag.pushContainer( "attributes", _compiler.types.markoAttribute( targetProperty, _compiler.types.unaryExpression("void", _compiler.types.numericLiteral(0)) ) ); } } parentTags.push(child); visit.push(child); } else if ((0, _babelUtils.isTransparentTag)(child)) { visit.push(child); } } } if (attributeTags) { (rootTag.node.extra ??= {}).attributeTags = attributeTags; } } function translateAttributeTag(tag) { const { node } = tag; const meta = node.extra?.attributeTag; if (!meta) { throw tag. get("name"). buildCodeFrameError("@tags must be nested within another element."); } (0, _babelUtils.assertNoArgs)(tag); tag.replaceWith( _compiler.types.expressionStatement( _compiler.types.callExpression( (0, _babelUtils.importNamed)( tag.hub.file, "marko/src/runtime/helpers/attr-tag.js", meta.isRepeated ? "r" : "a", meta.isRepeated ? "marko_repeated_attr_tag" : "marko_repeatable_attr_tag" ), [_compiler.types.stringLiteral(meta.targetProperty), getAttrTagObject(tag)] ) ) ); } function getAttrTagObject(tag) { const attrs = (0, _util.getAttrs)(tag, false, true); if (_compiler.types.isNullLiteral(attrs)) { return _compiler.types.objectExpression([]); } return attrs; } function removeDashes(str) { return str.replace(/-([a-z])/g, matchToUpperCase); } function matchToUpperCase(_match, lower) { return lower.toUpperCase(); }