diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts
index 85235ff528..7605164c26 100644
--- a/compiler/forget/src/HIR/BuildHIR.ts
+++ b/compiler/forget/src/HIR/BuildHIR.ts
@@ -1518,14 +1518,22 @@ function lowerExpression(
});
continue;
}
- const name = attribute.get("name");
- if (!name.isJSXIdentifier()) {
- builder.errors.push({
- reason: `(BuildHIR::lowerExpression) Handle ${name.type} attribute names in JSXElement`,
- severity: ErrorSeverity.Todo,
- nodePath: name,
- });
- continue;
+ const namePath = attribute.get("name");
+ let propName;
+ if (namePath.isJSXIdentifier()) {
+ propName = namePath.node.name;
+ if (propName.indexOf(":") !== -1) {
+ builder.errors.push({
+ reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name '${name}'`,
+ severity: ErrorSeverity.Todo,
+ nodePath: namePath,
+ });
+ }
+ } else {
+ invariant(namePath.isJSXNamespacedName(), "Refinement");
+ const namespace = namePath.node.namespace.name;
+ const name = namePath.node.name.name;
+ propName = `${namespace}:${name}`;
}
const valueExpr = attribute.get("value");
let value;
@@ -1551,8 +1559,7 @@ function lowerExpression(
}
value = lowerExpressionToTemporary(builder, expression);
}
- const prop: string = name.node.name;
- props.push({ kind: "JsxAttribute", name: prop, place: value });
+ props.push({ kind: "JsxAttribute", name: propName, place: value });
}
return {
kind: "JsxExpression",
@@ -1922,6 +1929,13 @@ function lowerJsxElementName(
if (tag.match(/^[A-Z]/)) {
return lowerIdentifier(builder, exprPath);
} else {
+ if (tag.indexOf(":") !== -1) {
+ builder.errors.push({
+ reason: `(BuildHIR::lowerJsxElementName) JSXIdentifier to have no colons, got '${tag}'`,
+ severity: ErrorSeverity.InvalidInput,
+ nodePath: exprPath,
+ });
+ }
const place: Place = buildTemporaryPlace(builder, exprLoc);
builder.push({
id: makeInstructionId(0),
@@ -1937,6 +1951,29 @@ function lowerJsxElementName(
}
} else if (exprPath.isJSXMemberExpression()) {
return lowerJsxMemberExpression(builder, exprPath);
+ } else if (exprPath.isJSXNamespacedName()) {
+ const namespace = exprPath.node.namespace.name;
+ const name = exprPath.node.name.name;
+ const tag = `${namespace}:${name}`;
+ if (namespace.indexOf(":") !== -1 || name.indexOf(":") !== -1) {
+ builder.errors.push({
+ reason: `(BuildHIR::lowerJsxElementName) Expected JSXNamespacedName to have no colons in the namespace or name, got '${namespace}' : '${name}'`,
+ severity: ErrorSeverity.InvalidInput,
+ nodePath: exprPath,
+ });
+ }
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
+ builder.push({
+ id: makeInstructionId(0),
+ value: {
+ kind: "Primitive",
+ value: tag,
+ loc: exprLoc,
+ },
+ loc: exprLoc,
+ lvalue: { ...place },
+ });
+ return place;
} else {
builder.errors.push({
reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`,
diff --git a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
index c8a132fd47..eda9cdd0f1 100644
--- a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+++ b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
@@ -658,9 +658,19 @@ function codegenInstructionValue(
for (const attribute of instrValue.props) {
switch (attribute.kind) {
case "JsxAttribute": {
+ let propName: t.JSXIdentifier | t.JSXNamespacedName;
+ if (attribute.name.indexOf(":") === -1) {
+ propName = t.jsxIdentifier(attribute.name);
+ } else {
+ const [namespace, name] = attribute.name.split(":", 2);
+ propName = t.jsxNamespacedName(
+ t.jsxIdentifier(namespace),
+ t.jsxIdentifier(name)
+ );
+ }
attributes.push(
t.jsxAttribute(
- t.jsxIdentifier(attribute.name),
+ propName,
t.jsxExpressionContainer(codegenPlace(cx, attribute.place))
)
);
@@ -681,9 +691,17 @@ function codegenInstructionValue(
}
}
let tagValue = codegenPlace(cx, instrValue.tag);
- let tag: t.JSXIdentifier | t.JSXMemberExpression;
+ let tag: t.JSXIdentifier | t.JSXNamespacedName | t.JSXMemberExpression;
if (tagValue.type === "Identifier") {
- tag = t.jsxIdentifier(tagValue.name);
+ if (tagValue.name.indexOf(":") >= 0) {
+ const [namespace, name] = tagValue.name.split(":", 2);
+ tag = t.jsxNamespacedName(
+ t.jsxIdentifier(namespace),
+ t.jsxIdentifier(name)
+ );
+ } else {
+ tag = t.jsxIdentifier(tagValue.name);
+ }
} else if (tagValue.type === "MemberExpression") {
tag = convertMemberExpressionToJsx(tagValue);
} else {
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
index 637caca4ca..144b6536d1 100644
--- a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
+++ b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
@@ -16,10 +16,8 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
const g = { b() {}, c: () => {} };
const { z, aa = "aa" } = useCustom();
- ;
;
;
- ;
const j = function bar([quz, qux], ...args) {};
@@ -127,7 +125,7 @@ let moduleLocal = false;
| ^^^^^^
13 | const { z, aa = "aa" } = useCustom();
14 |
- 15 | ;
+ 15 | ;
[ReactForget] TodoError: (BuildHIR::lowerAssignment) Handle AssignmentPattern assignments
11 |
@@ -135,215 +133,206 @@ let moduleLocal = false;
> 13 | const { z, aa = "aa" } = useCustom();
| ^^^^^^^^^
14 |
- 15 | ;
- 16 | ;
-
-[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle JSXNamespacedName attribute names in JSXElement
- 13 | const { z, aa = "aa" } = useCustom();
- 14 |
-> 15 | ;
- | ^^^^^^^^^^
- 16 | ;
- 17 | ;
- 18 | ;
+ 15 | ;
+ 16 | ;
[ReactForget] TodoError: (BuildHIR::lowerJsxElement) Handle JSXEmptyExpression expressions
- 15 | ;
- 16 | ;
-> 17 | ;
+ 14 |
+ 15 | ;
+> 16 | ;
| ^^^^^^^^^^^^
- 18 | ;
+ 17 |
+ 18 | const j = function bar([quz, qux], ...args) {};
19 |
- 20 | const j = function bar([quz, qux], ...args) {};
[ReactForget] TodoError: (BuildHIR::lower) Handle RestElement params
- 18 | ;
- 19 |
-> 20 | const j = function bar([quz, qux], ...args) {};
+ 16 | ;
+ 17 |
+> 18 | const j = function bar([quz, qux], ...args) {};
| ^^^^^^^
- 21 |
- 22 | for (; i < 3; i += 1) {
- 23 | x.push(i);
+ 19 |
+ 20 | for (; i < 3; i += 1) {
+ 21 | x.push(i);
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
- 20 | const j = function bar([quz, qux], ...args) {};
- 21 |
-> 22 | for (; i < 3; i += 1) {
+ 18 | const j = function bar([quz, qux], ...args) {};
+ 19 |
+> 20 | for (; i < 3; i += 1) {
| ^
- 23 | x.push(i);
- 24 | }
- 25 | for (; i < 3; ) {
+ 21 | x.push(i);
+ 22 | }
+ 23 | for (; i < 3; ) {
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
- 23 | x.push(i);
- 24 | }
-> 25 | for (; i < 3; ) {
+ 21 | x.push(i);
+ 22 | }
+> 23 | for (; i < 3; ) {
| ^
- 26 | break;
- 27 | }
- 28 | for (;;) {
+ 24 | break;
+ 25 | }
+ 26 | for (;;) {
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle empty update in ForStatement
- 23 | x.push(i);
- 24 | }
-> 25 | for (; i < 3; ) {
+ 21 | x.push(i);
+ 22 | }
+> 23 | for (; i < 3; ) {
| ^
- 26 | break;
- 27 | }
- 28 | for (;;) {
+ 24 | break;
+ 25 | }
+ 26 | for (;;) {
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement
- 26 | break;
- 27 | }
-> 28 | for (;;) {
+ 24 | break;
+ 25 | }
+> 26 | for (;;) {
| ^
- 29 | break;
- 30 | }
- 31 |
+ 27 | break;
+ 28 | }
+ 29 |
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle empty update in ForStatement
- 26 | break;
- 27 | }
-> 28 | for (;;) {
+ 24 | break;
+ 25 | }
+> 26 | for (;;) {
| ^
- 29 | break;
- 30 | }
- 31 |
+ 27 | break;
+ 28 | }
+ 29 |
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle empty test in ForStatement
- 26 | break;
- 27 | }
-> 28 | for (;;) {
+ 24 | break;
+ 25 | }
+> 26 | for (;;) {
| ^
- 29 | break;
- 30 | }
- 31 |
+ 27 | break;
+ 28 | }
+ 29 |
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle tagged template with interpolations
- 30 | }
- 31 |
-> 32 | graphql`
+ 28 | }
+ 29 |
+> 30 | graphql`
| ^
- 33 | ${g}
- 34 | `;
- 35 |
+ 31 | ${g}
+ 32 | `;
+ 33 |
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value
- 34 | `;
- 35 |
-> 36 | graphql`\\t\n`;
+ 32 | `;
+ 33 |
+> 34 | graphql`\\t\n`;
| ^^^^^^^^^^^^^^
- 37 |
- 38 | for (const c of [1, 2]) {
- 39 | }
+ 35 |
+ 36 | for (const c of [1, 2]) {
+ 37 | }
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle ForOfStatement statements
- 36 | graphql`\\t\n`;
- 37 |
-> 38 | for (const c of [1, 2]) {
+ 34 | graphql`\\t\n`;
+ 35 |
+> 36 | for (const c of [1, 2]) {
| ^
- 39 | }
- 40 |
- 41 | for (let x in { a: 1 }) {
+ 37 | }
+ 38 |
+ 39 | for (let x in { a: 1 }) {
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle ForInStatement statements
- 39 | }
- 40 |
-> 41 | for (let x in { a: 1 }) {
+ 37 | }
+ 38 |
+> 39 | for (let x in { a: 1 }) {
| ^
- 42 | }
- 43 |
- 44 | let updateIdentifier = 0;
+ 40 | }
+ 41 |
+ 42 | let updateIdentifier = 0;
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression
- 43 |
- 44 | let updateIdentifier = 0;
-> 45 | --updateIdentifier;
+ 41 |
+ 42 | let updateIdentifier = 0;
+> 43 | --updateIdentifier;
| ^^^^^^^^^^^^^^^^^^
- 46 | ++updateIdentifier;
- 47 | updateIdentifier.y++;
- 48 | updateIdentifier.y--;
+ 44 | ++updateIdentifier;
+ 45 | updateIdentifier.y++;
+ 46 | updateIdentifier.y--;
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression
- 44 | let updateIdentifier = 0;
- 45 | --updateIdentifier;
-> 46 | ++updateIdentifier;
+ 42 | let updateIdentifier = 0;
+ 43 | --updateIdentifier;
+> 44 | ++updateIdentifier;
| ^^^^^^^^^^^^^^^^^^
- 47 | updateIdentifier.y++;
- 48 | updateIdentifier.y--;
- 49 |
+ 45 | updateIdentifier.y++;
+ 46 | updateIdentifier.y--;
+ 47 |
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument
- 45 | --updateIdentifier;
- 46 | ++updateIdentifier;
-> 47 | updateIdentifier.y++;
+ 43 | --updateIdentifier;
+ 44 | ++updateIdentifier;
+> 45 | updateIdentifier.y++;
| ^^^^^^^^^^^^^^^^^^^^
- 48 | updateIdentifier.y--;
- 49 |
- 50 | switch (i) {
+ 46 | updateIdentifier.y--;
+ 47 |
+ 48 | switch (i) {
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument
- 46 | ++updateIdentifier;
- 47 | updateIdentifier.y++;
-> 48 | updateIdentifier.y--;
+ 44 | ++updateIdentifier;
+ 45 | updateIdentifier.y++;
+> 46 | updateIdentifier.y--;
| ^^^^^^^^^^^^^^^^^^^^
- 49 |
- 50 | switch (i) {
- 51 | case 1 + 1: {
+ 47 |
+ 48 | switch (i) {
+ 49 | case 1 + 1: {
[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
- 53 | case foo(): {
- 54 | }
-> 55 | case x.y: {
+ 51 | case foo(): {
+ 52 | }
+> 53 | case x.y: {
| ^^^
- 56 | }
- 57 | default: {
- 58 | }
-
-[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
- 51 | case 1 + 1: {
- 52 | }
-> 53 | case foo(): {
- | ^^^^^
54 | }
- 55 | case x.y: {
+ 55 | default: {
56 | }
[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
- 49 |
- 50 | switch (i) {
-> 51 | case 1 + 1: {
+ 49 | case 1 + 1: {
+ 50 | }
+> 51 | case foo(): {
| ^^^^^
52 | }
- 53 | case foo(): {
+ 53 | case x.y: {
54 | }
+[ReactForget] TodoError: (BuildHIR::lowerStatement) Switch case test values must be identifiers or primitives, compound values are not yet supported
+ 47 |
+ 48 | switch (i) {
+> 49 | case 1 + 1: {
+ | ^^^^^
+ 50 | }
+ 51 | case foo(): {
+ 52 | }
+
[ReactForget] InvalidInputError: (BuildHIR::lowerAssignment) Assigning to an identifier defined outside the function scope is not supported.
- 60 |
- 61 | // Cannot assign to globals
-> 62 | someUnknownGlobal = true;
+ 58 |
+ 59 | // Cannot assign to globals
+> 60 | someUnknownGlobal = true;
| ^^^^^^^^^^^^^^^^^
- 63 | moduleLocal = true;
- 64 |
- 65 | function component(a) {
+ 61 | moduleLocal = true;
+ 62 |
+ 63 | function component(a) {
[ReactForget] InvalidInputError: (BuildHIR::lowerAssignment) Assigning to an identifier defined outside the function scope is not supported.
- 61 | // Cannot assign to globals
- 62 | someUnknownGlobal = true;
-> 63 | moduleLocal = true;
+ 59 | // Cannot assign to globals
+ 60 | someUnknownGlobal = true;
+> 61 | moduleLocal = true;
| ^^^^^^^^^^^
- 64 |
- 65 | function component(a) {
- 66 | // Add support for function declarations once we support `var` hoisting.
+ 62 |
+ 63 | function component(a) {
+ 64 | // Add support for function declarations once we support `var` hoisting.
[ReactForget] TodoError: (BuildHIR::lowerStatement) Handle FunctionDeclaration statements
- 63 | moduleLocal = true;
- 64 |
-> 65 | function component(a) {
+ 61 | moduleLocal = true;
+ 62 |
+> 63 | function component(a) {
| ^
- 66 | // Add support for function declarations once we support `var` hoisting.
- 67 | function t() {}
- 68 | t();
+ 64 | // Add support for function declarations once we support `var` hoisting.
+ 65 | function t() {}
+ 66 | t();
```
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js
index 6addd8d50e..ed442e4737 100644
--- a/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js
+++ b/compiler/forget/src/__tests__/fixtures/compiler/error.todo-kitchensink.js
@@ -12,10 +12,8 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
const g = { b() {}, c: () => {} };
const { z, aa = "aa" } = useCustom();
- ;
;
;
- ;
const j = function bar([quz, qux], ...args) {};
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/jsx-namespaced-name.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/jsx-namespaced-name.expect.md
new file mode 100644
index 0000000000..3ae8bb889f
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/jsx-namespaced-name.expect.md
@@ -0,0 +1,29 @@
+
+## Input
+
+```javascript
+function Component(props) {
+ return ;
+}
+
+```
+
+## Code
+
+```javascript
+function Component(props) {
+ const $ = React.unstable_useMemoCache(2);
+ const c_0 = $[0] !== props.version;
+ let t0;
+ if (c_0) {
+ t0 = ;
+ $[0] = props.version;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/jsx-namespaced-name.js b/compiler/forget/src/__tests__/fixtures/compiler/jsx-namespaced-name.js
new file mode 100644
index 0000000000..e09a13331d
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/jsx-namespaced-name.js
@@ -0,0 +1,3 @@
+function Component(props) {
+ return ;
+}