Skip to content

Commit

Permalink
Merge pull request #353 from ryansolid/next
Browse files Browse the repository at this point in the history
0.39.0 Updates
  • Loading branch information
ryansolid authored Sep 23, 2024
2 parents 3d451a9 + 0b23f00 commit 2c8a9b1
Show file tree
Hide file tree
Showing 35 changed files with 1,411 additions and 247 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Archive production artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: dist-folder
path: |
Expand Down
2 changes: 2 additions & 0 deletions packages/babel-plugin-jsx-dom-expressions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/types": "^7.20.7",
"html-entities": "2.3.3",
"jest-diff": "^29.7.0",
"jsdom": "^25.0.0",
"validate-html-nesting": "^1.2.1"
},
"peerDependencies": {
Expand Down
111 changes: 101 additions & 10 deletions packages/babel-plugin-jsx-dom-expressions/src/dom/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,19 @@ export function transformElement(path, info) {
config = getConfig(path),
wrapSVG = info.topLevel && tagName != "svg" && SVGElements.has(tagName),
voidTag = VoidElements.indexOf(tagName) > -1,
isCustomElement = tagName.indexOf("-") > -1 || !!path.get("openingElement").get("attributes").find(a => a.node.name?.name === "is"),
isCustomElement = tagName.indexOf("-") > -1 || path.get("openingElement").get("attributes").some(a => a.node?.name?.name === "is" || a.name?.name === "is"),
isImportNode = (tagName === 'img'||tagName === 'iframe') && path.get("openingElement").get("attributes").some(a => a.node.name?.name === "loading" && a.node.value?.value === "lazy"
),
results = {
template: `<${tagName}`,
templateWithClosingTags: `<${tagName}`,
declarations: [],
exprs: [],
dynamics: [],
postExprs: [],
isSVG: wrapSVG,
hasCustomElement: isCustomElement,
isImportNode,
tagName,
renderer: "dom",
skipTemplate: false
Expand All @@ -95,13 +99,17 @@ export function transformElement(path, info) {
return results;
}
}
if (wrapSVG) results.template = "<svg>" + results.template;
if (wrapSVG) {
results.template = "<svg>" + results.template;
results.templateWithClosingTags = "<svg>" + results.templateWithClosingTags;
}
if (!info.skipId) results.id = path.scope.generateUidIdentifier("el$");
transformAttributes(path, results);
if (config.contextToCustomElements && (tagName === "slot" || isCustomElement)) {
contextToCustomElement(path, results);
}
results.template += ">";
results.templateWithClosingTags += ">";
if (!voidTag) {
// always close tags can still be skipped if they have no closing parents and are the last element
const toBeClosed =
Expand All @@ -114,6 +122,7 @@ export function transformElement(path, info) {
} else results.toBeClosed = info.toBeClosed;
if (tagName !== "noscript") transformChildren(path, results, config);
if (toBeClosed) results.template += `</${tagName}>`;
results.templateWithClosingTags += `</${tagName}>`;
}
if (info.topLevel && config.hydratable && results.hasHydratableEvent) {
let runHydrationEvents = registerImportMethod(
Expand All @@ -123,7 +132,10 @@ export function transformElement(path, info) {
);
results.postExprs.push(t.expressionStatement(t.callExpression(runHydrationEvents, [])));
}
if (wrapSVG) results.template += "</svg>";
if (wrapSVG) {
results.template += "</svg>";
results.templateWithClosingTags += "</svg>";
}
return results;
}

Expand Down Expand Up @@ -216,6 +228,13 @@ export function setAttr(path, elem, name, value, { isSVG, dynamic, prevId, isCE,
return t.assignmentExpression("=", t.memberExpression(elem, t.identifier("data")), value);
}

if(namespace === 'bool') {
return t.callExpression(
registerImportMethod(path, "setBoolAttribute", getRendererConfig(path, "dom").moduleName),
[elem, t.stringLiteral(name), value]
);
}

const isChildProp = ChildProperties.has(name);
const isProp = Properties.has(name);
const alias = getPropAlias(name, tagName.toUpperCase());
Expand Down Expand Up @@ -270,7 +289,7 @@ function transformAttributes(path, results) {
attributes = path.get("openingElement").get("attributes");
const tagName = getTagName(path.node),
isSVG = SVGElements.has(tagName),
isCE = tagName.includes("-"),
isCE = tagName.includes("-") || attributes.some(a => a.node.name?.name === 'is'),
hasChildren = path.node.children.length > 0,
config = getConfig(path);

Expand Down Expand Up @@ -542,15 +561,29 @@ function transformAttributes(path, results) {
children = value;
} else if (key.startsWith("on")) {
const ev = toEventName(key);
if (key.startsWith("on:") || key.startsWith("oncapture:")) {
const listenerOptions = [t.stringLiteral(key.split(":")[1]), value.expression];
if (key.startsWith("on:")) {
const args = [elem, t.stringLiteral(key.split(":")[1]), value.expression];

results.exprs.unshift(
t.expressionStatement(
t.callExpression(
registerImportMethod(
path,
"addEventListener",
getRendererConfig(path, "dom").moduleName,
),
args,
),
),
);
} else if (key.startsWith("oncapture:")) {
// deprecated see above condition
const args = [t.stringLiteral(key.split(":")[1]), value.expression, t.booleanLiteral(true)];
results.exprs.push(
t.expressionStatement(
t.callExpression(
t.memberExpression(elem, t.identifier("addEventListener")),
key.startsWith("oncapture:")
? listenerOptions.concat(t.booleanLiteral(true))
: listenerOptions
args
)
)
);
Expand Down Expand Up @@ -697,6 +730,54 @@ function transformAttributes(path, results) {
isCE,
tagName
});
} else if(key.slice(0, 5) === 'bool:'){

// inline it on the template when possible
let content = value;

if (t.isJSXExpressionContainer(content)) content = content.expression;

function addBoolAttribute() {
results.template += `${needsSpacing ? " " : ""}${key.slice(5)}`;
needsSpacing = true;
}

switch (content.type) {
case "StringLiteral": {
if (content.value.length && content.value !== "0") {
addBoolAttribute();
}
return;
}
case "NullLiteral": {
return;
}
case "BooleanLiteral": {
if (content.value) {
addBoolAttribute();
}
return;
}
case "Identifier": {
if (content.name === "undefined") {
return;
}
break;
}
}

// when not possible to inline it in the template
results.exprs.push(
t.expressionStatement(
setAttr(
attribute,
elem,
key,
t.isJSXExpressionContainer(value) ? value.expression : value,
{ isSVG, isCE, tagName },
),
),
);
} else {
results.exprs.push(
t.expressionStatement(
Expand All @@ -718,6 +799,7 @@ function transformAttributes(path, results) {
} else {
!isSVG && (key = key.toLowerCase());
results.template += `${needsSpacing ? ' ' : ''}${key}`;
results.templateWithClosingTags += `${needsSpacing ? ' ' : ''}${key}`;
if (!value) {
needsSpacing = true;
return;
Expand All @@ -737,6 +819,7 @@ function transformAttributes(path, results) {
if (!text.length) {
needsSpacing = false;
results.template += `=""`;
results.templateWithClosingTags += `=""`;
return;
}

Expand All @@ -762,9 +845,11 @@ function transformAttributes(path, results) {
if (needsQuoting) {
needsSpacing = false;
results.template += `="${escapeHTML(text, true)}"`;
results.templateWithClosingTags += `="${escapeHTML(text, true)}"`;
} else {
needsSpacing = true;
results.template += `=${escapeHTML(text, true)}`;
results.templateWithClosingTags += `=${escapeHTML(text, true)}`;
}
}
}
Expand Down Expand Up @@ -818,6 +903,7 @@ function transformChildren(path, results, config) {
const i = memo.length;
if (transformed.text && i && memo[i - 1].text) {
memo[i - 1].template += transformed.template;
memo[i - 1].templateWithClosingTags += transformed.templateWithClosingTags || transformed.template;
} else memo.push(transformed);
return memo;
}, []);
Expand All @@ -830,6 +916,9 @@ function transformChildren(path, results, config) {
}

results.template += child.template;
results.templateWithClosingTags += child.templateWithClosingTags || child.template ;
results.isImportNode = results.isImportNode || child.isImportNode;

if (child.id) {
if (child.tagName === "head") {
if (config.hydratable) {
Expand Down Expand Up @@ -878,6 +967,7 @@ function transformChildren(path, results, config) {
childPostExprs.push(...child.postExprs);
results.hasHydratableEvent = results.hasHydratableEvent || child.hasHydratableEvent;
results.hasCustomElement = results.hasCustomElement || child.hasCustomElement;
results.isImportNode = results.isImportNode || child.isImportNode;
tempPath = child.id.name;
nextPlaceholder = null;
i++;
Expand Down Expand Up @@ -931,6 +1021,7 @@ function createPlaceholder(path, results, tempPath, i, char) {
config = getConfig(path);
let contentId;
results.template += `<!${char}>`;
results.templateWithClosingTags += `<!${char}>`;
if (config.hydratable && char === "/") {
contentId = path.scope.generateUidIdentifier("co$");
results.declarations.push(
Expand Down Expand Up @@ -980,7 +1071,7 @@ function detectExpressions(children, index, config) {
} else if (t.isJSXElement(child)) {
const tagName = getTagName(child);
if (isComponent(tagName)) return true;
if (config.contextToCustomElements && (tagName === "slot" || tagName.indexOf("-") > -1))
if (config.contextToCustomElements && (tagName === "slot" || tagName.indexOf("-") > -1 || child.openingElement.attributes.some(a => a.name?.name === 'is')))
return true;
if (
child.openingElement.attributes.some(
Expand Down
9 changes: 7 additions & 2 deletions packages/babel-plugin-jsx-dom-expressions/src/dom/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ export function appendTemplates(path, templates) {
cooked: template.template,
raw: escapeStringForTemplate(template.template)
};

const shouldUseImportNode = template.isCE || template.isImportNode

return t.variableDeclarator(
template.id,
t.addComment(
t.callExpression(
registerImportMethod(path, "template", getRendererConfig(path, "dom").moduleName),
[t.templateLiteral([t.templateElement(tmpl, true)], [])].concat(
template.isSVG || template.isCE
? [t.booleanLiteral(template.isCE), t.booleanLiteral(template.isSVG)]
template.isSVG || shouldUseImportNode
? [t.booleanLiteral(!!shouldUseImportNode), t.booleanLiteral(template.isSVG)]
: []
)
),
Expand Down Expand Up @@ -75,8 +78,10 @@ function registerTemplate(path, results) {
templates.push({
id: templateId,
template: results.template,
templateWithClosingTags: results.templateWithClosingTags,
isSVG: results.isSVG,
isCE: results.hasCustomElement,
isImportNode: results.isImportNode,
renderer: "dom"
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as t from "@babel/types";
import { getRendererConfig, registerImportMethod } from "./utils";
import { appendTemplates as appendTemplatesDOM } from "../dom/template";
import { appendTemplates as appendTemplatesSSR } from "../ssr/template";
import { isInvalidMarkup } from "./validate.js";
const { diff } = require("jest-diff");

// add to the top/bottom of the module.
export default path => {
Expand All @@ -16,6 +18,21 @@ export default path => {
);
}
if (path.scope.data.templates?.length) {
for (const template of path.scope.data.templates) {
const html = template.templateWithClosingTags;
// not sure when/why this is not a string
if (typeof html === "string") {
const result = isInvalidMarkup(html);
if (result) {
const message =
"The HTML provided is malformed and will yield unexpected output when evaluated by a browser.\n";
console.warn(message);
console.log(diff(result.html, result.browser));
console.warn("Original HTML:\n", html);
// throw path.buildCodeFrameError();
}
}
}
let domTemplates = path.scope.data.templates.filter(temp => temp.renderer === "dom");
let ssrTemplates = path.scope.data.templates.filter(temp => temp.renderer === "ssr");
domTemplates.length > 0 && appendTemplatesDOM(path, domTemplates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const JSXValidator = {
JSXElement(path) {
const elName = path.node.openingElement.name;
const parent = path.parent;

if (!t.isJSXElement(parent) || !t.isJSXIdentifier(elName)) return;
const elTagName = elName.name;
if (isComponent(elTagName)) return;
Expand Down
5 changes: 3 additions & 2 deletions packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export const reservedNameSpaces = new Set([
"style",
"use",
"prop",
"attr"
"attr",
"bool"
]);

export const nonSpreadNameSpaces = new Set(["class", "style", "use", "prop", "attr"]);
export const nonSpreadNameSpaces = new Set(["class", "style", "use", "prop", "attr", "bool"]);

export function getConfig(path) {
return path.hub.file.metadata.config;
Expand Down
Loading

0 comments on commit 2c8a9b1

Please sign in to comment.