Skip to content

Commit

Permalink
Feat complex metadata (#1638)
Browse files Browse the repository at this point in the history
* feat: improve parseJSX to resolve complex useMetadata

* fix: issue with metadata always be flat without correct depth

* chore: add changeset

* chore: add example for complex useMetadata

* chore: run fmt

* fix: complex metadata with spread variable

* chore: run fmt

* chore: update snapshots

* chore: moved `isTypescriptFile` from `src/helpers` to `parsers/jsx/helpers`

* chore: update snapshots
  • Loading branch information
nmerget authored Jan 14, 2025
1 parent 20ad8dc commit af43f50
Show file tree
Hide file tree
Showing 57 changed files with 6,713 additions and 507 deletions.
31 changes: 31 additions & 0 deletions .changeset/clean-cobras-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
'@builder.io/mitosis': patch
---

[All] Refactored `useMetadata` hook to enable import resolution instead of simple `JSON5` parsing.

You could use a normal JS `Object` and import it inside your `*.lite.tsx` file like this:

```ts
// data.ts

export const myMetadata: Record<string, string | number> = {
a: 'b',
c: 1,
};
```

```tsx
// my-button.lite.tsx
import { useMetadata } from '@builder.io/mitosis';
import { myMetadata } from './data.ts';

useMetadata({
x: 'y',
my: myMetadata,
});

export default function MyButton() {
return <button></button>;
}
```
18 changes: 18 additions & 0 deletions examples/metdata/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
env: {
browser: true,
},
plugins: ["@builder.io/mitosis"],
parser: "@typescript-eslint/parser",
extends: [],
parserOptions: {
ecmaVersion: 2018,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
rules: {
"@builder.io/mitosis/no-conditional-render": "warn",
},
};
1 change: 1 addition & 0 deletions examples/metdata/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
output
3 changes: 3 additions & 0 deletions examples/metdata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Metadata example for Mitosis

This is an example to showcase the ``useMetadata`` hook. You can use this to set predefined configuration parameters for each component. Or you can add additional parameters to use them in a plugin.
37 changes: 37 additions & 0 deletions examples/metdata/mitosis.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const metadataPlugin = () => ({
code: {
pre: (code, json) => {
if (json.meta.useMetadata) {
return `
/**
useMetadata:
${JSON.stringify(json.meta.useMetadata)}
*/
${code}`;
}

return code;
},
},
});

module.exports = {
files: 'src/**',
commonOptions: {
plugins: [metadataPlugin],
},
targets: [
'react',
// still unsupported
// 'qwik',
// 'builder',
'vue',
'html',
// TO-DO: fix error causing svelte output not to work
// 'svelte',
'solid',
'angular',
'webcomponent',
],
};
22 changes: 22 additions & 0 deletions examples/metdata/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@builder.io/metadata-example",
"private": true,
"scripts": {
"build": "mitosis build",
"lint": "eslint"
},
"exports": {
"./react/*": "./dist/react/src/*",
"./qwik/*": "./dist/qwik/src/*",
"./vue/*": "./dist/vue/src/*",
"./svelte/*": "./dist/svelte/src/*",
"./angular/*": "./dist/angular/src/*",
"./html/*": "./dist/html/src/*",
"./solid/*": "./dist/solid/src/*"
},
"dependencies": {
"@builder.io/mitosis": "workspace:*",
"@builder.io/mitosis-cli": "workspace:*",
"eslint": "^7.21.0"
}
}
13 changes: 13 additions & 0 deletions examples/metdata/src/components/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ComponentMetadata } from '@builder.io/mitosis';
import { customMetaData } from '../shared/data';

export const metadata: ComponentMetadata = {
regularKey: 'abc',
'some-key': customMetaData,
react: {
forwardRef: 'xxx',
},
vue: {
customKey: 'yyy',
},
};
8 changes: 8 additions & 0 deletions examples/metdata/src/components/metadata.lite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useMetadata } from '@builder.io/mitosis';
import { metadata } from './data';

useMetadata({ ...metadata });

export default function MetadataExample() {
return <div>Metadata</div>;
}
11 changes: 11 additions & 0 deletions examples/metdata/src/shared/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { CustomMetadata } from './model';

export const customMetaData: CustomMetadata = {
a: 'custom',
b: 1,
c: {
d: 'nested',
},
};


5 changes: 5 additions & 0 deletions examples/metdata/src/shared/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type CustomMetadata = {
a: string;
b: number;
c: Object;
};
10 changes: 10 additions & 0 deletions examples/metdata/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "ESNext",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"jsxImportSource": "@builder.io/mitosis"
},
"include": ["src"]
}
104 changes: 100 additions & 4 deletions packages/core/src/__tests__/__snapshots__/alpine.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,10 @@ exports[`Alpine.js > jsx > Javascript Test > Basic Outputs 1`] = `
`;
exports[`Alpine.js > jsx > Javascript Test > Basic Outputs Meta 1`] = `
"<div x-data=\\"myBasicOutputsComponent()\\"></div>
"/** useMetadata: {\\"outputs\\":[\\"onMessage\\",\\"onEvent\\"],\\"baz\\":\\"metadata inside
component\\"} */
<div x-data=\\"myBasicOutputsComponent()\\"></div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"myBasicOutputsComponent\\", () => ({
Expand Down Expand Up @@ -1630,7 +1633,9 @@ exports[`Alpine.js > jsx > Javascript Test > basicForwardRef 1`] = `
`;
exports[`Alpine.js > jsx > Javascript Test > basicForwardRefMetadata 1`] = `
"<style>
"/** useMetadata: {\\"forwardRef\\":\\"inputRef\\"} */
<style>
.input {
color: red;
}
Expand Down Expand Up @@ -1784,6 +1789,20 @@ exports[`Alpine.js > jsx > Javascript Test > classState 1`] = `
"
`;
exports[`Alpine.js > jsx > Javascript Test > complexMeta 1`] = `
"/** useMetadata:
{\\"x\\":\\"y\\",\\"asdf\\":{\\"stringValue\\":\\"d\\",\\"booleanValue\\":true,\\"numberValue\\":1,\\"innerObject\\":{\\"stringValue\\":\\"inner\\",\\"numberValue\\":2,\\"booleanValue\\":false},\\"spreadStringValue\\":\\"f\\"}}
*/
<div x-data=\\"complexMetaRaw()\\"></div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"complexMetaRaw\\", () => ({}));
});
</script>
"
`;
exports[`Alpine.js > jsx > Javascript Test > componentWithContext 1`] = `
"<div x-data=\\"componentWithContext()\\">
<div><span x-html=\\"foo.value\\"></span></div>
Expand Down Expand Up @@ -1922,6 +1941,35 @@ exports[`Alpine.js > jsx > Javascript Test > expressionState 1`] = `
"
`;
exports[`Alpine.js > jsx > Javascript Test > figmaMeta 1`] = `
"/** useMetadata:
{\\"figma\\":{\\"name\\":\\"def-button-beta-outlined\\",\\"url\\":\\"https://www.figma.com/xxx\\",\\"props\\":{\\"iconSmall\\":{\\"type\\":\\"instance\\",\\"key\\":\\"📍
Icon Small\\"},\\"iconMedium\\":{\\"type\\":\\"instance\\",\\"key\\":\\"📍 Icon
Medium\\"},\\"label\\":{\\"type\\":\\"string\\",\\"key\\":\\"✏️
Label\\"},\\"icon\\":{\\"type\\":\\"boolean\\",\\"key\\":\\"👁️
Icon\\",\\"value\\":{\\"false\\":false,\\"true\\":\\"placeholder\\"}},\\"interactiveState\\":{\\"type\\":\\"enum\\",\\"key\\":\\"Interactive
State\\",\\"value\\":{\\"(Def)
Enabled\\":false,\\"Hovered\\":false,\\"Pressed\\":false,\\"Focused\\":false,\\"Disabled\\":\\"true\\"}},\\"size\\":{\\"type\\":\\"enum\\",\\"key\\":\\"Size\\",\\"value\\":{\\"(Def)
Medium\\":false,\\"Small\\":\\"small\\"}},\\"width\\":{\\"type\\":\\"enum\\",\\"key\\":\\"Width\\",\\"value\\":{\\"(Def)
Auto Width\\":false,\\"Full Width\\":\\"full\\"}}}}} */
<button
x-data=\\"figmaButton()\\"
x-bind:data-icon=\\"icon\\"
x-bind:data-disabled=\\"interactiveState\\"
x-bind:data-width=\\"width\\"
x-bind:data-size=\\"size\\"
>
<span x-html=\\"label\\"></span>
</button>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"figmaButton\\", () => ({}));
});
</script>
"
`;
exports[`Alpine.js > jsx > Javascript Test > getterState 1`] = `
"<div x-data=\\"button()\\">
<p><span x-html=\\"foo2\\"></span></p>
Expand Down Expand Up @@ -3319,7 +3367,10 @@ exports[`Alpine.js > jsx > Typescript Test > Basic Outputs 1`] = `
`;
exports[`Alpine.js > jsx > Typescript Test > Basic Outputs Meta 1`] = `
"<div x-data=\\"myBasicOutputsComponent()\\"></div>
"/** useMetadata: {\\"outputs\\":[\\"onMessage\\",\\"onEvent\\"],\\"baz\\":\\"metadata inside
component\\"} */
<div x-data=\\"myBasicOutputsComponent()\\"></div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"myBasicOutputsComponent\\", () => ({
Expand Down Expand Up @@ -4697,7 +4748,9 @@ exports[`Alpine.js > jsx > Typescript Test > basicForwardRef 1`] = `
`;
exports[`Alpine.js > jsx > Typescript Test > basicForwardRefMetadata 1`] = `
"<style>
"/** useMetadata: {\\"forwardRef\\":\\"inputRef\\"} */
<style>
.input {
color: red;
}
Expand Down Expand Up @@ -4851,6 +4904,20 @@ exports[`Alpine.js > jsx > Typescript Test > classState 1`] = `
"
`;
exports[`Alpine.js > jsx > Typescript Test > complexMeta 1`] = `
"/** useMetadata:
{\\"x\\":\\"y\\",\\"asdf\\":{\\"stringValue\\":\\"d\\",\\"booleanValue\\":true,\\"numberValue\\":1,\\"innerObject\\":{\\"stringValue\\":\\"inner\\",\\"numberValue\\":2,\\"booleanValue\\":false},\\"spreadStringValue\\":\\"f\\"}}
*/
<div x-data=\\"complexMetaRaw()\\"></div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"complexMetaRaw\\", () => ({}));
});
</script>
"
`;
exports[`Alpine.js > jsx > Typescript Test > componentWithContext 1`] = `
"<div x-data=\\"componentWithContext()\\">
<div><span x-html=\\"foo.value\\"></span></div>
Expand Down Expand Up @@ -4989,6 +5056,35 @@ exports[`Alpine.js > jsx > Typescript Test > expressionState 1`] = `
"
`;
exports[`Alpine.js > jsx > Typescript Test > figmaMeta 1`] = `
"/** useMetadata:
{\\"figma\\":{\\"name\\":\\"def-button-beta-outlined\\",\\"url\\":\\"https://www.figma.com/xxx\\",\\"props\\":{\\"iconSmall\\":{\\"type\\":\\"instance\\",\\"key\\":\\"📍
Icon Small\\"},\\"iconMedium\\":{\\"type\\":\\"instance\\",\\"key\\":\\"📍 Icon
Medium\\"},\\"label\\":{\\"type\\":\\"string\\",\\"key\\":\\"✏️
Label\\"},\\"icon\\":{\\"type\\":\\"boolean\\",\\"key\\":\\"👁️
Icon\\",\\"value\\":{\\"false\\":false,\\"true\\":\\"placeholder\\"}},\\"interactiveState\\":{\\"type\\":\\"enum\\",\\"key\\":\\"Interactive
State\\",\\"value\\":{\\"(Def)
Enabled\\":false,\\"Hovered\\":false,\\"Pressed\\":false,\\"Focused\\":false,\\"Disabled\\":\\"true\\"}},\\"size\\":{\\"type\\":\\"enum\\",\\"key\\":\\"Size\\",\\"value\\":{\\"(Def)
Medium\\":false,\\"Small\\":\\"small\\"}},\\"width\\":{\\"type\\":\\"enum\\",\\"key\\":\\"Width\\",\\"value\\":{\\"(Def)
Auto Width\\":false,\\"Full Width\\":\\"full\\"}}}}} */
<button
x-data=\\"figmaButton()\\"
x-bind:data-icon=\\"icon\\"
x-bind:data-disabled=\\"interactiveState\\"
x-bind:data-width=\\"width\\"
x-bind:data-size=\\"size\\"
>
<span x-html=\\"label\\"></span>
</button>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"figmaButton\\", () => ({}));
});
</script>
"
`;
exports[`Alpine.js > jsx > Typescript Test > getterState 1`] = `
"<div x-data=\\"button()\\">
<p><span x-html=\\"foo2\\"></span></p>
Expand Down
Loading

0 comments on commit af43f50

Please sign in to comment.