From b697b53558801c43e82bde8125e5eb23de909053 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 00:29:34 +0800 Subject: [PATCH 001/156] feat: introduce jsx-macros --- packages/config/package.json | 1 + packages/config/src/options.ts | 3 + packages/jsx-macros/README.md | 3 + packages/jsx-macros/package.json | 150 ++++++++++ packages/jsx-macros/src/api.ts | 1 + packages/jsx-macros/src/core/index.ts | 144 ++++++++++ packages/jsx-macros/src/esbuild.ts | 3 + packages/jsx-macros/src/helpers.ts | 61 ++++ packages/jsx-macros/src/index.ts | 56 ++++ packages/jsx-macros/src/rolldown.ts | 3 + packages/jsx-macros/src/rollup.ts | 3 + packages/jsx-macros/src/rspack.ts | 3 + packages/jsx-macros/src/vite.ts | 3 + packages/jsx-macros/src/webpack.ts | 3 + .../tests/__snapshots__/fixtures.test.ts.snap | 33 +++ packages/jsx-macros/tests/fixtures.test.ts | 18 ++ .../tests/fixtures/define-expose.tsx | 6 + .../tests/fixtures/define-model.tsx | 4 + .../tests/fixtures/define-slots.tsx | 6 + packages/jsx-macros/tsup.config.ts | 1 + packages/macros/package.json | 1 + packages/macros/src/index.ts | 2 + packages/volar/package.json | 7 +- packages/volar/src/common.ts | 7 +- packages/volar/src/index.ts | 2 + packages/volar/src/jsx-directive/v-model.ts | 8 +- packages/volar/src/jsx-macros.ts | 264 ++++++++++++++++++ playground/vue3/package.json | 3 +- playground/vue3/src/App.vue | 6 + .../vue3/src/examples/jsx-macros/comp.tsx | 37 +++ .../vue3/src/examples/jsx-macros/index.tsx | 16 ++ playground/vue3/vue-macros.config.ts | 5 +- pnpm-lock.yaml | 28 +- tsconfig.fixture.json | 6 + 34 files changed, 886 insertions(+), 11 deletions(-) create mode 100644 packages/jsx-macros/README.md create mode 100644 packages/jsx-macros/package.json create mode 100644 packages/jsx-macros/src/api.ts create mode 100644 packages/jsx-macros/src/core/index.ts create mode 100644 packages/jsx-macros/src/esbuild.ts create mode 100644 packages/jsx-macros/src/helpers.ts create mode 100644 packages/jsx-macros/src/index.ts create mode 100644 packages/jsx-macros/src/rolldown.ts create mode 100644 packages/jsx-macros/src/rollup.ts create mode 100644 packages/jsx-macros/src/rspack.ts create mode 100644 packages/jsx-macros/src/vite.ts create mode 100644 packages/jsx-macros/src/webpack.ts create mode 100644 packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap create mode 100644 packages/jsx-macros/tests/fixtures.test.ts create mode 100644 packages/jsx-macros/tests/fixtures/define-expose.tsx create mode 100644 packages/jsx-macros/tests/fixtures/define-model.tsx create mode 100644 packages/jsx-macros/tests/fixtures/define-slots.tsx create mode 100644 packages/jsx-macros/tsup.config.ts create mode 100644 packages/volar/src/jsx-macros.ts create mode 100644 playground/vue3/src/examples/jsx-macros/comp.tsx create mode 100644 playground/vue3/src/examples/jsx-macros/index.tsx diff --git a/packages/config/package.json b/packages/config/package.json index c276f0830..26c9db62e 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -119,6 +119,7 @@ "@vue-macros/export-render": "workspace:*", "@vue-macros/hoist-static": "workspace:*", "@vue-macros/jsx-directive": "workspace:*", + "@vue-macros/jsx-macros": "workspace:*", "@vue-macros/named-template": "workspace:*", "@vue-macros/reactivity-transform": "workspace:*", "@vue-macros/script-lang": "workspace:*", diff --git a/packages/config/src/options.ts b/packages/config/src/options.ts index 57ddc8d63..fcdd14047 100644 --- a/packages/config/src/options.ts +++ b/packages/config/src/options.ts @@ -34,6 +34,7 @@ import type { Options as OptionsExportProps } from '@vue-macros/export-props' import type { Options as OptionsExportRender } from '@vue-macros/export-render' import type { Options as OptionsHoistStatic } from '@vue-macros/hoist-static' import type { Options as OptionsJsxDirective } from '@vue-macros/jsx-directive' +import type { Options as OptionsJsxMacros } from '@vue-macros/jsx-macros' import type { Options as OptionsNamedTemplate } from '@vue-macros/named-template' import type { Options as OptionsReactivityTransform } from '@vue-macros/reactivity-transform' import type { Options as OptionsScriptLang } from '@vue-macros/script-lang' @@ -76,6 +77,7 @@ export interface FeatureOptionsMap { exportRender: OptionsExportRender hoistStatic: OptionsHoistStatic jsxDirective: OptionsJsxDirective + jsxMacros: OptionsJsxMacros namedTemplate: OptionsNamedTemplate reactivityTransform: OptionsReactivityTransform scriptLang: OptionsScriptLang @@ -141,6 +143,7 @@ export function resolveOptions( exportRender: resolveSubOptions('exportRender', false), hoistStatic: resolveSubOptions('hoistStatic'), jsxDirective: resolveSubOptions('jsxDirective'), + jsxMacros: resolveSubOptions('jsxMacros', false), namedTemplate: resolveSubOptions('namedTemplate'), reactivityTransform: resolveSubOptions('reactivityTransform'), scriptLang: resolveSubOptions('scriptLang', false), diff --git a/packages/jsx-macros/README.md b/packages/jsx-macros/README.md new file mode 100644 index 000000000..ada30e804 --- /dev/null +++ b/packages/jsx-macros/README.md @@ -0,0 +1,3 @@ +# @vue-macros/jsx-macros [![npm](https://img.shields.io/npm/v/@vue-macros/jsx-macros.svg)](https://npmjs.com/package/@vue-macros/jsx-macros) + +Please refer to [README.md](https://github.com/vue-macros/vue-macros#readme) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json new file mode 100644 index 000000000..317c84ce9 --- /dev/null +++ b/packages/jsx-macros/package.json @@ -0,0 +1,150 @@ +{ + "name": "@vue-macros/jsx-macros", + "version": "0.0.0", + "packageManager": "pnpm@9.7.0", + "description": "define-slots feature from Vue Macros.", + "type": "commonjs", + "keywords": [ + "vue-macros", + "macros", + "vue", + "sfc", + "jsx-macros", + "unplugin" + ], + "license": "MIT", + "homepage": "https://vue-macros.dev", + "bugs": { + "url": "https://github.com/vue-macros/vue-macros/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vue-macros/vue-macros.git", + "directory": "packages/define-slots" + }, + "author": "三咲智子 ", + "files": [ + "*.d.ts", + "dist" + ], + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "exports": { + ".": { + "dev": "./src/index.ts", + "require": "./dist/index.js", + "import": "./dist/index.mjs" + }, + "./api": { + "dev": "./src/api.ts", + "require": "./dist/api.js", + "import": "./dist/api.mjs" + }, + "./esbuild": { + "dev": "./src/esbuild.ts", + "require": "./dist/esbuild.js", + "import": "./dist/esbuild.mjs" + }, + "./rolldown": { + "dev": "./src/rolldown.ts", + "require": "./dist/rolldown.js", + "import": "./dist/rolldown.mjs" + }, + "./rollup": { + "dev": "./src/rollup.ts", + "require": "./dist/rollup.js", + "import": "./dist/rollup.mjs" + }, + "./rspack": { + "dev": "./src/rspack.ts", + "require": "./dist/rspack.js", + "import": "./dist/rspack.mjs" + }, + "./vite": { + "dev": "./src/vite.ts", + "require": "./dist/vite.js", + "import": "./dist/vite.mjs" + }, + "./webpack": { + "dev": "./src/webpack.ts", + "require": "./dist/webpack.js", + "import": "./dist/webpack.mjs" + }, + "./helpers": { + "dev": "./src/helpers.ts", + "require": "./dist/helpers.js", + "import": "./dist/helpers.mjs" + }, + "./*": [ + "./*", + "./*.d.ts" + ] + }, + "typesVersions": { + "*": { + "*": [ + "./dist/*", + "./*" + ] + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs" + }, + "./api": { + "require": "./dist/api.js", + "import": "./dist/api.mjs" + }, + "./esbuild": { + "require": "./dist/esbuild.js", + "import": "./dist/esbuild.mjs" + }, + "./rolldown": { + "require": "./dist/rolldown.js", + "import": "./dist/rolldown.mjs" + }, + "./rollup": { + "require": "./dist/rollup.js", + "import": "./dist/rollup.mjs" + }, + "./rspack": { + "require": "./dist/rspack.js", + "import": "./dist/rspack.mjs" + }, + "./vite": { + "require": "./dist/vite.js", + "import": "./dist/vite.mjs" + }, + "./webpack": { + "require": "./dist/webpack.js", + "import": "./dist/webpack.mjs" + }, + "./*": [ + "./*", + "./*.d.ts" + ] + } + }, + "scripts": { + "build": "tsup", + "dev": "DEV=true tsup" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.0.0" + }, + "dependencies": { + "@vue-macros/common": "workspace:*", + "unplugin": "catalog:" + }, + "devDependencies": { + "vue": "catalog:" + }, + "engines": { + "node": ">=16.14.0" + } +} diff --git a/packages/jsx-macros/src/api.ts b/packages/jsx-macros/src/api.ts new file mode 100644 index 000000000..46d458ad7 --- /dev/null +++ b/packages/jsx-macros/src/api.ts @@ -0,0 +1 @@ +export * from './core' diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts new file mode 100644 index 000000000..cd497f1fa --- /dev/null +++ b/packages/jsx-macros/src/core/index.ts @@ -0,0 +1,144 @@ +import { + babelParse, + generateTransform, + getLang, + importHelperFn, + MagicStringAST, + walkAST, + type CodeTransform, +} from '@vue-macros/common' +import type { OptionsResolved } from '..' +import type { + ArrowFunctionExpression, + CallExpression, + FunctionDeclaration, + FunctionExpression, + Node, +} from '@babel/types' + +export function transformJsxMacros( + code: string, + id: string, + options: OptionsResolved, +): CodeTransform | undefined { + const s = new MagicStringAST(code) + + const parents: (Node | undefined | null)[] = [] + const roots: Map< + FunctionDeclaration | FunctionExpression | ArrowFunctionExpression, + Map + > = new Map() + walkAST(babelParse(code, getLang(id)), { + enter(node, parent) { + parents.unshift(parent) + const expression = + node.type === 'VariableDeclaration' + ? node.declarations[0].init + : node.type === 'ExpressionStatement' + ? node.expression + : undefined + const root = + parents[1] && + (parents[1].type === 'ArrowFunctionExpression' || + parents[1].type === 'FunctionDeclaration' || + parents[1].type === 'FunctionExpression') + ? parents[1] + : undefined + if (!root || !isMacro(expression)) return + + if (!roots.has(root)) + roots.set( + root, + new Map([ + ['defineModel', []], + ['defineSlots', []], + ['defineExpose', []], + ]), + ) + const map = roots.get(root)! + const macroName = s.sliceNode(expression.callee) + if (macroName) { + map.get(macroName)?.push(expression) + } + }, + leave() { + parents.shift() + }, + }) + + for (const [root, map] of roots) { + let propsName = '_props' + const paramsStart = root.params[0] + ? root.params[0].start! + : root.start! + + (s.slice(root.start!, root.body.start!).match(/\(\s*\)/)?.index || 0) + + 1 + if (root.params[0]) { + if (root.params[0].type === 'Identifier') { + propsName = root.params[0].name + } else if (root.params[0].type === 'ObjectPattern') { + const param = root.params[0].properties.find( + (i) => i.type === 'RestElement', + ) + if (param && param?.argument.type === 'Identifier') { + propsName = param.argument.name + } else if ( + root.params[0].type === 'ObjectPattern' && + root.params[0].properties.at(-1) + ) { + s.appendLeft(root.params[0].properties.at(-1)!.end!, `, ..._props`) + } + } + } else { + s.appendRight(paramsStart, '_props') + } + + for (const [macroName, nodes] of map) { + for (const node of nodes) { + if (macroName === 'defineSlots') { + s.overwrite( + node.start!, + (node.arguments[0]?.start && node.arguments[0].start - 1) || + node.typeArguments?.end || + node.callee.end!, + `Object.assign`, + ) + const slots = `${importHelperFn(s, 0, 'getCurrentInstance', options.lib)}().slots` + s.appendLeft( + node.end! - 1, + `${node.arguments[0] ? ',' : '{}, '}${slots}`, + ) + } else if (macroName === 'defineModel') { + s.overwriteNode( + node.callee, + importHelperFn(s, 0, 'useModel', '@vue-macros/jsx-macros/helpers'), + ) + s.appendRight( + node.arguments[0]?.start || node.end! - 1, + `${propsName}, ${node.arguments.length && node.arguments[0].type !== 'StringLiteral' ? `'modelValue',` : ''}`, + ) + } else if (macroName === 'defineExpose') { + s.overwriteNode( + node.callee, + importHelperFn(s, 0, 'useExpose', '@vue-macros/jsx-macros/helpers'), + ) + s.appendRight( + node.arguments[0]?.start || node.end! - 1, + `${importHelperFn(s, 0, 'getCurrentInstance', options.lib)}(), `, + ) + } + } + } + } + + return generateTransform(s, id) +} + +function isMacro(node?: Node | null): node is CallExpression { + return !!( + node && + node.type === 'CallExpression' && + node.callee.type === 'Identifier' && + ['defineSlots', 'defineModel', 'defineExpose'].includes(node.callee.name) + ) +} diff --git a/packages/jsx-macros/src/esbuild.ts b/packages/jsx-macros/src/esbuild.ts new file mode 100644 index 000000000..e8c6460dd --- /dev/null +++ b/packages/jsx-macros/src/esbuild.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.esbuild as typeof unplugin.esbuild diff --git a/packages/jsx-macros/src/helpers.ts b/packages/jsx-macros/src/helpers.ts new file mode 100644 index 000000000..d745bd6b0 --- /dev/null +++ b/packages/jsx-macros/src/helpers.ts @@ -0,0 +1,61 @@ +import { camelize, type ModelRef } from 'vue' + +export function useExpose(i: any, exposed = {}): void { + if (i) { + i.exposed = exposed + if (i.vnode) i.vnode.shapeFlag = 4 + } +} + +export type DefineModelOptions> = { + default?: any + get?: (v: T) => any + set?: (v: T) => any +} +export function useModel< + M extends PropertyKey, + T extends Record, + K extends keyof T, +>(props: T, name: K, options?: DefineModelOptions): ModelRef +export function useModel( + props: Record, + name: string = 'modelValue', + options: DefineModelOptions = {}, +): any { + name = camelize(name) + const modifiers = getModelModifiers(props, name) + const res = { + get value() { + const result = props?.[name] ?? options?.default + return options?.get ? options.get(result) : result + }, + set value(v) { + props?.[`onUpdate:${name}`]?.(v) + }, + __v_isRef: true, + } + + // @ts-expect-error + res[Symbol.iterator] = () => { + let i = 0 + return { + next() { + if (i < 2) { + return { value: i++ ? modifiers || {} : res, done: false } + } else { + return { done: true } + } + }, + } + } + return res +} + +export const getModelModifiers = ( + props: Record, + modelName: string, +): Record | undefined => { + return modelName === 'modelValue' + ? props.modelModifiers + : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] +} diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts new file mode 100644 index 000000000..db1e083cf --- /dev/null +++ b/packages/jsx-macros/src/index.ts @@ -0,0 +1,56 @@ +import { + createFilter, + detectVueVersion, + FilterFileType, + getFilterPattern, + REGEX_SETUP_SFC, + type BaseOptions, + type MarkRequired, +} from '@vue-macros/common' +import { + createUnplugin, + type UnpluginContextMeta, + type UnpluginInstance, +} from 'unplugin' +import { generatePluginName } from '#macros' with { type: 'macro' } +import { transformJsxMacros } from './core' + +export type Options = BaseOptions & { + lib?: string +} +export type OptionsResolved = MarkRequired + +function resolveOptions( + options: Options, + framework: UnpluginContextMeta['framework'], +): OptionsResolved { + const version = options.version || detectVueVersion() + const lib = options.lib || 'vue' + const include = getFilterPattern([FilterFileType.SRC_FILE], framework) + return { + include, + exclude: [REGEX_SETUP_SFC], + ...options, + version, + lib, + } +} + +const name = generatePluginName() + +const plugin: UnpluginInstance = createUnplugin( + (userOptions = {}, { framework }) => { + const options = resolveOptions(userOptions, framework) + const filter = createFilter(options) + + return { + name, + enforce: 'pre', + transformInclude: filter, + transform(code, id) { + return transformJsxMacros(code, id, options) + }, + } + }, +) +export default plugin diff --git a/packages/jsx-macros/src/rolldown.ts b/packages/jsx-macros/src/rolldown.ts new file mode 100644 index 000000000..082a55c18 --- /dev/null +++ b/packages/jsx-macros/src/rolldown.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.rolldown as typeof unplugin.rolldown diff --git a/packages/jsx-macros/src/rollup.ts b/packages/jsx-macros/src/rollup.ts new file mode 100644 index 000000000..45545feb1 --- /dev/null +++ b/packages/jsx-macros/src/rollup.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.rollup as typeof unplugin.rollup diff --git a/packages/jsx-macros/src/rspack.ts b/packages/jsx-macros/src/rspack.ts new file mode 100644 index 000000000..6df8a0299 --- /dev/null +++ b/packages/jsx-macros/src/rspack.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.rspack as typeof unplugin.rspack diff --git a/packages/jsx-macros/src/vite.ts b/packages/jsx-macros/src/vite.ts new file mode 100644 index 000000000..a7c5db2c1 --- /dev/null +++ b/packages/jsx-macros/src/vite.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.vite as typeof unplugin.vite diff --git a/packages/jsx-macros/src/webpack.ts b/packages/jsx-macros/src/webpack.ts new file mode 100644 index 000000000..74c1c9020 --- /dev/null +++ b/packages/jsx-macros/src/webpack.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.webpack as typeof unplugin.webpack diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap new file mode 100644 index 000000000..fcc1a6e5a --- /dev/null +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -0,0 +1,33 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` +" +import { useExpose as __MACROS_useExpose } from "@vue-macros/jsx-macros/helpers"; +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function(_props){ + __MACROS_useExpose(__MACROS_getCurrentInstance(), { + foo: 1 + }) + return
+} +" +`; + +exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` +" +import { useModel as __MACROS_useModel } from "@vue-macros/jsx-macros/helpers";export default function(_props){ + const foo = __MACROS_useModel(_props, 'foo') + return
{foo.value}
+} +" +`; + +exports[`fixtures > ./fixtures/define-slots.tsx 1`] = ` +" +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (_props) { + const slots = Object.assign({ + default: () =>
default
, + },__MACROS_getCurrentInstance().slots) + return
{slots.default()}
+} +" +`; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts new file mode 100644 index 000000000..b6ae4de7e --- /dev/null +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -0,0 +1,18 @@ +import { testFixtures } from '@vue-macros/test-utils' +import { describe } from 'vitest' +import { transformJsxMacros } from '../src/core' + +describe('fixtures', async () => { + await testFixtures( + import.meta.glob('./fixtures/**/*.tsx', { + eager: true, + as: 'raw', + }), + (args, id, code) => + transformJsxMacros(code, id, { + lib: 'vue', + include: ['*.tsx'], + version: 3.5, + })?.code, + ) +}) diff --git a/packages/jsx-macros/tests/fixtures/define-expose.tsx b/packages/jsx-macros/tests/fixtures/define-expose.tsx new file mode 100644 index 000000000..87e806d44 --- /dev/null +++ b/packages/jsx-macros/tests/fixtures/define-expose.tsx @@ -0,0 +1,6 @@ +export default function(){ + defineExpose({ + foo: 1 + }) + return
+} diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx new file mode 100644 index 000000000..06d9ef950 --- /dev/null +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -0,0 +1,4 @@ +export default function(){ + const foo = defineModel('foo') + return
{foo.value}
+} diff --git a/packages/jsx-macros/tests/fixtures/define-slots.tsx b/packages/jsx-macros/tests/fixtures/define-slots.tsx new file mode 100644 index 000000000..9646e9f7b --- /dev/null +++ b/packages/jsx-macros/tests/fixtures/define-slots.tsx @@ -0,0 +1,6 @@ +export default function () { + const slots = defineSlots({ + default: () =>
default
, + }) + return
{slots.default()}
+} diff --git a/packages/jsx-macros/tsup.config.ts b/packages/jsx-macros/tsup.config.ts new file mode 100644 index 000000000..1605eae16 --- /dev/null +++ b/packages/jsx-macros/tsup.config.ts @@ -0,0 +1 @@ +export { default } from '../../tsup.config.js' diff --git a/packages/macros/package.json b/packages/macros/package.json index f969a65e6..d30b00801 100644 --- a/packages/macros/package.json +++ b/packages/macros/package.json @@ -152,6 +152,7 @@ "@vue-macros/export-render": "workspace:*", "@vue-macros/hoist-static": "workspace:*", "@vue-macros/jsx-directive": "workspace:*", + "@vue-macros/jsx-macros": "workspace:*", "@vue-macros/named-template": "workspace:*", "@vue-macros/reactivity-transform": "workspace:*", "@vue-macros/script-lang": "workspace:*", diff --git a/packages/macros/src/index.ts b/packages/macros/src/index.ts index 21a5bbe48..e7b91e24c 100644 --- a/packages/macros/src/index.ts +++ b/packages/macros/src/index.ts @@ -35,6 +35,7 @@ import VueExportProps from '@vue-macros/export-props' import VueExportRender from '@vue-macros/export-render' import VueHoistStatic from '@vue-macros/hoist-static' import VueJsxDirective from '@vue-macros/jsx-directive' +import VueJsxMacros from '@vue-macros/jsx-macros' import VueNamedTemplate from '@vue-macros/named-template' import VueReactivityTransform from '@vue-macros/reactivity-transform' import VueScriptLang from '@vue-macros/script-lang' @@ -130,6 +131,7 @@ const plugin: UnpluginCombineInstance = options.plugins.vue, resolvePlugin(VueJsxDirective, framework, options.jsxDirective), + resolvePlugin(VueJsxMacros, framework, options.jsxMacros), options.plugins.vueJsx, resolvePlugin(VueDefineRender, framework, options.defineRender), setupComponentPlugins?.[1], diff --git a/packages/volar/package.json b/packages/volar/package.json index 839d2be15..4ef0bc090 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -142,6 +142,11 @@ "require": "./dist/template-ref.js", "import": "./dist/template-ref.mjs" }, + "./jsx-macros": { + "dev": "./src/jsx-macros.ts", + "require": "./dist/jsx-macros.js", + "import": "./dist/jsx-macros.mjs" + }, "./*": [ "./*", "./*.d.ts" @@ -270,11 +275,11 @@ "@vue-macros/config": "workspace:*", "@vue-macros/short-bind": "workspace:*", "@vue-macros/short-vmodel": "workspace:*", + "@vue/compiler-dom": "catalog:", "@vue/language-core": "catalog:", "muggle-string": "^0.4.1" }, "devDependencies": { - "@vue/compiler-dom": "catalog:", "typescript": "catalog:", "vue-tsc": "catalog:" }, diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index 57e169742..533ef386a 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -130,16 +130,19 @@ export interface VolarContext { } export function getStart( - node: import('typescript').Node, + node: + | import('typescript').Node + | import('typescript').SignatureDeclarationBase['parameters'], { ts, sfc, source = 'scriptSetup' }: VolarContext, ): number { return (ts as any).getTokenPosOfNode(node, sfc[source]!.ast) } export function getText( - node: import('typescript').Node, + node: import('typescript').Node | undefined, context: VolarContext, ): string { + if (!node) return '' const { sfc, source = 'scriptSetup' } = context return sfc[source]!.content.slice(getStart(node, context), node.end) } diff --git a/packages/volar/src/index.ts b/packages/volar/src/index.ts index 2033dc0d9..a59050086 100644 --- a/packages/volar/src/index.ts +++ b/packages/volar/src/index.ts @@ -12,6 +12,7 @@ import exportExpose from './export-expose' import exportProps from './export-props' import exportRender from './export-render' import jsxDirective from './jsx-directive' +import jsxMacros from './jsx-macros' import scriptLang from './script-lang' import scriptSFC from './script-sfc' import setupJsdoc from './setup-jsdoc' @@ -30,6 +31,7 @@ const plugins = { shortVmodel, defineSlots, jsxDirective, + jsxMacros, booleanProp, exportRender, exportProps, diff --git a/packages/volar/src/jsx-directive/v-model.ts b/packages/volar/src/jsx-directive/v-model.ts index 8e9497029..13989c852 100644 --- a/packages/volar/src/jsx-directive/v-model.ts +++ b/packages/volar/src/jsx-directive/v-model.ts @@ -119,10 +119,16 @@ export function transformVModel( source, start, attribute.name.end, - `{...{'onUpdate:${modelValue}': () => {} }} `, modelValue.slice(0, 3), [modelValue.slice(3), source, start, allCodeFeatures], ) + replaceSourceRange( + codes, + source, + attribute.end, + attribute.end, + ` {...{'onUpdate:${modelValue}': () => {} }}`, + ) } } diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts new file mode 100644 index 000000000..8ab4dff63 --- /dev/null +++ b/packages/volar/src/jsx-macros.ts @@ -0,0 +1,264 @@ +import { createFilter } from '@vue-macros/common' +import { toValidAssetId } from '@vue/compiler-dom' +import { allCodeFeatures } from '@vue/language-core' +import { replaceSourceRange } from 'muggle-string' +import { getStart, getText, type VueMacrosPlugin } from './common' +import type { TransformOptions } from './jsx-directive/index' +import type { + ArrowFunction, + CallExpression, + FunctionDeclaration, + Node, +} from 'typescript' + +function isFunction( + node: Node, + ts: typeof import('typescript'), +): node is ArrowFunction | FunctionDeclaration { + return ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) +} + +export function transformJsxMacros(options: TransformOptions): void { + const { ts, sfc, source, codes } = options + const rootMap = new Map< + ArrowFunction | FunctionDeclaration, + Map + >() + + function walk(node: Node, parents: Node[]) { + const root = + parents[1] && isFunction(parents[1], ts) ? parents[1] : undefined + const macro = root && getMacroCall(node, ts) + if (macro) { + if (!rootMap.has(root)) { + rootMap.set( + root, + new Map([ + ['defineSlots', []], + ['defineModel', []], + ['defineExpose', []], + ]), + ) + } + const propMap = rootMap.get(root)! + const name = getText(macro.expression, options) + + if (name === 'defineModel') { + const modelName = + macro.arguments[0] && ts.isStringLiteralLike(macro.arguments[0]) + ? macro.arguments[0].text + : 'modelValue' + const modelOptions = + macro.arguments[0] && ts.isStringLiteralLike(macro.arguments[0]) + ? macro.arguments[1] + : macro.arguments[0] + let required = false + if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { + for (const prop of modelOptions.properties) { + if ( + ts.isPropertyAssignment(prop) && + getText(prop.name, options) === 'required' + ) { + required = prop.initializer.kind === ts.SyntaxKind.TrueKeyword + } + } + } + const id = toValidAssetId(modelName, '_VLS_model' as any) + const typeString = `import("vue").UnwrapRef` + const requiredString = required ? ':' : '?:' + propMap + .get(name) + ?.push( + `${modelName}${requiredString} ${typeString}`, + `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, + ) + replaceSourceRange( + codes, + source, + getStart(macro, options), + getStart(macro, options), + `${id}; let ${id} =`, + ['__MACROS_', source, getStart(macro, options), allCodeFeatures], + ) + } else if (name === 'defineSlots') { + replaceSourceRange( + codes, + source, + getStart(macro, options), + getStart(macro, options), + `__MACROS_slots; let __MACROS_slots =`, + [ + '__MACROS_', + source, + getStart(macro.expression, options), + allCodeFeatures, + ], + ) + propMap.get(name)?.push('{ vSlots?: typeof __MACROS_slots }') + } else if (name === 'defineExpose') { + replaceSourceRange( + codes, + source, + getStart(macro, options), + getStart(macro, options), + `let __MACROS_expose = ${getText(macro.arguments[0], options)};`, + ['__MACROS_', source, getStart(macro, options), allCodeFeatures], + ) + propMap + .get(name) + ?.push('{ vExpose?: (exposed: typeof __MACROS_expose) => any }') + } + } + + ts.forEachChild(node, (child) => { + parents.unshift(node) + walk(child, parents) + parents.shift() + }) + } + ts.forEachChild(sfc[source]!.ast, (node) => walk(node, [])) + + for (const [root, props] of rootMap) { + const result: string[] = [] + for (const [name, members] of props) { + if (name === 'defineModel') { + result.push(`{${members.join(', ')}}`) + } else { + result.push(members.join('')) + } + } + + if (ts.isFunctionDeclaration(root) && root.body) { + replaceSourceRange( + codes, + source, + root.parameters.pos, + getStart(root.body, options), + `_props: `, + root.parameters[0]?.type + ? `${getText(root.parameters[0].type, options)} & ` + : '', + `Awaited['props'], __MACROS_setup = ((${getText(root.parameters[0], options)}) =>`, + ) + replaceSourceRange( + codes, + source, + root.body.end - 1, + root.body.end - 1, + `})()){ return {} as Awaited['render']`, + ) + } else { + replaceSourceRange( + codes, + source, + getStart(root.parameters, options), + getStart(root.parameters, options), + `_props: `, + root.parameters[0]?.type + ? `${getText(root.parameters[0].type, options)} & ` + : '', + `Awaited['props'], __MACROS_setup = ((`, + ) + replaceSourceRange( + codes, + source, + root.end, + root.end, + `)()) => ({}) as Awaited['render']`, + ) + } + root.body && + root.body.forEachChild((node) => { + if (ts.isReturnStatement(node) && node.expression) { + replaceSourceRange( + codes, + source, + getStart(node, options), + getStart(node.expression, options), + `return { props: {} as ${result.join(' &\n')},`, + `render: `, + ) + replaceSourceRange( + codes, + source, + node.expression.end, + node.expression.end, + `}`, + ) + } + }) + } + + if (rootMap.size) { + codes.push(` +declare function __MACROS_defineSlots>(slots?: T): T +declare const __MACROS_defineExpose: typeof import('vue').defineExpose; +declare const __MACROS_defineModel: typeof import('vue').defineModel;\n`) + } +} + +function getMacroCall( + node: import('typescript').Node | undefined, + ts: typeof import('typescript'), +): CallExpression | undefined { + if (!node) return + + if (ts.isVariableStatement(node)) { + return ts.forEachChild(node.declarationList, (decl) => getExpression(decl)) + } else { + return getExpression(node) + } + + function getExpression(decl: Node) { + if ( + ts.isVariableDeclaration(decl) && + decl.initializer && + ts.isCallExpression(decl.initializer) && + ts.isIdentifier(decl.initializer.expression) + ) { + const expression = + decl.initializer.expression.escapedText === '$' + ? decl.initializer.arguments[0] + : decl.initializer + if (isMacroCall(expression)) return expression + } else if (ts.isExpressionStatement(decl) && isMacroCall(decl.expression)) { + return decl.expression + } + } + + function isMacroCall(node: Node): node is CallExpression { + return !!( + ts.isCallExpression(node) && + ts.isIdentifier(node.expression) && + ['defineSlots', 'defineModel', 'defineExpose'].includes( + node.expression.escapedText!, + ) + ) + } +} + +const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { + if (!options) return [] + + const filter = createFilter(options) + + return { + name: 'vue-macros-jsx-macros', + version: 2.1, + resolveEmbeddedCode(fileName, sfc, embeddedFile) { + if (!filter(fileName) || !['tsx'].includes(embeddedFile.lang)) return + + for (const source of ['script', 'scriptSetup'] as const) { + if (!sfc[source]) return + transformJsxMacros({ + codes: embeddedFile.content, + sfc, + ts: ctx.modules.typescript, + source, + vueVersion: ctx.vueCompilerOptions.target, + }) + } + }, + } +} +export default plugin diff --git a/playground/vue3/package.json b/playground/vue3/package.json index 9825be9d0..28b19f7ff 100644 --- a/playground/vue3/package.json +++ b/playground/vue3/package.json @@ -12,8 +12,9 @@ "typecheck": "vue-tsc --noEmit" }, "dependencies": { - "@vueuse/core": "^11.0.3", "quasar": "^2.16.9", + "@vue-macros/jsx-macros": "workspace:*", + "@vueuse/core": "^11.0.3", "vue": "catalog:" }, "devDependencies": { diff --git a/playground/vue3/src/App.vue b/playground/vue3/src/App.vue index 64073de68..556dc0aad 100644 --- a/playground/vue3/src/App.vue +++ b/playground/vue3/src/App.vue @@ -18,6 +18,7 @@ import Full from './examples/full.setup' import HoistStatic from './examples/hoist-static/index.vue' import JsxDirective from './examples/jsx-directive/index.vue' +import JsxMacros from './examples/jsx-macros/index' import ReactivityTransform from './examples/reactivity-transform/index.vue' import ScriptLang from './examples/script-lang/index.vue' @@ -139,6 +140,11 @@ import ShortVmodel from './examples/short-vmodel/parent.vue' +
+ jsxMacros + +
+
booleanProp diff --git a/playground/vue3/src/examples/jsx-macros/comp.tsx b/playground/vue3/src/examples/jsx-macros/comp.tsx new file mode 100644 index 000000000..ff6f06f46 --- /dev/null +++ b/playground/vue3/src/examples/jsx-macros/comp.tsx @@ -0,0 +1,37 @@ +import { watch } from 'vue' + +export function Comp({ foo }: { foo: T }) { + const slots = defineSlots({ + default: (props: { bar: string }) =>
{props.bar}
, + }) + + const [modelValue, modifiers] = defineModel({ + required: true, + get(value) { + if (modifiers.trim) return value.trim() + return value + }, + set(value) { + if (modifiers.trim) return value.trim() + return value + }, + }) + watch( + modelValue, + () => { + console.log(modelValue.value) + }, + { immediate: true }, + ) + + defineExpose({ + foo, + }) + + return ( +
+ + +
+ ) +} diff --git a/playground/vue3/src/examples/jsx-macros/index.tsx b/playground/vue3/src/examples/jsx-macros/index.tsx new file mode 100644 index 000000000..85c7f6e44 --- /dev/null +++ b/playground/vue3/src/examples/jsx-macros/index.tsx @@ -0,0 +1,16 @@ +import { defineComponent, ref } from 'vue' +import { Comp } from './comp' + +export default defineComponent(() => { + const foo = ref('1') + + return () => ( +
+ + + + + {foo.value} +
+ ) +}) diff --git a/playground/vue3/vue-macros.config.ts b/playground/vue3/vue-macros.config.ts index 8345f53ce..dfa6fc6b3 100644 --- a/playground/vue3/vue-macros.config.ts +++ b/playground/vue3/vue-macros.config.ts @@ -17,12 +17,11 @@ export default defineConfig({ include: [/export-render.*\.vue$/, /\.setup\.tsx?$/], }, hoistStatic: true, + jsxMacros: true, namedTemplate: false, reactivityTransform: true, scriptLang: true, - scriptSFC: { - include: [/script-sfc.*\.tsx$/], - }, + scriptSFC: true, setupBlock: true, setupSFC: true, shortBind: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 902404ff8..37def4009 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -363,6 +363,9 @@ importers: '@vue-macros/jsx-directive': specifier: workspace:* version: link:../jsx-directive + '@vue-macros/jsx-macros': + specifier: workspace:* + version: link:../jsx-macros '@vue-macros/named-template': specifier: workspace:* version: link:../named-template @@ -616,6 +619,19 @@ importers: specifier: 'catalog:' version: 3.5.0(typescript@5.6.1-rc) + packages/jsx-macros: + dependencies: + '@vue-macros/common': + specifier: workspace:* + version: link:../common + unplugin: + specifier: 'catalog:' + version: 1.12.3 + devDependencies: + vue: + specifier: 'catalog:' + version: 3.5.0(typescript@5.6.1-rc) + packages/macros: dependencies: '@vue-macros/better-define': @@ -669,6 +685,9 @@ importers: '@vue-macros/jsx-directive': specifier: workspace:* version: link:../jsx-directive + '@vue-macros/jsx-macros': + specifier: workspace:* + version: link:../jsx-macros '@vue-macros/named-template': specifier: workspace:* version: link:../named-template @@ -909,6 +928,9 @@ importers: '@vue-macros/short-vmodel': specifier: workspace:* version: link:../short-vmodel + '@vue/compiler-dom': + specifier: 'catalog:' + version: 3.5.0 '@vue/language-core': specifier: 'catalog:' version: 2.0.29(typescript@5.6.1-rc) @@ -916,9 +938,6 @@ importers: specifier: ^0.4.1 version: 0.4.1 devDependencies: - '@vue/compiler-dom': - specifier: 'catalog:' - version: 3.5.0 typescript: specifier: 'catalog:' version: 5.6.1-rc @@ -1010,6 +1029,9 @@ importers: playground/vue3: dependencies: + '@vue-macros/jsx-macros': + specifier: workspace:* + version: link:../../packages/jsx-macros '@vueuse/core': specifier: ^11.0.3 version: 11.0.3(vue@3.5.0(typescript@5.6.1-rc)) diff --git a/tsconfig.fixture.json b/tsconfig.fixture.json index bea8d264c..13d49387a 100644 --- a/tsconfig.fixture.json +++ b/tsconfig.fixture.json @@ -22,6 +22,12 @@ }, "scriptLang": { "include": ["**/script-lang/**"] + }, + "jsxMacros": { + "include": ["**/jsx-macros/**"] + }, + "scriptSFC": { + "include": ["**/jsx-macros/**"] } } } From 263d9ebe7413a667ab2dc9717537eb58f2c30324 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 00:31:26 +0800 Subject: [PATCH 002/156] chore: add changeset --- .changeset/four-crews-know.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/four-crews-know.md diff --git a/.changeset/four-crews-know.md b/.changeset/four-crews-know.md new file mode 100644 index 000000000..efd0ae37a --- /dev/null +++ b/.changeset/four-crews-know.md @@ -0,0 +1,9 @@ +--- +"@vue-macros/jsx-macros": minor +"unplugin-vue-macros": minor +"@vue-macros/volar": minor +"@vue-macros/config": patch +--- + +introduce jsx-macros + \ No newline at end of file From 6f474315800c954d0c2e7bcf0172a16655ce5f19 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 00:59:45 +0800 Subject: [PATCH 003/156] fix: lint --- packages/volar/package.json | 1 + packages/volar/src/jsx-macros.ts | 2 +- playground/vue3/package.json | 2 +- pnpm-lock.yaml | 73 ++++++++------------------------ 4 files changed, 20 insertions(+), 58 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index 28f0d5f1d..d39f67f4d 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -280,6 +280,7 @@ "muggle-string": "^0.4.1" }, "devDependencies": { + "@vue/compiler-core": "catalog:", "typescript": "catalog:", "vue-tsc": "catalog:" }, diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 8ab4dff63..2ad171fdf 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -168,7 +168,7 @@ export function transformJsxMacros(options: TransformOptions): void { ) } root.body && - root.body.forEachChild((node) => { + ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { replaceSourceRange( codes, diff --git a/playground/vue3/package.json b/playground/vue3/package.json index 28b19f7ff..16aecd946 100644 --- a/playground/vue3/package.json +++ b/playground/vue3/package.json @@ -12,9 +12,9 @@ "typecheck": "vue-tsc --noEmit" }, "dependencies": { - "quasar": "^2.16.9", "@vue-macros/jsx-macros": "workspace:*", "@vueuse/core": "^11.0.3", + "quasar": "^2.16.9", "vue": "catalog:" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60df2d919..e4a35269c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -938,6 +938,9 @@ importers: specifier: ^0.4.1 version: 0.4.1 devDependencies: + '@vue/compiler-core': + specifier: 'catalog:' + version: 3.5.3 typescript: specifier: 'catalog:' version: 5.6.1-rc @@ -2713,30 +2716,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@vue/compiler-core@3.5.0': - resolution: {integrity: sha512-ja7cpqAOfw4tyFAxgBz70Z42miNDeaqTxExTsnXDLomRpqfyCgyvZvFp482fmsElpfvsoMJUsvzULhvxUTW6Iw==} - '@vue/compiler-core@3.5.3': resolution: {integrity: sha512-adAfy9boPkP233NTyvLbGEqVuIfK/R0ZsBsIOW4BZNfb4BRpRW41Do1u+ozJpsb+mdoy80O20IzAsHaihRb5qA==} - '@vue/compiler-dom@3.5.0': - resolution: {integrity: sha512-xYjUybWZXl+1R/toDy815i4PbeehL2hThiSGkcpmIOCy2HoYyeeC/gAWK/Y/xsoK+GSw198/T5O31bYuQx5uvQ==} - '@vue/compiler-dom@3.5.3': resolution: {integrity: sha512-wnzFArg9zpvk/811CDOZOadJRugf1Bgl/TQ3RfV4nKfSPok4hi0w10ziYUQR6LnnBAUlEXYLUfZ71Oj9ds/+QA==} '@vue/compiler-sfc@2.7.16': resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==} - '@vue/compiler-sfc@3.5.0': - resolution: {integrity: sha512-B9DgLtrqok2GLuaFjLlSL15ZG3ZDBiitUH1ecex9guh/ZcA5MCdwuVE6nsfQxktuZY/QY0awJ35/ripIviCQTQ==} - '@vue/compiler-sfc@3.5.3': resolution: {integrity: sha512-P3uATLny2tfyvMB04OQFe7Sczteno7SLFxwrOA/dw01pBWQHB5HL15a8PosoNX2aG/EAMGqnXTu+1LnmzFhpTQ==} - '@vue/compiler-ssr@3.5.0': - resolution: {integrity: sha512-E263QZmA1dqRd7c3u/sWTLRMpQOT0aZ8av/L9SoD/v/BVMZaWFHPUUBswS+bzrfvG2suJF8vSLKx6k6ba5SUdA==} - '@vue/compiler-ssr@3.5.3': resolution: {integrity: sha512-F/5f+r2WzL/2YAPl7UlKcJWHrvoZN8XwEBLnT7S4BXwncH25iDOabhO2M2DWioyTguJAGavDOawejkFXj8EM1w==} @@ -6211,7 +6202,7 @@ snapshots: dependencies: '@vitejs/plugin-vue': 5.1.3(vite@5.4.3(@types/node@22.5.2)(less@4.2.0)(terser@5.31.6))(vue@3.5.3(typescript@5.6.1-rc)) '@vitejs/plugin-vue-jsx': 4.0.1(vite@5.4.3(@types/node@22.5.2)(less@4.2.0)(terser@5.31.6))(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-sfc': 3.5.0 + '@vue/compiler-sfc': 3.5.3 astro: 4.15.2(@types/node@22.5.2)(less@4.2.0)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.1-rc) vite-plugin-vue-devtools: 7.3.9(@nuxt/kit@3.13.0(magicast@0.3.5)(rollup@4.21.2))(rollup@4.21.2)(vite@5.4.3(@types/node@22.5.2)(less@4.2.0)(terser@5.31.6))(vue@3.5.3(typescript@5.6.1-rc)) vue: 3.5.3(typescript@5.6.1-rc) @@ -8069,7 +8060,7 @@ snapshots: '@vue-macros/boolean-prop@0.4.4(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-core': 3.5.0 + '@vue/compiler-core': 3.5.3 transitivePeerDependencies: - rollup - vue @@ -8086,7 +8077,7 @@ snapshots: dependencies: '@babel/types': 7.25.6 '@rollup/pluginutils': 5.1.0(rollup@4.21.2) - '@vue/compiler-sfc': 3.5.0 + '@vue/compiler-sfc': 3.5.3 ast-kit: 1.1.0 local-pkg: 0.5.0 magic-string-ast: 0.6.2 @@ -8179,7 +8170,7 @@ snapshots: '@vue-macros/export-expose@0.2.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-sfc': 3.5.0 + '@vue/compiler-sfc': 3.5.3 unplugin: 1.12.3 vue: 3.5.3(typescript@5.6.1-rc) transitivePeerDependencies: @@ -8196,7 +8187,7 @@ snapshots: '@vue-macros/export-render@0.2.9(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-sfc': 3.5.0 + '@vue/compiler-sfc': 3.5.3 unplugin: 1.12.3 vue: 3.5.3(typescript@5.6.1-rc) transitivePeerDependencies: @@ -8222,7 +8213,7 @@ snapshots: '@vue-macros/named-template@0.4.9(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-dom': 3.5.0 + '@vue/compiler-dom': 3.5.3 unplugin: 1.12.3 transitivePeerDependencies: - rollup @@ -8232,8 +8223,8 @@ snapshots: dependencies: '@babel/parser': 7.25.6 '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-core': 3.5.0 - '@vue/shared': 3.5.0 + '@vue/compiler-core': 3.5.3 + '@vue/shared': 3.5.3 magic-string: 0.30.11 unplugin: 1.12.3 vue: 3.5.3(typescript@5.6.1-rc) @@ -8251,7 +8242,7 @@ snapshots: '@vue-macros/setup-block@0.3.9(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-dom': 3.5.0 + '@vue/compiler-dom': 3.5.3 unplugin: 1.12.3 transitivePeerDependencies: - rollup @@ -8276,7 +8267,7 @@ snapshots: '@vue-macros/short-bind@1.0.3(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-core': 3.5.0 + '@vue/compiler-core': 3.5.3 transitivePeerDependencies: - rollup - vue @@ -8292,7 +8283,7 @@ snapshots: '@vue-macros/short-vmodel@1.4.9(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc))': dependencies: '@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.3(typescript@5.6.1-rc)) - '@vue/compiler-core': 3.5.0 + '@vue/compiler-core': 3.5.3 transitivePeerDependencies: - rollup - vue @@ -8345,7 +8336,7 @@ snapshots: '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 '@babel/parser': 7.25.6 - '@vue/compiler-sfc': 3.5.0 + '@vue/compiler-sfc': 3.5.3 '@vue/babel-plugin-transform-vue-jsx@1.4.0(@babel/core@7.25.2)': dependencies: @@ -8416,14 +8407,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vue/compiler-core@3.5.0': - dependencies: - '@babel/parser': 7.25.6 - '@vue/shared': 3.5.0 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.0 - '@vue/compiler-core@3.5.3': dependencies: '@babel/parser': 7.25.6 @@ -8432,11 +8415,6 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.0 - '@vue/compiler-dom@3.5.0': - dependencies: - '@vue/compiler-core': 3.5.0 - '@vue/shared': 3.5.0 - '@vue/compiler-dom@3.5.3': dependencies: '@vue/compiler-core': 3.5.3 @@ -8450,18 +8428,6 @@ snapshots: optionalDependencies: prettier: 2.8.8 - '@vue/compiler-sfc@3.5.0': - dependencies: - '@babel/parser': 7.25.6 - '@vue/compiler-core': 3.5.0 - '@vue/compiler-dom': 3.5.0 - '@vue/compiler-ssr': 3.5.0 - '@vue/shared': 3.5.0 - estree-walker: 2.0.2 - magic-string: 0.30.11 - postcss: 8.4.44 - source-map-js: 1.2.0 - '@vue/compiler-sfc@3.5.3': dependencies: '@babel/parser': 7.25.6 @@ -8474,11 +8440,6 @@ snapshots: postcss: 8.4.44 source-map-js: 1.2.0 - '@vue/compiler-ssr@3.5.0': - dependencies: - '@vue/compiler-dom': 3.5.0 - '@vue/shared': 3.5.0 - '@vue/compiler-ssr@3.5.3': dependencies: '@vue/compiler-dom': 3.5.3 @@ -8543,7 +8504,7 @@ snapshots: '@vue/language-core@2.0.29(typescript@5.6.1-rc)': dependencies: '@volar/language-core': 2.4.1 - '@vue/compiler-dom': 3.5.0 + '@vue/compiler-dom': 3.5.3 '@vue/compiler-vue2': 2.7.16 '@vue/shared': 3.5.0 computeds: 0.0.1 @@ -12145,7 +12106,7 @@ snapshots: '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2) '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) - '@vue/compiler-dom': 3.5.0 + '@vue/compiler-dom': 3.5.3 kolorist: 1.8.0 magic-string: 0.30.11 vite: 5.4.3(@types/node@22.5.2)(less@4.2.0)(terser@5.31.6) From e40402745089d7f58d8ca402a0a0a910f4daeac9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 01:08:19 +0800 Subject: [PATCH 004/156] fix: typo --- packages/jsx-macros/tests/fixtures/define-expose.tsx | 4 ++-- packages/jsx-macros/tests/fixtures/define-model.tsx | 2 +- playground/vue3/package.json | 1 - playground/vue3/vue-macros.config.ts | 4 +++- pnpm-lock.yaml | 3 --- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/jsx-macros/tests/fixtures/define-expose.tsx b/packages/jsx-macros/tests/fixtures/define-expose.tsx index 87e806d44..88c3978ba 100644 --- a/packages/jsx-macros/tests/fixtures/define-expose.tsx +++ b/packages/jsx-macros/tests/fixtures/define-expose.tsx @@ -1,6 +1,6 @@ -export default function(){ +export default function () { defineExpose({ - foo: 1 + foo: 1, }) return
} diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 06d9ef950..722ccc8c6 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -1,4 +1,4 @@ -export default function(){ +export default function () { const foo = defineModel('foo') return
{foo.value}
} diff --git a/playground/vue3/package.json b/playground/vue3/package.json index 16aecd946..9825be9d0 100644 --- a/playground/vue3/package.json +++ b/playground/vue3/package.json @@ -12,7 +12,6 @@ "typecheck": "vue-tsc --noEmit" }, "dependencies": { - "@vue-macros/jsx-macros": "workspace:*", "@vueuse/core": "^11.0.3", "quasar": "^2.16.9", "vue": "catalog:" diff --git a/playground/vue3/vue-macros.config.ts b/playground/vue3/vue-macros.config.ts index fc2bf1593..860e3db12 100644 --- a/playground/vue3/vue-macros.config.ts +++ b/playground/vue3/vue-macros.config.ts @@ -21,7 +21,9 @@ export default defineConfig({ namedTemplate: false, reactivityTransform: true, scriptLang: true, - scriptSFC: true, + scriptSFC: { + include: [/script-sfc.*\.tsx$/, /jsx-macros.*\.tsx$/], + }, setupBlock: true, setupSFC: true, shortBind: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4a35269c..1448235de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1032,9 +1032,6 @@ importers: playground/vue3: dependencies: - '@vue-macros/jsx-macros': - specifier: workspace:* - version: link:../../packages/jsx-macros '@vueuse/core': specifier: ^11.0.3 version: 11.0.3(vue@3.5.3(typescript@5.6.1-rc)) From 5608c7c5769a64c0103adb97044c11f3d5841a94 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 01:28:25 +0800 Subject: [PATCH 005/156] chore: up snap --- packages/jsx-macros/package.json | 33 +++++++++---------- .../tests/__snapshots__/fixtures.test.ts.snap | 6 ++-- packages/volar/package.json | 14 +++++--- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 317c84ce9..467df8b42 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,14 +1,16 @@ { "name": "@vue-macros/jsx-macros", "version": "0.0.0", - "packageManager": "pnpm@9.7.0", - "description": "define-slots feature from Vue Macros.", + "packageManager": "pnpm@9.9.0", + "description": "jsx-macros feature from Vue Macros.", "type": "commonjs", "keywords": [ "vue-macros", "macros", "vue", "sfc", + "setup", + "script-setup", "jsx-macros", "unplugin" ], @@ -20,11 +22,10 @@ "repository": { "type": "git", "url": "git+https://github.com/vue-macros/vue-macros.git", - "directory": "packages/define-slots" + "directory": "packages/jsx-macros" }, "author": "三咲智子 ", "files": [ - "*.d.ts", "dist" ], "main": "dist/index.js", @@ -46,6 +47,11 @@ "require": "./dist/esbuild.js", "import": "./dist/esbuild.mjs" }, + "./helpers": { + "dev": "./src/helpers.ts", + "require": "./dist/helpers.js", + "import": "./dist/helpers.mjs" + }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.js", @@ -71,15 +77,7 @@ "require": "./dist/webpack.js", "import": "./dist/webpack.mjs" }, - "./helpers": { - "dev": "./src/helpers.ts", - "require": "./dist/helpers.js", - "import": "./dist/helpers.mjs" - }, - "./*": [ - "./*", - "./*.d.ts" - ] + "./*": "./*" }, "typesVersions": { "*": { @@ -104,6 +102,10 @@ "require": "./dist/esbuild.js", "import": "./dist/esbuild.mjs" }, + "./helpers": { + "require": "./dist/helpers.js", + "import": "./dist/helpers.mjs" + }, "./rolldown": { "require": "./dist/rolldown.js", "import": "./dist/rolldown.mjs" @@ -124,10 +126,7 @@ "require": "./dist/webpack.js", "import": "./dist/webpack.mjs" }, - "./*": [ - "./*", - "./*.d.ts" - ] + "./*": "./*" } }, "scripts": { diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index fcc1a6e5a..683d99517 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -3,9 +3,9 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "@vue-macros/jsx-macros/helpers"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function(_props){ +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { - foo: 1 + foo: 1, }) return
} @@ -14,7 +14,7 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "@vue-macros/jsx-macros/helpers";export default function(_props){ +import { useModel as __MACROS_useModel } from "@vue-macros/jsx-macros/helpers";export default function (_props) { const foo = __MACROS_useModel(_props, 'foo') return
{foo.value}
} diff --git a/packages/volar/package.json b/packages/volar/package.json index d39f67f4d..d38e05604 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -107,6 +107,11 @@ "require": "./dist/jsx-directive.js", "import": "./dist/jsx-directive.mjs" }, + "./jsx-macros": { + "dev": "./src/jsx-macros.ts", + "require": "./dist/jsx-macros.js", + "import": "./dist/jsx-macros.mjs" + }, "./script-lang": { "dev": "./src/script-lang.ts", "require": "./dist/script-lang.js", @@ -142,11 +147,6 @@ "require": "./dist/template-ref.js", "import": "./dist/template-ref.mjs" }, - "./jsx-macros": { - "dev": "./src/jsx-macros.ts", - "require": "./dist/jsx-macros.js", - "import": "./dist/jsx-macros.mjs" - }, "./*": [ "./*", "./*.d.ts" @@ -223,6 +223,10 @@ "require": "./dist/jsx-directive.js", "import": "./dist/jsx-directive.mjs" }, + "./jsx-macros": { + "require": "./dist/jsx-macros.js", + "import": "./dist/jsx-macros.mjs" + }, "./script-lang": { "require": "./dist/script-lang.js", "import": "./dist/script-lang.mjs" From bf88321d5f35af7539d4f07900d47f66f6d1609e Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 02:11:08 +0800 Subject: [PATCH 006/156] fix: remove @vue/compiler-core --- packages/volar/package.json | 1 - pnpm-lock.yaml | 3 --- 2 files changed, 4 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index d38e05604..e7a289d07 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -284,7 +284,6 @@ "muggle-string": "^0.4.1" }, "devDependencies": { - "@vue/compiler-core": "catalog:", "typescript": "catalog:", "vue-tsc": "catalog:" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1448235de..031602007 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -938,9 +938,6 @@ importers: specifier: ^0.4.1 version: 0.4.1 devDependencies: - '@vue/compiler-core': - specifier: 'catalog:' - version: 3.5.3 typescript: specifier: 'catalog:' version: 5.6.1-rc From e4e7a09cd4ceaf09db25dff428f482163e98746d Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 02:46:10 +0800 Subject: [PATCH 007/156] feat: use virtual id --- packages/jsx-macros/src/core/helper/index.ts | 9 +++ .../jsx-macros/src/core/helper/use-expose.ts | 6 ++ .../jsx-macros/src/core/helper/use-model.ts | 54 ++++++++++++++++ packages/jsx-macros/src/core/index.ts | 5 +- packages/jsx-macros/src/helpers.ts | 63 +------------------ packages/jsx-macros/src/index.ts | 21 +++++++ 6 files changed, 95 insertions(+), 63 deletions(-) create mode 100644 packages/jsx-macros/src/core/helper/index.ts create mode 100644 packages/jsx-macros/src/core/helper/use-expose.ts create mode 100644 packages/jsx-macros/src/core/helper/use-model.ts diff --git a/packages/jsx-macros/src/core/helper/index.ts b/packages/jsx-macros/src/core/helper/index.ts new file mode 100644 index 000000000..26896a0b9 --- /dev/null +++ b/packages/jsx-macros/src/core/helper/index.ts @@ -0,0 +1,9 @@ +import { VIRTUAL_ID_PREFIX } from '@vue-macros/common' + +export const helperPrefix: '/vue-macros/jsx-macros' = `${VIRTUAL_ID_PREFIX}/jsx-macros` + +export const useExposeHelperId: '/vue-macros/jsx-macros/use-expose' = `${helperPrefix}/use-expose` +export { default as useExposeHelperCode } from './use-expose?raw' + +export const useModelHelperId: '/vue-macros/jsx-macros/use-model' = `${helperPrefix}/use-model` +export { default as useModelHelperCode } from './use-model?raw' diff --git a/packages/jsx-macros/src/core/helper/use-expose.ts b/packages/jsx-macros/src/core/helper/use-expose.ts new file mode 100644 index 000000000..e9633a73f --- /dev/null +++ b/packages/jsx-macros/src/core/helper/use-expose.ts @@ -0,0 +1,6 @@ +export function useExpose(i: any, exposed = {}): void { + if (i) { + i.exposed = exposed + if (i.vnode) i.vnode.shapeFlag = 4 + } +} diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts new file mode 100644 index 000000000..5f302227b --- /dev/null +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -0,0 +1,54 @@ +import { camelize, type ModelRef } from 'vue' + +type DefineModelOptions> = { + default?: any + get?: (v: T) => any + set?: (v: T) => any +} +export function useModel< + M extends PropertyKey, + T extends Record, + K extends keyof T, +>(props: T, name: K, options?: DefineModelOptions): ModelRef +export function useModel( + props: Record, + name: string = 'modelValue', + options: DefineModelOptions = {}, +): any { + name = camelize(name) + const modifiers = getModelModifiers(props, name) + const res = { + get value() { + const result = props?.[name] ?? options?.default + return options?.get ? options.get(result) : result + }, + set value(v) { + props?.[`onUpdate:${name}`]?.(v) + }, + __v_isRef: true, + } + + // @ts-expect-error + res[Symbol.iterator] = () => { + let i = 0 + return { + next() { + if (i < 2) { + return { value: i++ ? modifiers || {} : res, done: false } + } else { + return { done: true } + } + }, + } + } + return res +} + +export const getModelModifiers = ( + props: Record, + modelName: string, +): Record | undefined => { + return modelName === 'modelValue' + ? props.modelModifiers + : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index cd497f1fa..f72a44f0d 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -8,6 +8,7 @@ import { type CodeTransform, } from '@vue-macros/common' import type { OptionsResolved } from '..' +import { useExposeHelperId, useModelHelperId } from './helper' import type { ArrowFunctionExpression, CallExpression, @@ -111,7 +112,7 @@ export function transformJsxMacros( } else if (macroName === 'defineModel') { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useModel', '@vue-macros/jsx-macros/helpers'), + importHelperFn(s, 0, 'useModel', useModelHelperId), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, @@ -120,7 +121,7 @@ export function transformJsxMacros( } else if (macroName === 'defineExpose') { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useExpose', '@vue-macros/jsx-macros/helpers'), + importHelperFn(s, 0, 'useExpose', useExposeHelperId), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, diff --git a/packages/jsx-macros/src/helpers.ts b/packages/jsx-macros/src/helpers.ts index d745bd6b0..c68c820de 100644 --- a/packages/jsx-macros/src/helpers.ts +++ b/packages/jsx-macros/src/helpers.ts @@ -1,61 +1,2 @@ -import { camelize, type ModelRef } from 'vue' - -export function useExpose(i: any, exposed = {}): void { - if (i) { - i.exposed = exposed - if (i.vnode) i.vnode.shapeFlag = 4 - } -} - -export type DefineModelOptions> = { - default?: any - get?: (v: T) => any - set?: (v: T) => any -} -export function useModel< - M extends PropertyKey, - T extends Record, - K extends keyof T, ->(props: T, name: K, options?: DefineModelOptions): ModelRef -export function useModel( - props: Record, - name: string = 'modelValue', - options: DefineModelOptions = {}, -): any { - name = camelize(name) - const modifiers = getModelModifiers(props, name) - const res = { - get value() { - const result = props?.[name] ?? options?.default - return options?.get ? options.get(result) : result - }, - set value(v) { - props?.[`onUpdate:${name}`]?.(v) - }, - __v_isRef: true, - } - - // @ts-expect-error - res[Symbol.iterator] = () => { - let i = 0 - return { - next() { - if (i < 2) { - return { value: i++ ? modifiers || {} : res, done: false } - } else { - return { done: true } - } - }, - } - } - return res -} - -export const getModelModifiers = ( - props: Record, - modelName: string, -): Record | undefined => { - return modelName === 'modelValue' - ? props.modelModifiers - : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] -} +export { useExpose } from './core/helper/use-expose' +export { useModel } from './core/helper/use-model' diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index db1e083cf..d137dd3cc 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -3,6 +3,7 @@ import { detectVueVersion, FilterFileType, getFilterPattern, + normalizePath, REGEX_SETUP_SFC, type BaseOptions, type MarkRequired, @@ -14,6 +15,13 @@ import { } from 'unplugin' import { generatePluginName } from '#macros' with { type: 'macro' } import { transformJsxMacros } from './core' +import { + helperPrefix, + useExposeHelperCode, + useExposeHelperId, + useModelHelperCode, + useModelHelperId, +} from './core/helper' export type Options = BaseOptions & { lib?: string @@ -46,6 +54,19 @@ const plugin: UnpluginInstance = createUnplugin( return { name, enforce: 'pre', + + resolveId(id) { + if (normalizePath(id).startsWith(helperPrefix)) return id + }, + loadInclude(id) { + return normalizePath(id).startsWith(helperPrefix) + }, + load(_id) { + const id = normalizePath(_id) + if (id === useExposeHelperId) return useExposeHelperCode + else if (id === useModelHelperId) return useModelHelperCode + }, + transformInclude: filter, transform(code, id) { return transformJsxMacros(code, id, options) From e716a080e1d583c699f11604fdd47ae7ee59e857 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 7 Sep 2024 02:53:44 +0800 Subject: [PATCH 008/156] chore: up snap --- packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 683d99517..b107b81b6 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -2,7 +2,7 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { useExpose as __MACROS_useExpose } from "@vue-macros/jsx-macros/helpers"; +import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, @@ -14,7 +14,7 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "@vue-macros/jsx-macros/helpers";export default function (_props) { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export default function (_props) { const foo = __MACROS_useModel(_props, 'foo') return
{foo.value}
} From b1e123db076d612afdeb860840aee870c2228b52 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 8 Sep 2024 18:32:06 +0800 Subject: [PATCH 009/156] chore: use HELPER_PREFIX --- packages/jsx-macros/src/core/index.ts | 12 +- .../tests/__snapshots__/fixtures.test.ts.snap | 10 +- packages/volar/src/common.ts | 3 +- packages/volar/src/jsx-directive/context.ts | 89 ++++++-- packages/volar/src/jsx-macros.ts | 216 ++++++++++-------- 5 files changed, 208 insertions(+), 122 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index f72a44f0d..6273c657b 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -2,6 +2,7 @@ import { babelParse, generateTransform, getLang, + HELPER_PREFIX, importHelperFn, MagicStringAST, walkAST, @@ -68,7 +69,7 @@ export function transformJsxMacros( }) for (const [root, map] of roots) { - let propsName = '_props' + let propsName = `${HELPER_PREFIX}props` const paramsStart = root.params[0] ? root.params[0].start! : root.start! + @@ -87,11 +88,14 @@ export function transformJsxMacros( root.params[0].type === 'ObjectPattern' && root.params[0].properties.at(-1) ) { - s.appendLeft(root.params[0].properties.at(-1)!.end!, `, ..._props`) + s.appendLeft( + root.params[0].properties.at(-1)!.end!, + `, ...${HELPER_PREFIX}props`, + ) } } } else { - s.appendRight(paramsStart, '_props') + s.appendRight(paramsStart, `${HELPER_PREFIX}props`) } for (const [macroName, nodes] of map) { @@ -104,7 +108,7 @@ export function transformJsxMacros( node.callee.end!, `Object.assign`, ) - const slots = `${importHelperFn(s, 0, 'getCurrentInstance', options.lib)}().slots` + const slots = `${importHelperFn(s, 0, 'getCurrentInstance', options.lib)}()?.slots` s.appendLeft( node.end! - 1, `${node.arguments[0] ? ',' : '{}, '}${slots}`, diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index b107b81b6..bdb659339 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -3,7 +3,7 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (_props) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) @@ -14,8 +14,8 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export default function (_props) { - const foo = __MACROS_useModel(_props, 'foo') +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export default function (__MACROS_props) { + const foo = __MACROS_useModel(__MACROS_props, 'foo') return
{foo.value}
} " @@ -23,10 +23,10 @@ import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model" exports[`fixtures > ./fixtures/define-slots.tsx 1`] = ` " -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (_props) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { const slots = Object.assign({ default: () =>
default
, - },__MACROS_getCurrentInstance().slots) + },__MACROS_getCurrentInstance()?.slots) return
{slots.default()}
} " diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index 8cdc5c8d0..44d5d2b23 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -144,10 +144,9 @@ export function getStart( } export function getText( - node: import('typescript').Node | undefined, + node: import('typescript').Node, context: VolarContext, ): string { - if (!node) return '' const { sfc, source = 'scriptSetup' } = context return sfc[source]!.content.slice(getStart(node, context), node.end) } diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 8dc5c5c64..934d31c4a 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -16,33 +16,92 @@ export function transformCtx( const openingElement = getOpeningElement(node, options) if (!openingElement) return '' + if (!codes.toString().includes('function __VLS_getFunctionalComponentCtx')) { + codes.push(` +function __VLS_getFunctionalComponentCtx( + comp: T, + compInstance: K, + s: S, +): S extends keyof typeof __VLS_nativeElements + ? { expose: (exposed: (typeof __VLS_nativeElements)[S]) => any } + : '__ctx' extends keyof __VLS_PickNotAny + ? K extends { __ctx?: infer Ctx } + ? { slots: Ctx['props']['vSlots'] } & Ctx + : never + : T extends (props: infer P, ctx: infer Ctx) => any + ? { props: P; slots: P['vSlots'] } & Ctx + : {};\n`) + } + let props = '' + let refValue for (const prop of openingElement.attributes.properties) { if (!ts.isJsxAttribute(prop)) continue - const name = getText(prop.name, options) - if (name.startsWith('v-')) continue - const value = isJsxExpression(prop.initializer) - ? getText(prop.initializer.expression!, options) + let name = getText(prop.name, options) + if ( + name === 'ref' && + prop.initializer && + isJsxExpression(prop.initializer) && + prop.initializer.expression + ) { + refValue = getRefValue(prop.initializer.expression, options) + continue + } + + if (name.startsWith('v-model')) { + name = name.split('_')[0].split(':')[1] || 'modelValue' + } else if (name.startsWith('v-')) { + continue + } + + const value = prop.initializer + ? isJsxExpression(prop.initializer) && prop.initializer.expression + ? getText(prop.initializer.expression, options) + : getText(prop.initializer, options) : 'true' props += `'${name}': ${value},` } + const ctxName = `__VLS_ctx_${refValue || index}` const tagName = getTagName(node, { ...options, withTypes: true }) - const ctxName = `__VLS_ctx${index}` - if (!codes.toString().includes('function __VLS_getFunctionalComponentCtx')) { - codes.push( - `function __VLS_getFunctionalComponentCtx(comp: T, compInstance: K): __VLS_PickNotAny< - '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } ? Ctx : never : any - , T extends (props: infer P, ctx: infer Ctx) => any ? { props: P, slots: P['vSlots'] } & Ctx : any>; -`, - ) - } - addCode( codes, - `const ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}));\n`, + `const ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}), '${tagName}');\n`, ) return ctxName } + +function getRefValue( + expression: import('typescript').Expression, + options: TransformOptions, +) { + const { ts } = options + + if (ts.isIdentifier(expression)) { + return getText(expression, options) + } else if (ts.isFunctionLike(expression)) { + let left + if (ts.isBinaryExpression(expression.body)) { + left = expression.body.left + } + ts.forEachChild(expression.body, (node) => { + if (ts.isBinaryExpression(node)) { + left = node.left + } else if ( + ts.isExpressionStatement(node) && + ts.isBinaryExpression(node.expression) + ) { + left = node.expression.left + } + }) + return ( + left && + getText( + ts.isPropertyAccessExpression(left) ? left.expression : left, + options, + ) + ) + } +} diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 2ad171fdf..7a3d658e4 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -1,33 +1,70 @@ -import { createFilter } from '@vue-macros/common' +import { createFilter, HELPER_PREFIX } from '@vue-macros/common' import { toValidAssetId } from '@vue/compiler-dom' import { allCodeFeatures } from '@vue/language-core' import { replaceSourceRange } from 'muggle-string' import { getStart, getText, type VueMacrosPlugin } from './common' import type { TransformOptions } from './jsx-directive/index' -import type { - ArrowFunction, - CallExpression, - FunctionDeclaration, - Node, -} from 'typescript' -function isFunction( - node: Node, +type RootMap = Map< + import('typescript').ArrowFunction | import('typescript').FunctionDeclaration, + Map +> + +function getMacroCall( + node: import('typescript').Node | undefined, ts: typeof import('typescript'), -): node is ArrowFunction | FunctionDeclaration { - return ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) +): import('typescript').CallExpression | undefined { + if (!node) return + + if (ts.isVariableStatement(node)) { + return ts.forEachChild(node.declarationList, (decl) => getExpression(decl)) + } else { + return getExpression(node) + } + + function getExpression(decl: import('typescript').Node) { + if ( + ts.isVariableDeclaration(decl) && + decl.initializer && + ts.isCallExpression(decl.initializer) && + ts.isIdentifier(decl.initializer.expression) + ) { + const expression = + decl.initializer.expression.escapedText === '$' + ? decl.initializer.arguments[0] + : decl.initializer + if (isMacroCall(expression)) return expression + } else if (ts.isExpressionStatement(decl) && isMacroCall(decl.expression)) { + return decl.expression + } + } + + function isMacroCall( + node: import('typescript').Node, + ): node is import('typescript').CallExpression { + return !!( + ts.isCallExpression(node) && + ts.isIdentifier(node.expression) && + ['defineSlots', 'defineModel', 'defineExpose'].includes( + node.expression.escapedText!, + ) + ) + } } -export function transformJsxMacros(options: TransformOptions): void { +function getRootMap(options: TransformOptions): RootMap { const { ts, sfc, source, codes } = options - const rootMap = new Map< - ArrowFunction | FunctionDeclaration, - Map - >() + const rootMap: RootMap = new Map() - function walk(node: Node, parents: Node[]) { + function walk( + node: import('typescript').Node, + parents: import('typescript').Node[], + ) { const root = - parents[1] && isFunction(parents[1], ts) ? parents[1] : undefined + parents[1] && + (ts.isArrowFunction(parents[1]) || ts.isFunctionDeclaration(parents[1])) + ? parents[1] + : undefined const macro = root && getMacroCall(node, ts) if (macro) { if (!rootMap.has(root)) { @@ -63,7 +100,7 @@ export function transformJsxMacros(options: TransformOptions): void { } } } - const id = toValidAssetId(modelName, '_VLS_model' as any) + const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) const typeString = `import("vue").UnwrapRef` const requiredString = required ? ':' : '?:' propMap @@ -77,8 +114,8 @@ export function transformJsxMacros(options: TransformOptions): void { source, getStart(macro, options), getStart(macro, options), - `${id}; let ${id} =`, - ['__MACROS_', source, getStart(macro, options), allCodeFeatures], + `// @ts-ignore\n${id};\nlet ${id} =`, + [HELPER_PREFIX, source, getStart(macro, options), allCodeFeatures], ) } else if (name === 'defineSlots') { replaceSourceRange( @@ -86,27 +123,27 @@ export function transformJsxMacros(options: TransformOptions): void { source, getStart(macro, options), getStart(macro, options), - `__MACROS_slots; let __MACROS_slots =`, + `// @ts-ignore\n${HELPER_PREFIX}slots;\nlet ${HELPER_PREFIX}slots =`, [ - '__MACROS_', + HELPER_PREFIX, source, getStart(macro.expression, options), allCodeFeatures, ], ) - propMap.get(name)?.push('{ vSlots?: typeof __MACROS_slots }') + propMap.get(name)?.push(`{ vSlots?: typeof ${HELPER_PREFIX}slots }`) } else if (name === 'defineExpose') { replaceSourceRange( codes, source, getStart(macro, options), getStart(macro, options), - `let __MACROS_expose = ${getText(macro.arguments[0], options)};`, - ['__MACROS_', source, getStart(macro, options), allCodeFeatures], + `const ${HELPER_PREFIX}expose = ${getText(macro.arguments[0], options)};`, + [HELPER_PREFIX, source, getStart(macro, options), allCodeFeatures], ) propMap .get(name) - ?.push('{ vExpose?: (exposed: typeof __MACROS_expose) => any }') + ?.push(`(exposed: typeof ${HELPER_PREFIX}expose) => {}`) } } @@ -117,35 +154,47 @@ export function transformJsxMacros(options: TransformOptions): void { }) } ts.forEachChild(sfc[source]!.ast, (node) => walk(node, [])) + return rootMap +} - for (const [root, props] of rootMap) { - const result: string[] = [] - for (const [name, members] of props) { - if (name === 'defineModel') { - result.push(`{${members.join(', ')}}`) - } else { - result.push(members.join('')) - } - } +function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { + const { ts, source, codes } = options + for (const [root, props] of rootMap) { + const asyncPrefix = root.modifiers?.find( + (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, + ) + ? 'async' + : '' + const result = `({}) as Awaited['render'] & { __ctx: Awaited }` if (ts.isFunctionDeclaration(root) && root.body) { replaceSourceRange( codes, source, root.parameters.pos, - getStart(root.body, options), - `_props: `, + root.parameters.pos, + `${HELPER_PREFIX}props: `, root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` : '', - `Awaited['props'], __MACROS_setup = ((${getText(root.parameters[0], options)}) =>`, + `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncPrefix}(`, + ) + replaceSourceRange( + codes, + source, + getStart(root.body, options), + getStart(root.body, options), + '=>', ) replaceSourceRange( codes, source, root.body.end - 1, root.body.end - 1, - `})()){ return {} as Awaited['render']`, + `})({} as any)){ return `, + result, ) } else { replaceSourceRange( @@ -153,20 +202,22 @@ export function transformJsxMacros(options: TransformOptions): void { source, getStart(root.parameters, options), getStart(root.parameters, options), - `_props: `, + `${HELPER_PREFIX}props: `, root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` : '', - `Awaited['props'], __MACROS_setup = ((`, + `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncPrefix}(`, ) replaceSourceRange( codes, source, root.end, root.end, - `)()) => ({}) as Awaited['render']`, + `)({} as any)) => `, + result, ) } + root.body && ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { @@ -175,65 +226,37 @@ export function transformJsxMacros(options: TransformOptions): void { source, getStart(node, options), getStart(node.expression, options), - `return { props: {} as ${result.join(' &\n')},`, - `render: `, + `return {\nprops: {} as `, + props.get('defineModel')?.length + ? `{ ${props.get('defineModel')?.join(', ')} }` + : '{}', + props.get('defineSlots')?.length + ? ` & ${props.get('defineSlots')?.join()}` + : '', + props.get('defineExpose')?.length + ? `,\nexpose: ${props.get('defineExpose')?.join()}` + : '', + `,\nrender: `, ) replaceSourceRange( codes, source, node.expression.end, node.expression.end, - `}`, + `\n}`, ) } }) } - if (rootMap.size) { + if ( + rootMap.size && + !codes.toString().includes(`declare function ${HELPER_PREFIX}defineSlots`) + ) { codes.push(` -declare function __MACROS_defineSlots>(slots?: T): T -declare const __MACROS_defineExpose: typeof import('vue').defineExpose; -declare const __MACROS_defineModel: typeof import('vue').defineModel;\n`) - } -} - -function getMacroCall( - node: import('typescript').Node | undefined, - ts: typeof import('typescript'), -): CallExpression | undefined { - if (!node) return - - if (ts.isVariableStatement(node)) { - return ts.forEachChild(node.declarationList, (decl) => getExpression(decl)) - } else { - return getExpression(node) - } - - function getExpression(decl: Node) { - if ( - ts.isVariableDeclaration(decl) && - decl.initializer && - ts.isCallExpression(decl.initializer) && - ts.isIdentifier(decl.initializer.expression) - ) { - const expression = - decl.initializer.expression.escapedText === '$' - ? decl.initializer.arguments[0] - : decl.initializer - if (isMacroCall(expression)) return expression - } else if (ts.isExpressionStatement(decl) && isMacroCall(decl.expression)) { - return decl.expression - } - } - - function isMacroCall(node: Node): node is CallExpression { - return !!( - ts.isCallExpression(node) && - ts.isIdentifier(node.expression) && - ['defineSlots', 'defineModel', 'defineExpose'].includes( - node.expression.escapedText!, - ) - ) +declare function ${HELPER_PREFIX}defineSlots>(slots?: T): T +declare const ${HELPER_PREFIX}defineExpose: typeof import('vue').defineExpose; +declare const ${HELPER_PREFIX}defineModel: typeof import('vue').defineModel;\n`) } } @@ -249,14 +272,15 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { if (!filter(fileName) || !['tsx'].includes(embeddedFile.lang)) return for (const source of ['script', 'scriptSetup'] as const) { - if (!sfc[source]) return - transformJsxMacros({ - codes: embeddedFile.content, + if (!sfc[source]) continue + const options = { sfc, - ts: ctx.modules.typescript, source, - vueVersion: ctx.vueCompilerOptions.target, - }) + ts: ctx.modules.typescript, + codes: embeddedFile.content, + } + const rootMap = getRootMap(options) + if (rootMap.size) transformJsxMacros(rootMap, options) } }, } From 0be8011d7f75e98863e40143d0ec98dfefe61d66 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 8 Sep 2024 23:16:49 +0800 Subject: [PATCH 010/156] fix: typo --- packages/jsx-macros/src/core/helper/use-model.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts index 5f302227b..629a44e83 100644 --- a/packages/jsx-macros/src/core/helper/use-model.ts +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -19,11 +19,11 @@ export function useModel( const modifiers = getModelModifiers(props, name) const res = { get value() { - const result = props?.[name] ?? options?.default + const result = props[name] ?? options?.default return options?.get ? options.get(result) : result }, set value(v) { - props?.[`onUpdate:${name}`]?.(v) + props[`onUpdate:${name}`]?.(v) }, __v_isRef: true, } From 2bcf0c3af33cdb4117dd424c39e387cc83e03b55 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 8 Sep 2024 23:29:25 +0800 Subject: [PATCH 011/156] refactor: vite plugin --- packages/jsx-macros/src/core/index.ts | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 6273c657b..d9fe4ef49 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -18,19 +18,13 @@ import type { Node, } from '@babel/types' -export function transformJsxMacros( - code: string, - id: string, - options: OptionsResolved, -): CodeTransform | undefined { - const s = new MagicStringAST(code) - +function getRootMap(s: MagicStringAST, id: string) { const parents: (Node | undefined | null)[] = [] - const roots: Map< + const rootMap: Map< FunctionDeclaration | FunctionExpression | ArrowFunctionExpression, Map > = new Map() - walkAST(babelParse(code, getLang(id)), { + walkAST(babelParse(s.toString(), getLang(id)), { enter(node, parent) { parents.unshift(parent) const expression = @@ -48,8 +42,8 @@ export function transformJsxMacros( : undefined if (!root || !isMacro(expression)) return - if (!roots.has(root)) - roots.set( + if (!rootMap.has(root)) + rootMap.set( root, new Map([ ['defineModel', []], @@ -57,7 +51,7 @@ export function transformJsxMacros( ['defineExpose', []], ]), ) - const map = roots.get(root)! + const map = rootMap.get(root)! const macroName = s.sliceNode(expression.callee) if (macroName) { map.get(macroName)?.push(expression) @@ -67,8 +61,18 @@ export function transformJsxMacros( parents.shift() }, }) + return rootMap +} + +export function transformJsxMacros( + code: string, + id: string, + options: OptionsResolved, +): CodeTransform | undefined { + const s = new MagicStringAST(code) + const rootMap = getRootMap(s, id) - for (const [root, map] of roots) { + for (const [root, map] of rootMap) { let propsName = `${HELPER_PREFIX}props` const paramsStart = root.params[0] ? root.params[0].start! From e9cfb36c37a5883273052ec371e740853169ebcf Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 9 Sep 2024 14:24:12 +0800 Subject: [PATCH 012/156] fix: syntax error --- packages/jsx-macros/src/core/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index d9fe4ef49..acd2cd236 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -92,8 +92,9 @@ export function transformJsxMacros( root.params[0].type === 'ObjectPattern' && root.params[0].properties.at(-1) ) { - s.appendLeft( + s.overwrite( root.params[0].properties.at(-1)!.end!, + root.params[0].end! - 1, `, ...${HELPER_PREFIX}props`, ) } From b1176bbd46b752dca2ffbd4b80b056af6fe01ddf Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 10 Sep 2024 23:02:22 +0800 Subject: [PATCH 013/156] feat: support FunctionExpression --- .../tests/__snapshots__/fixtures.test.ts.snap | 30 ++++- .../tests/fixtures/define-model.tsx | 5 + .../tests/fixtures/define-slots.tsx | 7 ++ packages/volar/src/jsx-macros.ts | 113 +++++++++--------- 4 files changed, 99 insertions(+), 56 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index bdb659339..d9731f956 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -14,7 +14,12 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export default function (__MACROS_props) { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props}) => { + const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) + return
{foo.value}
+} + +export default function (__MACROS_props) { const foo = __MACROS_useModel(__MACROS_props, 'foo') return
{foo.value}
} @@ -23,7 +28,14 @@ import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model" exports[`fixtures > ./fixtures/define-slots.tsx 1`] = ` " -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export const Comp = (__MACROS_props) => { + const slots = Object.assign<{ + default: () => any + }>({}, __MACROS_getCurrentInstance()?.slots) + return
{slots.default()}
+} + +export default function (__MACROS_props) { const slots = Object.assign({ default: () =>
default
, },__MACROS_getCurrentInstance()?.slots) @@ -31,3 +43,17 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d } " `; + +exports[`fixtures > ./fixtures/index.tsx 1`] = ` +" +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = (__MACROS_props) => { + __MACROS_useModel(__MACROS_props, 'foo') + return
+} + +export const Comp1 = (__MACROS_props) => { + __MACROS_useModel(__MACROS_props, 'foo') + return
+} +" +`; diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 722ccc8c6..609713b80 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -1,3 +1,8 @@ +export const Comp = ({ bar }: { bar: string }) => { + const foo = defineModel('foo', { default: bar }) + return
{foo.value}
+} + export default function () { const foo = defineModel('foo') return
{foo.value}
diff --git a/packages/jsx-macros/tests/fixtures/define-slots.tsx b/packages/jsx-macros/tests/fixtures/define-slots.tsx index 9646e9f7b..d9ed24ff4 100644 --- a/packages/jsx-macros/tests/fixtures/define-slots.tsx +++ b/packages/jsx-macros/tests/fixtures/define-slots.tsx @@ -1,3 +1,10 @@ +export const Comp = () => { + const slots = defineSlots<{ + default: () => any + }>() + return
{slots.default()}
+} + export default function () { const slots = defineSlots({ default: () =>
default
, diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 7a3d658e4..5a724b23d 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -6,11 +6,13 @@ import { getStart, getText, type VueMacrosPlugin } from './common' import type { TransformOptions } from './jsx-directive/index' type RootMap = Map< - import('typescript').ArrowFunction | import('typescript').FunctionDeclaration, + | import('typescript').ArrowFunction + | import('typescript').FunctionExpression + | import('typescript').FunctionDeclaration, Map > -function getMacroCall( +function getMacro( node: import('typescript').Node | undefined, ts: typeof import('typescript'), ): import('typescript').CallExpression | undefined { @@ -33,13 +35,13 @@ function getMacroCall( decl.initializer.expression.escapedText === '$' ? decl.initializer.arguments[0] : decl.initializer - if (isMacroCall(expression)) return expression - } else if (ts.isExpressionStatement(decl) && isMacroCall(decl.expression)) { + if (isMacro(expression)) return expression + } else if (ts.isExpressionStatement(decl) && isMacro(decl.expression)) { return decl.expression } } - function isMacroCall( + function isMacro( node: import('typescript').Node, ): node is import('typescript').CallExpression { return !!( @@ -62,10 +64,12 @@ function getRootMap(options: TransformOptions): RootMap { ) { const root = parents[1] && - (ts.isArrowFunction(parents[1]) || ts.isFunctionDeclaration(parents[1])) + (ts.isArrowFunction(parents[1]) || + ts.isFunctionExpression(parents[1]) || + ts.isFunctionDeclaration(parents[1])) ? parents[1] : undefined - const macro = root && getMacroCall(node, ts) + const macro = root && getMacro(node, ts) if (macro) { if (!rootMap.has(root)) { rootMap.set( @@ -161,6 +165,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { const { ts, source, codes } = options for (const [root, props] of rootMap) { + if (!root.body) continue const asyncPrefix = root.modifiers?.find( (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, ) @@ -169,12 +174,13 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { const result = `({}) as Awaited['render'] & { __ctx: Awaited }` - if (ts.isFunctionDeclaration(root) && root.body) { + + if (ts.isArrowFunction(root)) { replaceSourceRange( codes, source, - root.parameters.pos, - root.parameters.pos, + getStart(root.parameters, options), + getStart(root.parameters, options), `${HELPER_PREFIX}props: `, root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` @@ -184,24 +190,17 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { replaceSourceRange( codes, source, - getStart(root.body, options), - getStart(root.body, options), - '=>', - ) - replaceSourceRange( - codes, - source, - root.body.end - 1, - root.body.end - 1, - `})({} as any)){ return `, + root.end, + root.end, + `)({} as any)) => `, result, ) } else { replaceSourceRange( codes, source, - getStart(root.parameters, options), - getStart(root.parameters, options), + root.parameters.pos, + root.parameters.pos, `${HELPER_PREFIX}props: `, root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` @@ -211,42 +210,48 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { replaceSourceRange( codes, source, - root.end, - root.end, - `)({} as any)) => `, + getStart(root.body, options), + getStart(root.body, options), + '=>', + ) + replaceSourceRange( + codes, + source, + root.body.end - 1, + root.body.end - 1, + `})({} as any)){ return `, result, ) } - root.body && - ts.forEachChild(root.body, (node) => { - if (ts.isReturnStatement(node) && node.expression) { - replaceSourceRange( - codes, - source, - getStart(node, options), - getStart(node.expression, options), - `return {\nprops: {} as `, - props.get('defineModel')?.length - ? `{ ${props.get('defineModel')?.join(', ')} }` - : '{}', - props.get('defineSlots')?.length - ? ` & ${props.get('defineSlots')?.join()}` - : '', - props.get('defineExpose')?.length - ? `,\nexpose: ${props.get('defineExpose')?.join()}` - : '', - `,\nrender: `, - ) - replaceSourceRange( - codes, - source, - node.expression.end, - node.expression.end, - `\n}`, - ) - } - }) + ts.forEachChild(root.body, (node) => { + if (ts.isReturnStatement(node) && node.expression) { + replaceSourceRange( + codes, + source, + getStart(node, options), + getStart(node.expression, options), + `return {\nprops: {} as `, + props.get('defineModel')?.length + ? `{ ${props.get('defineModel')?.join(', ')} }` + : '{}', + props.get('defineSlots')?.length + ? ` & ${props.get('defineSlots')?.join()}` + : '', + props.get('defineExpose')?.length + ? `,\nexpose: ${props.get('defineExpose')?.join()}` + : '', + `,\nrender: `, + ) + replaceSourceRange( + codes, + source, + node.expression.end, + node.expression.end, + `\n}`, + ) + } + }) } if ( From 98a0ac7b804dce08c2940d4ae26ef209f1db6002 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 10 Sep 2024 23:11:06 +0800 Subject: [PATCH 014/156] fix: pnpm --- pnpm-lock.yaml | 104 +++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 68 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ea506934..ef01e1314 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -178,16 +178,16 @@ importers: version: 2.2.246 '@nolebase/vitepress-plugin-enhanced-mark': specifier: ^2.5.0 - version: 2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + version: 2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) '@nolebase/vitepress-plugin-enhanced-readabilities': specifier: ^2.5.0 - version: 2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + version: 2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) '@nolebase/vitepress-plugin-git-changelog': specifier: ^2.5.0 - version: 2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + version: 2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) '@nolebase/vitepress-plugin-highlight-targeted-heading': specifier: ^2.5.0 - version: 2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + version: 2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) '@shikijs/vitepress-twoslash': specifier: ^1.16.3 version: 1.16.3(@nuxt/kit@3.13.1(magicast@0.3.5)(rollup@4.21.2)(webpack-sources@3.2.3))(typescript@5.6.2) @@ -205,7 +205,7 @@ importers: version: 7.4.4(@nuxt/kit@3.13.1(magicast@0.3.5)(rollup@4.21.2)(webpack-sources@3.2.3))(rollup@4.21.2)(vite@5.4.3(@types/node@22.5.4)(less@4.2.0)(terser@5.32.0))(vue@3.5.3(typescript@5.6.2)) vitepress: specifier: ^1.3.4 - version: 1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + version: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) vitepress-plugin-group-icons: specifier: ^1.1.0 version: 1.1.0 @@ -623,11 +623,11 @@ importers: version: link:../common unplugin: specifier: 'catalog:' - version: 1.13.1(webpack-sources@3.2.3) + version: 1.14.0(webpack-sources@3.2.3) devDependencies: vue: specifier: 'catalog:' - version: 3.5.3(typescript@5.6.1-rc) + version: 3.5.3(typescript@5.6.2) packages/macros: dependencies: @@ -1131,20 +1131,12 @@ packages: '@algolia/client-common@4.24.0': resolution: {integrity: sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==} - '@algolia/client-common@5.3.2': - resolution: {integrity: sha512-4OxrO3q2FNgXCuOO8hUMt5saPwmY1efNLd9zzXbADnSwQHQeuAKLC/b2DZC+i9bCXXk3uENm7dKf4nm29/H0gw==} - engines: {node: '>= 14.0.0'} - '@algolia/client-personalization@4.24.0': resolution: {integrity: sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==} '@algolia/client-search@4.24.0': resolution: {integrity: sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==} - '@algolia/client-search@5.3.2': - resolution: {integrity: sha512-iJN3nylaSh9XuqUK0DRrRi/qwVqvA4PiWPydUB1a5NaceH7ng254GL4xwntAsX7RPIb8gQ2t65Gqoy5ToLs0kA==} - engines: {node: '>= 14.0.0'} - '@algolia/logger-common@4.24.0': resolution: {integrity: sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==} @@ -1157,20 +1149,12 @@ packages: '@algolia/requester-browser-xhr@4.24.0': resolution: {integrity: sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==} - '@algolia/requester-browser-xhr@5.3.2': - resolution: {integrity: sha512-5DVcWHuZZLbso2mgIsZ2KgPZGCQbgzgpjkAZZGlOc9xEEqUe3K7ZurqYKkfhYJmo7OQGoyEiqFNa71b3Yyparw==} - engines: {node: '>= 14.0.0'} - '@algolia/requester-common@4.24.0': resolution: {integrity: sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==} '@algolia/requester-node-http@4.24.0': resolution: {integrity: sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==} - '@algolia/requester-node-http@5.3.2': - resolution: {integrity: sha512-SgBoGAvPZRkTUkBvb4GU3qT7zVWJ947MQCdLBmZ4gkYwYkTq56NMmthMgpQY/Hfl08oOPQOILofSZnmEprqHng==} - engines: {node: '>= 14.0.0'} - '@algolia/transporter@4.24.0': resolution: {integrity: sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==} @@ -6331,31 +6315,31 @@ packages: snapshots: - '@algolia/autocomplete-core@1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0)': + '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)': dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0) - '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0) + '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - search-insights - '@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0)': + '@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)': dependencies: - '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0) + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0)': + '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)': dependencies: - '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0) - '@algolia/client-search': 5.3.2 + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) + '@algolia/client-search': 4.24.0 algoliasearch: 4.24.0 - '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0)': + '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)': dependencies: - '@algolia/client-search': 5.3.2 + '@algolia/client-search': 4.24.0 algoliasearch: 4.24.0 '@algolia/cache-browser-local-storage@4.24.0': @@ -6386,8 +6370,6 @@ snapshots: '@algolia/requester-common': 4.24.0 '@algolia/transporter': 4.24.0 - '@algolia/client-common@5.3.2': {} - '@algolia/client-personalization@4.24.0': dependencies: '@algolia/client-common': 4.24.0 @@ -6400,12 +6382,6 @@ snapshots: '@algolia/requester-common': 4.24.0 '@algolia/transporter': 4.24.0 - '@algolia/client-search@5.3.2': - dependencies: - '@algolia/client-common': 5.3.2 - '@algolia/requester-browser-xhr': 5.3.2 - '@algolia/requester-node-http': 5.3.2 - '@algolia/logger-common@4.24.0': {} '@algolia/logger-console@4.24.0': @@ -6430,20 +6406,12 @@ snapshots: dependencies: '@algolia/requester-common': 4.24.0 - '@algolia/requester-browser-xhr@5.3.2': - dependencies: - '@algolia/client-common': 5.3.2 - '@algolia/requester-common@4.24.0': {} '@algolia/requester-node-http@4.24.0': dependencies: '@algolia/requester-common': 4.24.0 - '@algolia/requester-node-http@5.3.2': - dependencies: - '@algolia/client-common': 5.3.2 - '@algolia/transporter@4.24.0': dependencies: '@algolia/cache-common': 4.24.0 @@ -7109,9 +7077,9 @@ snapshots: '@docsearch/css@3.6.1': {} - '@docsearch/js@3.6.1(@algolia/client-search@5.3.2)': + '@docsearch/js@3.6.1(@algolia/client-search@4.24.0)': dependencies: - '@docsearch/react': 3.6.1(@algolia/client-search@5.3.2) + '@docsearch/react': 3.6.1(@algolia/client-search@4.24.0) preact: 10.23.2 transitivePeerDependencies: - '@algolia/client-search' @@ -7120,10 +7088,10 @@ snapshots: - react-dom - search-insights - '@docsearch/react@3.6.1(@algolia/client-search@5.3.2)': + '@docsearch/react@3.6.1(@algolia/client-search@4.24.0)': dependencies: - '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0) - '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@5.3.2)(algoliasearch@4.24.0) + '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) + '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0) '@docsearch/css': 3.6.1 algoliasearch: 4.24.0 transitivePeerDependencies: @@ -7493,11 +7461,11 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@nolebase/ui@2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': + '@nolebase/ui@2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': dependencies: '@iconify-json/octicon': 1.2.0 less: 4.2.0 - vitepress: 1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + vitepress: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) vue: 3.5.3(typescript@5.6.2) transitivePeerDependencies: - '@algolia/client-search' @@ -7528,10 +7496,10 @@ snapshots: - typescript - universal-cookie - '@nolebase/vitepress-plugin-enhanced-mark@2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': + '@nolebase/vitepress-plugin-enhanced-mark@2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': dependencies: less: 4.2.0 - vitepress: 1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + vitepress: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) transitivePeerDependencies: - '@algolia/client-search' - '@types/node' @@ -7561,13 +7529,13 @@ snapshots: - typescript - universal-cookie - '@nolebase/vitepress-plugin-enhanced-readabilities@2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': + '@nolebase/vitepress-plugin-enhanced-readabilities@2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': dependencies: '@iconify-json/carbon': 1.2.1 '@iconify-json/icon-park-outline': 1.2.0 - '@nolebase/ui': 2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + '@nolebase/ui': 2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) less: 4.2.0 - vitepress: 1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + vitepress: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) transitivePeerDependencies: - '@algolia/client-search' - '@types/node' @@ -7597,10 +7565,10 @@ snapshots: - typescript - universal-cookie - '@nolebase/vitepress-plugin-git-changelog@2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': + '@nolebase/vitepress-plugin-git-changelog@2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': dependencies: '@iconify-json/octicon': 1.2.0 - '@nolebase/ui': 2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + '@nolebase/ui': 2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) colorette: 2.0.20 date-fns: 3.6.0 defu: 6.1.4 @@ -7610,7 +7578,7 @@ snapshots: gray-matter: 4.0.3 less: 4.2.0 uncrypto: 0.1.3 - vitepress: 1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + vitepress: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) transitivePeerDependencies: - '@algolia/client-search' - '@types/node' @@ -7640,10 +7608,10 @@ snapshots: - typescript - universal-cookie - '@nolebase/vitepress-plugin-highlight-targeted-heading@2.5.0(@algolia/client-search@5.3.2)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': + '@nolebase/vitepress-plugin-highlight-targeted-heading@2.5.0(@algolia/client-search@4.24.0)(@types/node@22.5.4)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2)': dependencies: less: 4.2.0 - vitepress: 1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) + vitepress: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2) transitivePeerDependencies: - '@algolia/client-search' - '@types/node' @@ -12730,10 +12698,10 @@ snapshots: transitivePeerDependencies: - supports-color - vitepress@1.3.4(@algolia/client-search@5.3.2)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2): + vitepress@1.3.4(@algolia/client-search@4.24.0)(@types/node@22.5.4)(less@4.2.0)(postcss@8.4.45)(terser@5.32.0)(typescript@5.6.2): dependencies: '@docsearch/css': 3.6.1 - '@docsearch/js': 3.6.1(@algolia/client-search@5.3.2) + '@docsearch/js': 3.6.1(@algolia/client-search@4.24.0) '@shikijs/core': 1.16.3 '@shikijs/transformers': 1.16.3 '@types/markdown-it': 14.1.2 From b5b684fa6cb44c6217a14522181e9828d4ff1906 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 19 Sep 2024 01:17:06 +0800 Subject: [PATCH 015/156] feat: support setup-component --- packages/jsx-macros/package.json | 1 + .../src/core/define-expose/index.ts | 2 + .../src/core/define-expose/react.ts | 73 ++++++++ .../jsx-macros/src/core/define-expose/vue.ts | 18 ++ packages/jsx-macros/src/core/define-model.ts | 18 ++ packages/jsx-macros/src/core/define-slots.ts | 21 +++ packages/jsx-macros/src/core/index.ts | 167 ++++++++++-------- .../jsx-macros/src/core/setup-fc/index.ts | 33 ++++ .../src/core/setup-fc/restructure.ts | 128 ++++++++++++++ packages/jsx-macros/src/index.ts | 5 +- .../tests/__snapshots__/fixtures.test.ts.snap | 43 ++++- .../__snapshots__/restructure.spec.ts.snap | 29 +++ packages/jsx-macros/tests/fixtures.test.ts | 15 ++ packages/jsx-macros/tests/restructure.spec.ts | 63 +++++++ packages/macros/src/index.ts | 2 +- packages/volar/src/jsx-macros.ts | 71 ++++---- packages/volar/src/jsx-ref.ts | 2 +- .../vue3/src/examples/jsx-macros/comp.tsx | 2 +- .../vue3/src/examples/jsx-macros/index.tsx | 38 ++-- .../src/examples/setup-component/index.tsx | 6 +- .../examples/setup-component/type-decl.tsx | 14 +- playground/vue3/vue-macros.config.ts | 2 +- pnpm-lock.yaml | 3 + 23 files changed, 618 insertions(+), 138 deletions(-) create mode 100644 packages/jsx-macros/src/core/define-expose/index.ts create mode 100644 packages/jsx-macros/src/core/define-expose/react.ts create mode 100644 packages/jsx-macros/src/core/define-expose/vue.ts create mode 100644 packages/jsx-macros/src/core/define-model.ts create mode 100644 packages/jsx-macros/src/core/define-slots.ts create mode 100644 packages/jsx-macros/src/core/setup-fc/index.ts create mode 100644 packages/jsx-macros/src/core/setup-fc/restructure.ts create mode 100644 packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap create mode 100644 packages/jsx-macros/tests/restructure.spec.ts diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 467df8b42..8be16d151 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -138,6 +138,7 @@ }, "dependencies": { "@vue-macros/common": "workspace:*", + "@vue/compiler-core": "catalog:", "unplugin": "catalog:" }, "devDependencies": { diff --git a/packages/jsx-macros/src/core/define-expose/index.ts b/packages/jsx-macros/src/core/define-expose/index.ts new file mode 100644 index 000000000..c4cd9399b --- /dev/null +++ b/packages/jsx-macros/src/core/define-expose/index.ts @@ -0,0 +1,2 @@ +export { transformVueDefineExpose } from './vue' +export { transformReactDefineExpose } from './react' diff --git a/packages/jsx-macros/src/core/define-expose/react.ts b/packages/jsx-macros/src/core/define-expose/react.ts new file mode 100644 index 000000000..6fe23a60a --- /dev/null +++ b/packages/jsx-macros/src/core/define-expose/react.ts @@ -0,0 +1,73 @@ +import { + HELPER_PREFIX, + importHelperFn, + type MagicStringAST, +} from '@vue-macros/common' +import { walkIdentifiers } from 'vue/compiler-sfc' +import { getParamsStart, type FunctionalNode } from '..' +import type { CallExpression, Node } from '@babel/types' + +export function transformReactDefineExpose( + node: CallExpression, + root: FunctionalNode, + s: MagicStringAST, + lib: string, +): void { + if (root.type === 'FunctionDeclaration' && root.id) { + s.prependLeft(root.start!, `const ${s.sliceNode(root.id)} = `) + } + s.appendLeft( + root.start!, + `${importHelperFn(s, 0, 'forwardRef', lib === 'preact' ? 'preact/compat' : lib)}(`, + ) + + const refName = root.params[1] + ? s.sliceNode(root.params[1]) + : `${HELPER_PREFIX}ref` + if (!root.params[0]) { + s.appendRight(getParamsStart(root, s.original), `, ${refName}`) + } else if (!root.params[1]) { + s.appendLeft(root.params[0].end!, `, ${refName}`) + } + + s.overwrite( + node.start!, + node.arguments[0].start!, + `${importHelperFn(s, 0, 'useImperativeHandle', lib === 'preact' ? 'preact/hooks' : lib)}(${refName}, () =>(`, + ) + const result = new Set() + walkIdentifiers( + node.arguments[0], + (id, _, parentStack, ___, isLocal) => { + if (!isLocal) { + let res: Node | null = id + for (let i = parentStack.length - 1; i >= 0; i--) { + if ( + ['MemberExpression', 'OptionalMemberExpression'].includes( + parentStack[i].type, + ) + ) { + res = parentStack[i] + } else { + if ( + ['CallExpression', 'OptionalCallExpression'].includes( + parentStack[i].type, + ) + ) { + res = null + } + break + } + } + if (res) result.add(s.sliceNode(res)) + } + }, + false, + ) + s.appendRight( + node.arguments[0].end!, + `), ${`[${result.size ? [...result] : ''}]`}`, + ) + + s.appendRight(root.end!, `)`) +} diff --git a/packages/jsx-macros/src/core/define-expose/vue.ts b/packages/jsx-macros/src/core/define-expose/vue.ts new file mode 100644 index 000000000..81105c230 --- /dev/null +++ b/packages/jsx-macros/src/core/define-expose/vue.ts @@ -0,0 +1,18 @@ +import { importHelperFn, type MagicStringAST } from '@vue-macros/common' +import { useExposeHelperId } from '../helper' +import type { CallExpression } from '@babel/types' + +export function transformVueDefineExpose( + node: CallExpression, + s: MagicStringAST, + lib: string, +): void { + s.overwriteNode( + node.callee, + importHelperFn(s, 0, 'useExpose', useExposeHelperId), + ) + s.appendRight( + node.arguments[0]?.start || node.end! - 1, + `${importHelperFn(s, 0, 'getCurrentInstance', lib)}(), `, + ) +} diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts new file mode 100644 index 000000000..56e1ce339 --- /dev/null +++ b/packages/jsx-macros/src/core/define-model.ts @@ -0,0 +1,18 @@ +import { importHelperFn, type MagicStringAST } from '@vue-macros/common' +import { useModelHelperId } from './helper' +import type { CallExpression } from '@babel/types' + +export function transformDefineModel( + node: CallExpression, + propsName: string, + s: MagicStringAST, +): void { + s.overwriteNode( + node.callee, + importHelperFn(s, 0, 'useModel', useModelHelperId), + ) + s.appendRight( + node.arguments[0]?.start || node.end! - 1, + `${propsName}, ${node.arguments.length && node.arguments[0].type !== 'StringLiteral' ? `'modelValue',` : ''}`, + ) +} diff --git a/packages/jsx-macros/src/core/define-slots.ts b/packages/jsx-macros/src/core/define-slots.ts new file mode 100644 index 000000000..aa5a2d149 --- /dev/null +++ b/packages/jsx-macros/src/core/define-slots.ts @@ -0,0 +1,21 @@ +import { importHelperFn, type MagicStringAST } from '@vue-macros/common' +import type { CallExpression } from '@babel/types' + +export function transformDefineSlots( + node: CallExpression, + propsName: string, + s: MagicStringAST, + lib: string, +): void { + s.overwrite( + node.start!, + (node.arguments[0]?.start && node.arguments[0].start - 1) || + node.typeArguments?.end || + node.callee.end!, + `Object.assign`, + ) + const slots = lib.includes('vue') + ? `${importHelperFn(s, 0, 'getCurrentInstance', lib)}()?.slots` + : `${propsName}.vSlots` + s.appendLeft(node.end! - 1, `${node.arguments[0] ? ',' : '{}, '}${slots}`) +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index acd2cd236..922a9dd62 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -3,13 +3,18 @@ import { generateTransform, getLang, HELPER_PREFIX, - importHelperFn, MagicStringAST, walkAST, type CodeTransform, } from '@vue-macros/common' import type { OptionsResolved } from '..' -import { useExposeHelperId, useModelHelperId } from './helper' +import { + transformReactDefineExpose, + transformVueDefineExpose, +} from './define-expose' +import { transformDefineModel } from './define-model' +import { transformDefineSlots } from './define-slots' +import { transformSetupFC } from './setup-fc' import type { ArrowFunctionExpression, CallExpression, @@ -18,13 +23,34 @@ import type { Node, } from '@babel/types' +export { restructure } from './setup-fc/restructure' + +export type FunctionalNode = + | FunctionDeclaration + | FunctionExpression + | ArrowFunctionExpression + +function isMacro(node?: Node | null): node is CallExpression { + return !!( + node && + node.type === 'CallExpression' && + node.callee.type === 'Identifier' && + ['defineSlots', 'defineModel', 'defineExpose'].includes(node.callee.name) + ) +} + function getRootMap(s: MagicStringAST, id: string) { const parents: (Node | undefined | null)[] = [] const rootMap: Map< - FunctionDeclaration | FunctionExpression | ArrowFunctionExpression, - Map + FunctionalNode, + { + isSetupFC?: boolean + defineModel?: CallExpression[] + defineSlots?: CallExpression + defineExpose?: CallExpression + } > = new Map() - walkAST(babelParse(s.toString(), getLang(id)), { + walkAST(babelParse(s.original, getLang(id)), { enter(node, parent) { parents.unshift(parent) const expression = @@ -40,21 +66,29 @@ function getRootMap(s: MagicStringAST, id: string) { parents[1].type === 'FunctionExpression') ? parents[1] : undefined - if (!root || !isMacro(expression)) return + if (!root) return - if (!rootMap.has(root)) - rootMap.set( - root, - new Map([ - ['defineModel', []], - ['defineSlots', []], - ['defineExpose', []], - ]), - ) - const map = rootMap.get(root)! + let isSetupFC = false + if ( + root.type !== 'FunctionDeclaration' && + parents[2]?.type === 'VariableDeclarator' && + parents[2].id.type === 'Identifier' && + parents[2].id.typeAnnotation?.type === 'TSTypeAnnotation' && + s.sliceNode(parents[2].id.typeAnnotation.typeAnnotation) === 'SetupFC' + ) { + isSetupFC = true + if (!rootMap.has(root)) rootMap.set(root, {}) + rootMap.get(root)!.isSetupFC = isSetupFC + } + + if (!isMacro(expression)) return + if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = s.sliceNode(expression.callee) if (macroName) { - map.get(macroName)?.push(expression) + if (macroName === 'defineModel') + (rootMap.get(root)!.defineModel ??= []).push(expression) + else if (macroName === 'defineSlots' || macroName === 'defineExpose') + rootMap.get(root)![macroName] = expression } }, leave() { @@ -64,6 +98,15 @@ function getRootMap(s: MagicStringAST, id: string) { return rootMap } +export function getParamsStart(node: FunctionalNode, code: string): number { + return node.params[0] + ? node.params[0].start! + : node.start! + + (code.slice(node.start!, node.body.start!).match(/\(\s*\)/)?.index || + 0) + + 1 +} + export function transformJsxMacros( code: string, id: string, @@ -74,81 +117,49 @@ export function transformJsxMacros( for (const [root, map] of rootMap) { let propsName = `${HELPER_PREFIX}props` - const paramsStart = root.params[0] - ? root.params[0].start! - : root.start! + - (s.slice(root.start!, root.body.start!).match(/\(\s*\)/)?.index || 0) + - 1 if (root.params[0]) { if (root.params[0].type === 'Identifier') { propsName = root.params[0].name } else if (root.params[0].type === 'ObjectPattern') { - const param = root.params[0].properties.find( - (i) => i.type === 'RestElement', - ) - if (param && param?.argument.type === 'Identifier') { - propsName = param.argument.name - } else if ( - root.params[0].type === 'ObjectPattern' && - root.params[0].properties.at(-1) + const lastProp = root.params[0].properties.at(-1) + if ( + lastProp?.type === 'RestElement' && + lastProp.argument.type === 'Identifier' ) { - s.overwrite( - root.params[0].properties.at(-1)!.end!, - root.params[0].end! - 1, - `, ...${HELPER_PREFIX}props`, + propsName = lastProp.argument.name + } else if (lastProp) { + s.appendRight( + root.params[0].extra?.trailingComma + ? (root.params[0].extra?.trailingComma as number) + 1 + : lastProp.end!, + `${root.params[0].extra?.trailingComma ? '' : ','} ...${HELPER_PREFIX}props`, ) } } } else { - s.appendRight(paramsStart, `${HELPER_PREFIX}props`) + s.appendRight(getParamsStart(root, s.original), `${HELPER_PREFIX}props`) } - for (const [macroName, nodes] of map) { - for (const node of nodes) { - if (macroName === 'defineSlots') { - s.overwrite( - node.start!, - (node.arguments[0]?.start && node.arguments[0].start - 1) || - node.typeArguments?.end || - node.callee.end!, - `Object.assign`, - ) - const slots = `${importHelperFn(s, 0, 'getCurrentInstance', options.lib)}()?.slots` - s.appendLeft( - node.end! - 1, - `${node.arguments[0] ? ',' : '{}, '}${slots}`, - ) - } else if (macroName === 'defineModel') { - s.overwriteNode( - node.callee, - importHelperFn(s, 0, 'useModel', useModelHelperId), - ) - s.appendRight( - node.arguments[0]?.start || node.end! - 1, - `${propsName}, ${node.arguments.length && node.arguments[0].type !== 'StringLiteral' ? `'modelValue',` : ''}`, - ) - } else if (macroName === 'defineExpose') { - s.overwriteNode( - node.callee, - importHelperFn(s, 0, 'useExpose', useExposeHelperId), - ) - s.appendRight( - node.arguments[0]?.start || node.end! - 1, - `${importHelperFn(s, 0, 'getCurrentInstance', options.lib)}(), `, - ) - } + if (map.defineModel?.length && !map.isSetupFC) { + map.defineModel.forEach((node) => { + transformDefineModel(node, propsName, s) + }) + } + if (map.defineSlots) { + transformDefineSlots(map.defineSlots, propsName, s, options.lib) + } + if (map.defineExpose && !map.isSetupFC) { + if (options.lib.includes('vue')) { + transformVueDefineExpose(map.defineExpose, s, options.lib) + } else if (options.lib.includes('react')) { + transformReactDefineExpose(map.defineExpose, root, s, options.lib) } } + + if (map.isSetupFC) { + transformSetupFC(root, s) + } } return generateTransform(s, id) } - -function isMacro(node?: Node | null): node is CallExpression { - return !!( - node && - node.type === 'CallExpression' && - node.callee.type === 'Identifier' && - ['defineSlots', 'defineModel', 'defineExpose'].includes(node.callee.name) - ) -} diff --git a/packages/jsx-macros/src/core/setup-fc/index.ts b/packages/jsx-macros/src/core/setup-fc/index.ts new file mode 100644 index 000000000..512085c27 --- /dev/null +++ b/packages/jsx-macros/src/core/setup-fc/index.ts @@ -0,0 +1,33 @@ +import { + HELPER_PREFIX, + importHelperFn, + type MagicStringAST, +} from '@vue-macros/common' +import type { FunctionalNode } from '..' +import { restructure } from './restructure' + +export function transformSetupFC( + node: FunctionalNode, + s: MagicStringAST, +): void { + if (node.params[0]) { + restructure(s, node) + const isBlockStatement = node.body.type === 'BlockStatement' + const start = node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start! + if (!isBlockStatement) { + s.appendLeft(start, '{') + } + const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') + s.appendRight( + start + (isBlockStatement ? 1 : 0), + `\nconst ${HELPER_PREFIX}props0 = ${useAttrs}();${!isBlockStatement ? 'return ' : ''}`, + ) + if (!isBlockStatement) { + s.appendRight(node.end!, '}') + } + + s.removeNode(node.params[0]) + } +} diff --git a/packages/jsx-macros/src/core/setup-fc/restructure.ts b/packages/jsx-macros/src/core/setup-fc/restructure.ts new file mode 100644 index 000000000..fc6033166 --- /dev/null +++ b/packages/jsx-macros/src/core/setup-fc/restructure.ts @@ -0,0 +1,128 @@ +import { + HELPER_PREFIX, + importHelperFn, + type MagicString, +} from '@vue-macros/common' +import { walkIdentifiers } from '@vue/compiler-core' +import type { FunctionalNode } from '..' +import type { Node } from '@babel/types' + +type PropMap = Map< + string, + { path: string; value: string; defaultValue?: string; isRest?: boolean } +> + +function collectProps( + node: Node, + path: string = '', + s: MagicString, + propMap: PropMap, +) { + const properties = + node.type === 'ObjectPattern' + ? node.properties + : node.type === 'ArrayPattern' + ? node.elements + : [] + if (!properties.length) return + + const propNames: string[] = [] + properties.forEach((prop, index) => { + if (prop?.type === 'Identifier') { + propMap.set(prop.name, { path, value: `[${index}]` }) + propNames.push(`'${prop.name}'`) + } else if ( + prop?.type === 'AssignmentPattern' && + prop.left.type === 'Identifier' + ) { + propMap.set(prop.left.name, { + path, + value: `.${prop.left.name}`, + defaultValue: s.slice(prop.right.start!, prop.right.end!), + }) + propNames.push(`'${prop.left.name}'`) + } else if ( + prop?.type === 'ObjectProperty' && + prop.key.type === 'Identifier' + ) { + if (prop.value.type === 'AssignmentPattern') { + propMap.set(prop.key.name, { + path, + value: `.${prop.key.name}`, + defaultValue: s.slice(prop.value.right.start!, prop.value.right.end!), + }) + } else if ( + !collectProps(prop.value, `${path}.${prop.key.name}`, s, propMap) + ) { + propMap.set(prop.key.name, { path, value: `.${prop.key.name}` }) + } + propNames.push(`'${prop.key.name}'`) + } else if ( + prop?.type === 'RestElement' && + prop?.argument.type === 'Identifier' + ) { + propMap.set(prop.argument.name, { + path, + value: propNames.join(', '), + isRest: true, + }) + } else if (prop) { + collectProps(prop, `${path}[${index}]`, s, propMap) + } + }) + return true +} + +export function restructure(s: MagicString, node: FunctionalNode): void { + let index = 0 + const propMap: PropMap = new Map() + for (const param of node.params) { + const path = `${HELPER_PREFIX}props${index++}` + if (collectProps(param, path, s, propMap)) { + s.overwrite(param.start!, param.end!, path) + } + } + + if (propMap.size) { + for (const [key, { path, value, defaultValue, isRest }] of propMap) { + if (!(defaultValue || isRest)) continue + + const result = defaultValue + ? `Object.defineProperty(${path}, '${key}', { enumerable: true, get: () => ${path}['${key}'] ?? ${defaultValue} })` + : `const ${key} = ${importHelperFn(s, 0, 'createPropsRestProxy', 'vue')}(${path}, [${value}])` + const isBlockStatement = node.body.type === 'BlockStatement' + const start = node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start! + if (!isBlockStatement) { + s.appendLeft(start, '{') + } + s.appendRight( + start + (isBlockStatement ? 1 : 0), + `${result};${!isBlockStatement ? 'return ' : ''}`, + ) + if (!isBlockStatement) { + s.appendRight(node.end! + 1, '}') + } + } + + walkIdentifiers( + node.body, + (id, parent, __, ___, isLocal) => { + const prop = propMap.get(id.name) + if (!isLocal && prop && !prop.isRest) { + s.overwrite( + id.start!, + id.end!, + `${ + parent?.type === 'ObjectProperty' && parent.shorthand + ? `${id.name}: ` + : '' + }${prop.path}${prop.value}`, + ) + } + }, + false, + ) + } +} diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index d137dd3cc..ba5ac28ae 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -26,7 +26,10 @@ import { export type Options = BaseOptions & { lib?: string } -export type OptionsResolved = MarkRequired +export type OptionsResolved = MarkRequired< + Options, + 'include' | 'version' | 'lib' +> function resolveOptions( options: Options, diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index d9731f956..5216f7727 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -3,7 +3,7 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function Comp({foo, ...__MACROS_props}) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) @@ -44,16 +44,45 @@ export default function (__MACROS_props) { " `; -exports[`fixtures > ./fixtures/index.tsx 1`] = ` +exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = (__MACROS_props) => { - __MACROS_useModel(__MACROS_props, 'foo') +import { forwardRef as __MACROS_forwardRef } from "react"; +import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export default function Comp(...__MACROS_rest){ return (__MACROS_forwardRef(function Comp({foo, ...__MACROS_props}, __MACROS_ref) { + __MACROS_useImperativeHandle(__MACROS_ref, () =>({ + foo: 1, + }), []) return
+}))(...__MACROS_rest)} +" +`; + +exports[`react fixtures > ./fixtures/define-model.tsx 1`] = ` +" +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props}) => { + const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) + return
{foo.value}
} -export const Comp1 = (__MACROS_props) => { - __MACROS_useModel(__MACROS_props, 'foo') - return
+export default function (__MACROS_props) { + const foo = __MACROS_useModel(__MACROS_props, 'foo') + return
{foo.value}
+} +" +`; + +exports[`react fixtures > ./fixtures/define-slots.tsx 1`] = ` +"export const Comp = (__MACROS_props) => { + const slots = Object.assign<{ + default: () => any + }>({}, __MACROS_props.vSlots) + return
{slots.default()}
+} + +export default function (__MACROS_props) { + const slots = Object.assign({ + default: () =>
default
, + },__MACROS_props.vSlots) + return
{slots.default()}
} " `; diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap new file mode 100644 index 000000000..ac7eb99ea --- /dev/null +++ b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap @@ -0,0 +1,29 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`transform > reconstruct 1`] = ` +"const App = (__MACROS_props0, __MACROS_props1) => { + function onClick(__MACROS_props0){ + return { foo: __MACROS_props0.foo, baz: __MACROS_props1.baz.baz } + }; + return [ __MACROS_props0[0][0][1], __MACROS_props0[1].id.foo[0], __MACROS_props1.baz ] + }" +`; + +exports[`transform > reconstruct arrowFunctionExpression 1`] = ` +"const App = (__MACROS_props0) => ( + <>{[__MACROS_props0[0].root.foo]} + )" +`; + +exports[`transform > reconstruct default-prop 1`] = ` +"function App(__MACROS_props0, __MACROS_props1){Object.defineProperty(__MACROS_props0, 'foo', { enumerable: true, get: () => __MACROS_props0['foo'] ?? [] });Object.defineProperty(__MACROS_props1, 'bar', { enumerable: true, get: () => __MACROS_props1['bar'] ?? 1 }); + return <>{[__MACROS_props0.foo, __MACROS_props1.bar, __MACROS_props1[1]]} + }" +`; + +exports[`transform > reconstruct rest-prop 1`] = ` +" +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props0){Object.defineProperty(__MACROS_props0, 'bar', { enumerable: true, get: () => __MACROS_props0['bar'] ?? 1 });const rest = __MACROS_createPropsRestProxy(__MACROS_props0, ['foo', 'bar']); + return <>{[__MACROS_props0.foo, __MACROS_props0.bar, rest]} + }" +`; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index b6ae4de7e..63244e34c 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -16,3 +16,18 @@ describe('fixtures', async () => { })?.code, ) }) + +describe('react fixtures', async () => { + await testFixtures( + import.meta.glob('./fixtures/**/*.tsx', { + eager: true, + as: 'raw', + }), + (args, id, code) => + transformJsxMacros(code, id, { + lib: 'react', + include: ['*.tsx'], + version: 18, + })?.code, + ) +}) diff --git a/packages/jsx-macros/tests/restructure.spec.ts b/packages/jsx-macros/tests/restructure.spec.ts new file mode 100644 index 000000000..9aa102465 --- /dev/null +++ b/packages/jsx-macros/tests/restructure.spec.ts @@ -0,0 +1,63 @@ +import { babelParse, walkAST } from '@vue-macros/common' +import { describe, expect, test } from 'vitest' +import { MagicString } from 'vue/compiler-sfc' +import { restructure } from '../src/core' +import type { Node } from '@babel/types' + +export function transformRestructure(code: string) { + const s = new MagicString(code) + const ast = babelParse(code, 'tsx') + walkAST(ast, { + enter(node) { + if ( + node.type === 'FunctionExpression' || + node.type === 'ArrowFunctionExpression' || + node.type === 'FunctionDeclaration' + ) { + restructure(s, node) + } + }, + }) + return s.toString() +} + +describe('transform', () => { + test('reconstruct', () => { + const code = transformRestructure( + `const App = ([[[,foo]], {id: {foo: [bar]}}], { baz }) => { + function onClick({ foo }){ + return { foo, baz: baz.baz } + }; + return [ foo, bar, baz ] + }`, + )! + expect(code).toMatchSnapshot() + }) + + test('reconstruct arrowFunctionExpression', () => { + const code = transformRestructure( + `const App = ([{root: {foo}}]) => ( + <>{[foo]} + )`, + )! + expect(code).toMatchSnapshot() + }) + + test('reconstruct default-prop', () => { + const code = transformRestructure( + `function App({foo = []}, [bar = 1, baz]){ + return <>{[foo, bar, baz]} + }`, + )! + expect(code).toMatchSnapshot() + }) + + test('reconstruct rest-prop', () => { + const code = transformRestructure( + `function App({foo, bar = 1, ...rest}){ + return <>{[foo, bar, rest]} + }`, + )! + expect(code).toMatchSnapshot() + }) +}) diff --git a/packages/macros/src/index.ts b/packages/macros/src/index.ts index e7b91e24c..d4277c766 100644 --- a/packages/macros/src/index.ts +++ b/packages/macros/src/index.ts @@ -68,6 +68,7 @@ const plugin: UnpluginCombineInstance = const plugins: OptionsPlugin[] = [ resolvePlugin(VueSetupSFC, framework, options.setupSFC), + resolvePlugin(VueJsxMacros, framework, options.jsxMacros), setupComponentPlugins?.[0], resolvePlugin(VueSetupBlock, framework, options.setupBlock), resolvePlugin(VueScriptLang, framework, options.scriptLang), @@ -131,7 +132,6 @@ const plugin: UnpluginCombineInstance = options.plugins.vue, resolvePlugin(VueJsxDirective, framework, options.jsxDirective), - resolvePlugin(VueJsxMacros, framework, options.jsxMacros), options.plugins.vueJsx, resolvePlugin(VueDefineRender, framework, options.defineRender), setupComponentPlugins?.[1], diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 5a724b23d..8518a1200 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -9,7 +9,11 @@ type RootMap = Map< | import('typescript').ArrowFunction | import('typescript').FunctionExpression | import('typescript').FunctionDeclaration, - Map + { + defineModel?: string[] + defineSlots?: string + defineExpose?: string + } > function getMacro( @@ -69,21 +73,27 @@ function getRootMap(options: TransformOptions): RootMap { ts.isFunctionDeclaration(parents[1])) ? parents[1] : undefined + if ( + root && + !ts.isFunctionDeclaration(root) && + ts.isVariableDeclaration(parents[2]) && + parents[2].type && + getText(parents[2].type, options) === 'SetupFC' + ) { + replaceSourceRange( + codes, + source, + parents[2].name.end, + parents[2].type.end, + ) + } + const macro = root && getMacro(node, ts) if (macro) { if (!rootMap.has(root)) { - rootMap.set( - root, - new Map([ - ['defineSlots', []], - ['defineModel', []], - ['defineExpose', []], - ]), - ) + rootMap.set(root, {}) } - const propMap = rootMap.get(root)! const name = getText(macro.expression, options) - if (name === 'defineModel') { const modelName = macro.arguments[0] && ts.isStringLiteralLike(macro.arguments[0]) @@ -107,9 +117,9 @@ function getRootMap(options: TransformOptions): RootMap { const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) const typeString = `import("vue").UnwrapRef` const requiredString = required ? ':' : '?:' - propMap - .get(name) - ?.push( + rootMap + .get(root)! + .defineModel?.push( `${modelName}${requiredString} ${typeString}`, `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, ) @@ -127,7 +137,7 @@ function getRootMap(options: TransformOptions): RootMap { source, getStart(macro, options), getStart(macro, options), - `// @ts-ignore\n${HELPER_PREFIX}slots;\nlet ${HELPER_PREFIX}slots =`, + `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, [ HELPER_PREFIX, source, @@ -135,7 +145,8 @@ function getRootMap(options: TransformOptions): RootMap { allCodeFeatures, ], ) - propMap.get(name)?.push(`{ vSlots?: typeof ${HELPER_PREFIX}slots }`) + rootMap.get(root)!.defineSlots = + `{ vSlots?: typeof ${HELPER_PREFIX}slots }` } else if (name === 'defineExpose') { replaceSourceRange( codes, @@ -145,12 +156,10 @@ function getRootMap(options: TransformOptions): RootMap { `const ${HELPER_PREFIX}expose = ${getText(macro.arguments[0], options)};`, [HELPER_PREFIX, source, getStart(macro, options), allCodeFeatures], ) - propMap - .get(name) - ?.push(`(exposed: typeof ${HELPER_PREFIX}expose) => {}`) + rootMap.get(root)!.defineExpose = + `(exposed: typeof ${HELPER_PREFIX}expose) => {}` } } - ts.forEachChild(node, (child) => { parents.unshift(node) walk(child, parents) @@ -171,7 +180,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) ? 'async' : '' - const result = `({}) as Awaited['render'] & { __ctx: Awaited['render']> & { __ctx: Awaited }` @@ -232,15 +241,11 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { getStart(node, options), getStart(node.expression, options), `return {\nprops: {} as `, - props.get('defineModel')?.length - ? `{ ${props.get('defineModel')?.join(', ')} }` + props.defineModel?.length + ? `{ ${props.defineModel?.join(', ')} }` : '{}', - props.get('defineSlots')?.length - ? ` & ${props.get('defineSlots')?.join()}` - : '', - props.get('defineExpose')?.length - ? `,\nexpose: ${props.get('defineExpose')?.join()}` - : '', + props.defineSlots ? ` & ${props.defineSlots}` : '', + props.defineExpose ? `,\nexpose: ${props.defineExpose}` : '', `,\nrender: `, ) replaceSourceRange( @@ -258,10 +263,14 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { rootMap.size && !codes.toString().includes(`declare function ${HELPER_PREFIX}defineSlots`) ) { - codes.push(` + codes.push( + ` declare function ${HELPER_PREFIX}defineSlots>(slots?: T): T declare const ${HELPER_PREFIX}defineExpose: typeof import('vue').defineExpose; -declare const ${HELPER_PREFIX}defineModel: typeof import('vue').defineModel;\n`) +declare const ${HELPER_PREFIX}defineModel: typeof import('vue').defineModel; +declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; +`, + ) } } diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index b2660a367..2e80c82cc 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -51,7 +51,7 @@ function getRefNodes( const result: RefNode[] = [] function walk(node: import('typescript').Node) { if (ts.isVariableStatement(node)) { - return ts.forEachChild(node.declarationList, (decl) => { + ts.forEachChild(node.declarationList, (decl) => { if ( ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name) && diff --git a/playground/vue3/src/examples/jsx-macros/comp.tsx b/playground/vue3/src/examples/jsx-macros/comp.tsx index ff6f06f46..e68d5f223 100644 --- a/playground/vue3/src/examples/jsx-macros/comp.tsx +++ b/playground/vue3/src/examples/jsx-macros/comp.tsx @@ -1,6 +1,6 @@ import { watch } from 'vue' -export function Comp({ foo }: { foo: T }) { +export function Comp({ foo }: { foo: T }) { const slots = defineSlots({ default: (props: { bar: string }) =>
{props.bar}
, }) diff --git a/playground/vue3/src/examples/jsx-macros/index.tsx b/playground/vue3/src/examples/jsx-macros/index.tsx index 85c7f6e44..c92aaf16c 100644 --- a/playground/vue3/src/examples/jsx-macros/index.tsx +++ b/playground/vue3/src/examples/jsx-macros/index.tsx @@ -1,16 +1,28 @@ -import { defineComponent, ref } from 'vue' +import { expectTypeOf } from 'expect-type' +import { useRef } from 'unplugin-vue-macros/runtime' +import { ref } from 'vue' import { Comp } from './comp' -export default defineComponent(() => { - const foo = ref('1') +export default { + setup: () => { + const foo = ref('1') + const compRef = useRef() + expectTypeOf(compRef.value?.foo).toEqualTypeOf<1 | undefined>() - return () => ( -
- - - - - {foo.value} -
- ) -}) + return () => ( +
+ (compRef.value = e)} + v-model_trim={foo.value} + foo={1} + v-slot={{ bar }} + > + {bar} + + + + {foo.value} +
+ ) + }, +} diff --git a/playground/vue3/src/examples/setup-component/index.tsx b/playground/vue3/src/examples/setup-component/index.tsx index fb68acb11..d7ce1f6c0 100644 --- a/playground/vue3/src/examples/setup-component/index.tsx +++ b/playground/vue3/src/examples/setup-component/index.tsx @@ -1,11 +1,15 @@ +import { useRef } from 'unplugin-vue-macros/runtime' import Context from './context' import { SetupComponentTypeDecl } from './type-decl' export const SetupComponentFoo = defineSetupComponent(() => { const Ctx = Context() + const compRef = useRef() return () => ( <> - + +
double: {Number(compRef.value?.double) * foo}
+
) diff --git a/playground/vue3/src/examples/setup-component/type-decl.tsx b/playground/vue3/src/examples/setup-component/type-decl.tsx index 62f0b39f4..2d74315a7 100644 --- a/playground/vue3/src/examples/setup-component/type-decl.tsx +++ b/playground/vue3/src/examples/setup-component/type-decl.tsx @@ -3,16 +3,24 @@ import { foo } from './foo' console.log(foo) +const Comp: SetupFC = ({ foo }: { foo: number }) => {foo} + export const SetupComponentTypeDecl: SetupFC = () => { - const count = ref(0) + const count = ref(1) const double = computed(() => count.value * 2) + defineExpose({ double }) + const slots = defineSlots({ + default: Comp, + }) + const foo = ref(1) return () => (
Type Declaration + + count: + -
count: {count.value}
-
double: {double.value}
) } diff --git a/playground/vue3/vue-macros.config.ts b/playground/vue3/vue-macros.config.ts index 4daea5861..12f6383e5 100644 --- a/playground/vue3/vue-macros.config.ts +++ b/playground/vue3/vue-macros.config.ts @@ -23,7 +23,7 @@ export default defineConfig({ reactivityTransform: true, scriptLang: true, scriptSFC: { - include: [/script-sfc.*\.tsx$/, /jsx-macros.*\.tsx$/], + include: [/vue3\/.*\.tsx$/], }, setupBlock: true, setupSFC: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef01e1314..578745a30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -621,6 +621,9 @@ importers: '@vue-macros/common': specifier: workspace:* version: link:../common + '@vue/compiler-core': + specifier: 'catalog:' + version: 3.5.3 unplugin: specifier: 'catalog:' version: 1.14.0(webpack-sources@3.2.3) From bf0f78a1ce7ce21f2ab53f2e56e63e94ad778420 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 19 Sep 2024 17:18:09 +0800 Subject: [PATCH 016/156] feat: support reactivity-transform --- packages/jsx-macros/src/core/index.ts | 11 ++- .../tests/__snapshots__/fixtures.test.ts.snap | 18 ++--- .../tests/fixtures/define-model.tsx | 4 +- packages/macros/src/index.ts | 2 +- packages/volar/src/jsx-macros.ts | 74 ++++++++++++------- 5 files changed, 67 insertions(+), 42 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 922a9dd62..a1dc11951 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -3,6 +3,7 @@ import { generateTransform, getLang, HELPER_PREFIX, + isCallOf, MagicStringAST, walkAST, type CodeTransform, @@ -31,6 +32,7 @@ export type FunctionalNode = | ArrowFunctionExpression function isMacro(node?: Node | null): node is CallExpression { + node = isCallOf(node, '$') ? node.arguments[0] : node return !!( node && node.type === 'CallExpression' && @@ -83,10 +85,15 @@ function getRootMap(s: MagicStringAST, id: string) { if (!isMacro(expression)) return if (!rootMap.has(root)) rootMap.set(root, {}) - const macroName = s.sliceNode(expression.callee) + const macro = + isCallOf(expression, '$') && + expression.arguments[0].type === 'CallExpression' + ? expression.arguments[0] + : expression + const macroName = s.sliceNode(macro.callee) if (macroName) { if (macroName === 'defineModel') - (rootMap.get(root)!.defineModel ??= []).push(expression) + (rootMap.get(root)!.defineModel ??= []).push(macro) else if (macroName === 'defineSlots' || macroName === 'defineExpose') rootMap.get(root)![macroName] = expression } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 5216f7727..6f67b0fde 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -3,7 +3,7 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function Comp({foo, ...__MACROS_props}) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) @@ -14,14 +14,14 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props}) => { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) return
{foo.value}
} export default function (__MACROS_props) { - const foo = __MACROS_useModel(__MACROS_props, 'foo') - return
{foo.value}
+ const foo = $(__MACROS_useModel(__MACROS_props, 'foo')) + return
{foo}
} " `; @@ -47,25 +47,25 @@ export default function (__MACROS_props) { exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { forwardRef as __MACROS_forwardRef } from "react"; -import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export default function Comp(...__MACROS_rest){ return (__MACROS_forwardRef(function Comp({foo, ...__MACROS_props}, __MACROS_ref) { +import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export default __MACROS_forwardRef(function (__MACROS_props, __MACROS_ref) { __MACROS_useImperativeHandle(__MACROS_ref, () =>({ foo: 1, }), []) return
-}))(...__MACROS_rest)} +}) " `; exports[`react fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props}) => { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) return
{foo.value}
} export default function (__MACROS_props) { - const foo = __MACROS_useModel(__MACROS_props, 'foo') - return
{foo.value}
+ const foo = $(__MACROS_useModel(__MACROS_props, 'foo')) + return
{foo}
} " `; diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 609713b80..13ff9885a 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -4,6 +4,6 @@ export const Comp = ({ bar }: { bar: string }) => { } export default function () { - const foo = defineModel('foo') - return
{foo.value}
+ const foo = $(defineModel('foo')) + return
{foo}
} diff --git a/packages/macros/src/index.ts b/packages/macros/src/index.ts index d4277c766..8ff1a5395 100644 --- a/packages/macros/src/index.ts +++ b/packages/macros/src/index.ts @@ -67,8 +67,8 @@ const plugin: UnpluginCombineInstance = ) const plugins: OptionsPlugin[] = [ - resolvePlugin(VueSetupSFC, framework, options.setupSFC), resolvePlugin(VueJsxMacros, framework, options.jsxMacros), + resolvePlugin(VueSetupSFC, framework, options.setupSFC), setupComponentPlugins?.[0], resolvePlugin(VueSetupBlock, framework, options.setupBlock), resolvePlugin(VueScriptLang, framework, options.scriptLang), diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 8518a1200..48930a92d 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -1,6 +1,5 @@ import { createFilter, HELPER_PREFIX } from '@vue-macros/common' import { toValidAssetId } from '@vue/compiler-dom' -import { allCodeFeatures } from '@vue/language-core' import { replaceSourceRange } from 'muggle-string' import { getStart, getText, type VueMacrosPlugin } from './common' import type { TransformOptions } from './jsx-directive/index' @@ -19,7 +18,13 @@ type RootMap = Map< function getMacro( node: import('typescript').Node | undefined, ts: typeof import('typescript'), -): import('typescript').CallExpression | undefined { +): + | { + expression: import('typescript').CallExpression + initializer: import('typescript').Node + isReactivityTransform?: boolean + } + | undefined { if (!node) return if (ts.isVariableStatement(node)) { @@ -35,13 +40,22 @@ function getMacro( ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression) ) { - const expression = + const isReactivityTransform = decl.initializer.expression.escapedText === '$' - ? decl.initializer.arguments[0] - : decl.initializer - if (isMacro(expression)) return expression + const expression = isReactivityTransform + ? decl.initializer.arguments[0] + : decl.initializer + if (isMacro(expression)) + return { + expression, + isReactivityTransform, + initializer: decl.initializer, + } } else if (ts.isExpressionStatement(decl) && isMacro(decl.expression)) { - return decl.expression + return { + expression: decl.expression, + initializer: decl, + } } } @@ -90,19 +104,22 @@ function getRootMap(options: TransformOptions): RootMap { const macro = root && getMacro(node, ts) if (macro) { + const { expression, isReactivityTransform, initializer } = macro if (!rootMap.has(root)) { rootMap.set(root, {}) } - const name = getText(macro.expression, options) + const name = getText(expression.expression, options) if (name === 'defineModel') { const modelName = - macro.arguments[0] && ts.isStringLiteralLike(macro.arguments[0]) - ? macro.arguments[0].text + expression.arguments[0] && + ts.isStringLiteralLike(expression.arguments[0]) + ? expression.arguments[0].text : 'modelValue' const modelOptions = - macro.arguments[0] && ts.isStringLiteralLike(macro.arguments[0]) - ? macro.arguments[1] - : macro.arguments[0] + expression.arguments[0] && + ts.isStringLiteralLike(expression.arguments[0]) + ? expression.arguments[1] + : expression.arguments[0] let required = false if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { for (const prop of modelOptions.properties) { @@ -126,24 +143,25 @@ function getRootMap(options: TransformOptions): RootMap { replaceSourceRange( codes, source, - getStart(macro, options), - getStart(macro, options), + getStart(expression, options), + getStart(expression, options), + HELPER_PREFIX, + ) + replaceSourceRange( + codes, + source, + getStart(isReactivityTransform ? initializer : expression, options), + getStart(isReactivityTransform ? initializer : expression, options), `// @ts-ignore\n${id};\nlet ${id} =`, - [HELPER_PREFIX, source, getStart(macro, options), allCodeFeatures], ) } else if (name === 'defineSlots') { replaceSourceRange( codes, source, - getStart(macro, options), - getStart(macro, options), + getStart(expression, options), + getStart(expression, options), `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, - [ - HELPER_PREFIX, - source, - getStart(macro.expression, options), - allCodeFeatures, - ], + HELPER_PREFIX, ) rootMap.get(root)!.defineSlots = `{ vSlots?: typeof ${HELPER_PREFIX}slots }` @@ -151,10 +169,10 @@ function getRootMap(options: TransformOptions): RootMap { replaceSourceRange( codes, source, - getStart(macro, options), - getStart(macro, options), - `const ${HELPER_PREFIX}expose = ${getText(macro.arguments[0], options)};`, - [HELPER_PREFIX, source, getStart(macro, options), allCodeFeatures], + getStart(expression, options), + getStart(expression, options), + `const ${HELPER_PREFIX}expose = ${getText(expression.arguments[0], options)};`, + HELPER_PREFIX, ) rootMap.get(root)!.defineExpose = `(exposed: typeof ${HELPER_PREFIX}expose) => {}` From 564c05a2fc991db3ed7148ef547904cec9faa825 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 19 Sep 2024 17:54:53 +0800 Subject: [PATCH 017/156] feat: support vueCompilerOptions --- packages/volar/src/jsx-macros.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 48930a92d..51857e512 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -3,6 +3,7 @@ import { toValidAssetId } from '@vue/compiler-dom' import { replaceSourceRange } from 'muggle-string' import { getStart, getText, type VueMacrosPlugin } from './common' import type { TransformOptions } from './jsx-directive/index' +import type { VueCompilerOptions } from '@vue/language-core' type RootMap = Map< | import('typescript').ArrowFunction @@ -18,6 +19,7 @@ type RootMap = Map< function getMacro( node: import('typescript').Node | undefined, ts: typeof import('typescript'), + vueCompilerOptions: VueCompilerOptions, ): | { expression: import('typescript').CallExpression @@ -65,14 +67,19 @@ function getMacro( return !!( ts.isCallExpression(node) && ts.isIdentifier(node.expression) && - ['defineSlots', 'defineModel', 'defineExpose'].includes( - node.expression.escapedText!, - ) + [ + ...vueCompilerOptions.macros.defineModel, + ...vueCompilerOptions.macros.defineExpose, + ...vueCompilerOptions.macros.defineSlots, + ].includes(node.expression.escapedText!) ) } } -function getRootMap(options: TransformOptions): RootMap { +function getRootMap( + options: TransformOptions, + vueCompilerOptions: VueCompilerOptions, +): RootMap { const { ts, sfc, source, codes } = options const rootMap: RootMap = new Map() @@ -102,14 +109,14 @@ function getRootMap(options: TransformOptions): RootMap { ) } - const macro = root && getMacro(node, ts) + const macro = root && getMacro(node, ts, vueCompilerOptions) if (macro) { const { expression, isReactivityTransform, initializer } = macro if (!rootMap.has(root)) { rootMap.set(root, {}) } const name = getText(expression.expression, options) - if (name === 'defineModel') { + if (vueCompilerOptions.macros.defineModel.includes(name)) { const modelName = expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) @@ -154,7 +161,7 @@ function getRootMap(options: TransformOptions): RootMap { getStart(isReactivityTransform ? initializer : expression, options), `// @ts-ignore\n${id};\nlet ${id} =`, ) - } else if (name === 'defineSlots') { + } else if (vueCompilerOptions.macros.defineSlots.includes(name)) { replaceSourceRange( codes, source, @@ -165,7 +172,7 @@ function getRootMap(options: TransformOptions): RootMap { ) rootMap.get(root)!.defineSlots = `{ vSlots?: typeof ${HELPER_PREFIX}slots }` - } else if (name === 'defineExpose') { + } else if (vueCompilerOptions.macros.defineExpose.includes(name)) { replaceSourceRange( codes, source, @@ -311,7 +318,7 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { ts: ctx.modules.typescript, codes: embeddedFile.content, } - const rootMap = getRootMap(options) + const rootMap = getRootMap(options, ctx.vueCompilerOptions) if (rootMap.size) transformJsxMacros(rootMap, options) } }, From c026485f224efc0348e321cc087294f9bc28201c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 19 Sep 2024 23:37:49 +0800 Subject: [PATCH 018/156] feat: remove prefix --- .../jsx-macros/src/core/setup-fc/index.ts | 4 +-- packages/volar/src/jsx-macros.ts | 25 ++++++------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/packages/jsx-macros/src/core/setup-fc/index.ts b/packages/jsx-macros/src/core/setup-fc/index.ts index 512085c27..c733f675a 100644 --- a/packages/jsx-macros/src/core/setup-fc/index.ts +++ b/packages/jsx-macros/src/core/setup-fc/index.ts @@ -11,7 +11,6 @@ export function transformSetupFC( s: MagicStringAST, ): void { if (node.params[0]) { - restructure(s, node) const isBlockStatement = node.body.type === 'BlockStatement' const start = node.body.extra?.parenthesized ? (node.body.extra.parenStart as number) @@ -27,7 +26,8 @@ export function transformSetupFC( if (!isBlockStatement) { s.appendRight(node.end!, '}') } - s.removeNode(node.params[0]) + + restructure(s, node) } } diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 51857e512..d220c1ced 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -112,9 +112,7 @@ function getRootMap( const macro = root && getMacro(node, ts, vueCompilerOptions) if (macro) { const { expression, isReactivityTransform, initializer } = macro - if (!rootMap.has(root)) { - rootMap.set(root, {}) - } + if (!rootMap.has(root)) rootMap.set(root, { defineModel: [] }) const name = getText(expression.expression, options) if (vueCompilerOptions.macros.defineModel.includes(name)) { const modelName = @@ -147,13 +145,6 @@ function getRootMap( `${modelName}${requiredString} ${typeString}`, `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, ) - replaceSourceRange( - codes, - source, - getStart(expression, options), - getStart(expression, options), - HELPER_PREFIX, - ) replaceSourceRange( codes, source, @@ -168,7 +159,6 @@ function getRootMap( getStart(expression, options), getStart(expression, options), `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, - HELPER_PREFIX, ) rootMap.get(root)!.defineSlots = `{ vSlots?: typeof ${HELPER_PREFIX}slots }` @@ -179,7 +169,6 @@ function getRootMap( getStart(expression, options), getStart(expression, options), `const ${HELPER_PREFIX}expose = ${getText(expression.arguments[0], options)};`, - HELPER_PREFIX, ) rootMap.get(root)!.defineExpose = `(exposed: typeof ${HELPER_PREFIX}expose) => {}` @@ -203,8 +192,8 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { const asyncPrefix = root.modifiers?.find( (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, ) - ? 'async' - : '' + if (asyncPrefix) + replaceSourceRange(codes, source, asyncPrefix.pos, asyncPrefix.end, '') const result = `({}) as __VLS_MaybeReturnType['render']> & { __ctx: Awaited }` @@ -219,7 +208,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` : '', - `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncPrefix}(`, + `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncPrefix ? 'async' : ''}(`, ) replaceSourceRange( codes, @@ -290,9 +279,9 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) { codes.push( ` -declare function ${HELPER_PREFIX}defineSlots>(slots?: T): T -declare const ${HELPER_PREFIX}defineExpose: typeof import('vue').defineExpose; -declare const ${HELPER_PREFIX}defineModel: typeof import('vue').defineModel; +declare function defineSlots>(slots?: T): T +declare const defineExpose: typeof import('vue').defineExpose; +declare const defineModel: typeof import('vue').defineModel; declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, ) From 57919062fd073480902736028dc6fa6f00ad31a6 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 19 Sep 2024 23:38:15 +0800 Subject: [PATCH 019/156] chore: update mono --- packages/jsx-macros/package.json | 80 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 8be16d151..492d2d2d7 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,9 +1,9 @@ { "name": "@vue-macros/jsx-macros", "version": "0.0.0", - "packageManager": "pnpm@9.9.0", + "packageManager": "pnpm@9.10.0", "description": "jsx-macros feature from Vue Macros.", - "type": "commonjs", + "type": "module", "keywords": [ "vue-macros", "macros", @@ -28,54 +28,54 @@ "files": [ "dist" ], - "main": "dist/index.js", - "module": "dist/index.mjs", + "main": "dist/index.cjs", + "module": "dist/index.js", "types": "dist/index.d.ts", "exports": { ".": { "dev": "./src/index.ts", - "require": "./dist/index.js", - "import": "./dist/index.mjs" + "require": "./dist/index.cjs", + "import": "./dist/index.js" }, "./api": { "dev": "./src/api.ts", - "require": "./dist/api.js", - "import": "./dist/api.mjs" + "require": "./dist/api.cjs", + "import": "./dist/api.js" }, "./esbuild": { "dev": "./src/esbuild.ts", - "require": "./dist/esbuild.js", - "import": "./dist/esbuild.mjs" + "require": "./dist/esbuild.cjs", + "import": "./dist/esbuild.js" }, "./helpers": { "dev": "./src/helpers.ts", - "require": "./dist/helpers.js", - "import": "./dist/helpers.mjs" + "require": "./dist/helpers.cjs", + "import": "./dist/helpers.js" }, "./rolldown": { "dev": "./src/rolldown.ts", - "require": "./dist/rolldown.js", - "import": "./dist/rolldown.mjs" + "require": "./dist/rolldown.cjs", + "import": "./dist/rolldown.js" }, "./rollup": { "dev": "./src/rollup.ts", - "require": "./dist/rollup.js", - "import": "./dist/rollup.mjs" + "require": "./dist/rollup.cjs", + "import": "./dist/rollup.js" }, "./rspack": { "dev": "./src/rspack.ts", - "require": "./dist/rspack.js", - "import": "./dist/rspack.mjs" + "require": "./dist/rspack.cjs", + "import": "./dist/rspack.js" }, "./vite": { "dev": "./src/vite.ts", - "require": "./dist/vite.js", - "import": "./dist/vite.mjs" + "require": "./dist/vite.cjs", + "import": "./dist/vite.js" }, "./webpack": { "dev": "./src/webpack.ts", - "require": "./dist/webpack.js", - "import": "./dist/webpack.mjs" + "require": "./dist/webpack.cjs", + "import": "./dist/webpack.js" }, "./*": "./*" }, @@ -91,40 +91,40 @@ "access": "public", "exports": { ".": { - "require": "./dist/index.js", - "import": "./dist/index.mjs" + "require": "./dist/index.cjs", + "import": "./dist/index.js" }, "./api": { - "require": "./dist/api.js", - "import": "./dist/api.mjs" + "require": "./dist/api.cjs", + "import": "./dist/api.js" }, "./esbuild": { - "require": "./dist/esbuild.js", - "import": "./dist/esbuild.mjs" + "require": "./dist/esbuild.cjs", + "import": "./dist/esbuild.js" }, "./helpers": { - "require": "./dist/helpers.js", - "import": "./dist/helpers.mjs" + "require": "./dist/helpers.cjs", + "import": "./dist/helpers.js" }, "./rolldown": { - "require": "./dist/rolldown.js", - "import": "./dist/rolldown.mjs" + "require": "./dist/rolldown.cjs", + "import": "./dist/rolldown.js" }, "./rollup": { - "require": "./dist/rollup.js", - "import": "./dist/rollup.mjs" + "require": "./dist/rollup.cjs", + "import": "./dist/rollup.js" }, "./rspack": { - "require": "./dist/rspack.js", - "import": "./dist/rspack.mjs" + "require": "./dist/rspack.cjs", + "import": "./dist/rspack.js" }, "./vite": { - "require": "./dist/vite.js", - "import": "./dist/vite.mjs" + "require": "./dist/vite.cjs", + "import": "./dist/vite.js" }, "./webpack": { - "require": "./dist/webpack.js", - "import": "./dist/webpack.mjs" + "require": "./dist/webpack.cjs", + "import": "./dist/webpack.js" }, "./*": "./*" } From 4963ad5f5b4d3d693358e175483b37698f2eace8 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 21 Sep 2024 12:50:03 +0800 Subject: [PATCH 020/156] feat: support defineComponent --- .../src/core/define-expose/index.ts | 19 ++ packages/jsx-macros/src/core/index.ts | 39 ++-- .../jsx-macros/src/core/setup-fc/index.ts | 37 ++-- .../src/core/setup-fc/restructure.ts | 2 +- .../tests/__snapshots__/fixtures.test.ts.snap | 60 +++++- .../__snapshots__/restructure.spec.ts.snap | 20 +- .../jsx-macros/tests/fixtures/setup-fc.tsx | 16 ++ packages/volar/src/jsx-macros.ts | 191 ++++++++++-------- 8 files changed, 244 insertions(+), 140 deletions(-) create mode 100644 packages/jsx-macros/tests/fixtures/setup-fc.tsx diff --git a/packages/jsx-macros/src/core/define-expose/index.ts b/packages/jsx-macros/src/core/define-expose/index.ts index c4cd9399b..1a5655e0d 100644 --- a/packages/jsx-macros/src/core/define-expose/index.ts +++ b/packages/jsx-macros/src/core/define-expose/index.ts @@ -1,2 +1,21 @@ +import type { FunctionalNode } from '..' +import { transformReactDefineExpose } from './react' +import { transformVueDefineExpose } from './vue' +import type { CallExpression } from '@babel/types' +import type { MagicStringAST } from '@vue-macros/common' + export { transformVueDefineExpose } from './vue' export { transformReactDefineExpose } from './react' + +export function transformDefineExpose( + node: CallExpression, + root: FunctionalNode, + s: MagicStringAST, + lib: string, +): void { + if (lib.includes('vue')) { + transformVueDefineExpose(node, s, lib) + } else if (lib.includes('react')) { + transformReactDefineExpose(node, root, s, lib) + } +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index a1dc11951..55ff10215 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -70,17 +70,20 @@ function getRootMap(s: MagicStringAST, id: string) { : undefined if (!root) return - let isSetupFC = false if ( - root.type !== 'FunctionDeclaration' && - parents[2]?.type === 'VariableDeclarator' && - parents[2].id.type === 'Identifier' && - parents[2].id.typeAnnotation?.type === 'TSTypeAnnotation' && - s.sliceNode(parents[2].id.typeAnnotation.typeAnnotation) === 'SetupFC' + (root.type !== 'FunctionDeclaration' && + parents[2]?.type === 'VariableDeclarator' && + parents[2].id.type === 'Identifier' && + parents[2].id.typeAnnotation?.type === 'TSTypeAnnotation' && + s.sliceNode(parents[2].id.typeAnnotation.typeAnnotation) === + 'SetupFC') || + (parents[2]?.type === 'CallExpression' && + ['defineComponent', 'defineSetupComponent'].includes( + s.sliceNode(parents[2].callee), + )) ) { - isSetupFC = true if (!rootMap.has(root)) rootMap.set(root, {}) - rootMap.get(root)!.isSetupFC = isSetupFC + rootMap.get(root)!.isSetupFC = true } if (!isMacro(expression)) return @@ -124,7 +127,9 @@ export function transformJsxMacros( for (const [root, map] of rootMap) { let propsName = `${HELPER_PREFIX}props` - if (root.params[0]) { + if (map.isSetupFC) { + transformSetupFC(root, s) + } else if (root.params[0]) { if (root.params[0].type === 'Identifier') { propsName = root.params[0].name } else if (root.params[0].type === 'ObjectPattern') { @@ -144,10 +149,10 @@ export function transformJsxMacros( } } } else { - s.appendRight(getParamsStart(root, s.original), `${HELPER_PREFIX}props`) + s.appendRight(getParamsStart(root, s.original), propsName) } - if (map.defineModel?.length && !map.isSetupFC) { + if (map.defineModel?.length) { map.defineModel.forEach((node) => { transformDefineModel(node, propsName, s) }) @@ -155,16 +160,8 @@ export function transformJsxMacros( if (map.defineSlots) { transformDefineSlots(map.defineSlots, propsName, s, options.lib) } - if (map.defineExpose && !map.isSetupFC) { - if (options.lib.includes('vue')) { - transformVueDefineExpose(map.defineExpose, s, options.lib) - } else if (options.lib.includes('react')) { - transformReactDefineExpose(map.defineExpose, root, s, options.lib) - } - } - - if (map.isSetupFC) { - transformSetupFC(root, s) + if (map.defineExpose) { + transformReactDefineExpose(map.defineExpose, root, s, options.lib) } } diff --git a/packages/jsx-macros/src/core/setup-fc/index.ts b/packages/jsx-macros/src/core/setup-fc/index.ts index c733f675a..cbe38de85 100644 --- a/packages/jsx-macros/src/core/setup-fc/index.ts +++ b/packages/jsx-macros/src/core/setup-fc/index.ts @@ -10,24 +10,23 @@ export function transformSetupFC( node: FunctionalNode, s: MagicStringAST, ): void { - if (node.params[0]) { - const isBlockStatement = node.body.type === 'BlockStatement' - const start = node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start! - if (!isBlockStatement) { - s.appendLeft(start, '{') - } - const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') - s.appendRight( - start + (isBlockStatement ? 1 : 0), - `\nconst ${HELPER_PREFIX}props0 = ${useAttrs}();${!isBlockStatement ? 'return ' : ''}`, - ) - if (!isBlockStatement) { - s.appendRight(node.end!, '}') - } - s.removeNode(node.params[0]) - - restructure(s, node) + const isBlockStatement = node.body.type === 'BlockStatement' + const start = node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start! + if (!isBlockStatement) { + s.appendLeft(start, '{') + } + const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') + s.appendRight( + start + (isBlockStatement ? 1 : 0), + `\nconst ${HELPER_PREFIX}props = ${useAttrs}();${!isBlockStatement ? 'return ' : ''}`, + ) + if (!isBlockStatement) { + s.appendRight(node.end!, '}') } + + restructure(s, node) + + if (node.params[0]) s.removeNode(node.params[0]) } diff --git a/packages/jsx-macros/src/core/setup-fc/restructure.ts b/packages/jsx-macros/src/core/setup-fc/restructure.ts index fc6033166..1f0321ca7 100644 --- a/packages/jsx-macros/src/core/setup-fc/restructure.ts +++ b/packages/jsx-macros/src/core/setup-fc/restructure.ts @@ -77,7 +77,7 @@ export function restructure(s: MagicString, node: FunctionalNode): void { let index = 0 const propMap: PropMap = new Map() for (const param of node.params) { - const path = `${HELPER_PREFIX}props${index++}` + const path = `${HELPER_PREFIX}props${index ? index++ : ''}` if (collectProps(param, path, s, propMap)) { s.overwrite(param.start!, param.end!, path) } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 6f67b0fde..7572e581e 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -2,13 +2,13 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { - __MACROS_useExpose(__MACROS_getCurrentInstance(), { +import { forwardRef as __MACROS_forwardRef } from "vue"; +import { useImperativeHandle as __MACROS_useImperativeHandle } from "vue";export default __MACROS_forwardRef(function (__MACROS_props, __MACROS_ref) { + __MACROS_useImperativeHandle(__MACROS_ref, () =>({ foo: 1, - }) + }), []) return
-} +}) " `; @@ -44,6 +44,31 @@ export default function (__MACROS_props) { " `; +exports[`fixtures > ./fixtures/setup-fc.tsx 1`] = ` +" +import { useAttrs as __MACROS_useAttrs } from "vue"; +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = defineComponent(() => { +const __MACROS_props = __MACROS_useAttrs(); + const foo = __MACROS_useModel(__MACROS_props, 'foo') + return () => { + return
{[foo.value, __MACROS_props.bar]}
+ } +}) + +const SetupComp = defineSetupComponent(() => { +const __MACROS_props = __MACROS_useAttrs(); + return () => { + return
{__MACROS_props.foo}
+ } +}) + +const SetupCompType: SetupFC = () => { +const __MACROS_props = __MACROS_useAttrs(); + return
{__MACROS_props.foo}
+} +" +`; + exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { forwardRef as __MACROS_forwardRef } from "react"; @@ -86,3 +111,28 @@ export default function (__MACROS_props) { } " `; + +exports[`react fixtures > ./fixtures/setup-fc.tsx 1`] = ` +" +import { useAttrs as __MACROS_useAttrs } from "vue"; +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = defineComponent(() => { +const __MACROS_props = __MACROS_useAttrs(); + const foo = __MACROS_useModel(__MACROS_props, 'foo') + return () => { + return
{[foo.value, __MACROS_props.bar]}
+ } +}) + +const SetupComp = defineSetupComponent(() => { +const __MACROS_props = __MACROS_useAttrs(); + return () => { + return
{__MACROS_props.foo}
+ } +}) + +const SetupCompType: SetupFC = () => { +const __MACROS_props = __MACROS_useAttrs(); + return
{__MACROS_props.foo}
+} +" +`; diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap index ac7eb99ea..c949f48f3 100644 --- a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap @@ -1,29 +1,29 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`transform > reconstruct 1`] = ` -"const App = (__MACROS_props0, __MACROS_props1) => { - function onClick(__MACROS_props0){ - return { foo: __MACROS_props0.foo, baz: __MACROS_props1.baz.baz } +"const App = (__MACROS_props, __MACROS_props) => { + function onClick(__MACROS_props){ + return { foo: __MACROS_props.foo, baz: __MACROS_props.baz.baz } }; - return [ __MACROS_props0[0][0][1], __MACROS_props0[1].id.foo[0], __MACROS_props1.baz ] + return [ __MACROS_props[0][0][1], __MACROS_props[1].id.foo[0], __MACROS_props.baz ] }" `; exports[`transform > reconstruct arrowFunctionExpression 1`] = ` -"const App = (__MACROS_props0) => ( - <>{[__MACROS_props0[0].root.foo]} +"const App = (__MACROS_props) => ( + <>{[__MACROS_props[0].root.foo]} )" `; exports[`transform > reconstruct default-prop 1`] = ` -"function App(__MACROS_props0, __MACROS_props1){Object.defineProperty(__MACROS_props0, 'foo', { enumerable: true, get: () => __MACROS_props0['foo'] ?? [] });Object.defineProperty(__MACROS_props1, 'bar', { enumerable: true, get: () => __MACROS_props1['bar'] ?? 1 }); - return <>{[__MACROS_props0.foo, __MACROS_props1.bar, __MACROS_props1[1]]} +"function App(__MACROS_props, __MACROS_props){Object.defineProperty(__MACROS_props, 'foo', { enumerable: true, get: () => __MACROS_props['foo'] ?? [] });Object.defineProperty(__MACROS_props, 'bar', { enumerable: true, get: () => __MACROS_props['bar'] ?? 1 }); + return <>{[__MACROS_props.foo, __MACROS_props.bar, __MACROS_props[1]]} }" `; exports[`transform > reconstruct rest-prop 1`] = ` " -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props0){Object.defineProperty(__MACROS_props0, 'bar', { enumerable: true, get: () => __MACROS_props0['bar'] ?? 1 });const rest = __MACROS_createPropsRestProxy(__MACROS_props0, ['foo', 'bar']); - return <>{[__MACROS_props0.foo, __MACROS_props0.bar, rest]} +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props){Object.defineProperty(__MACROS_props, 'bar', { enumerable: true, get: () => __MACROS_props['bar'] ?? 1 });const rest = __MACROS_createPropsRestProxy(__MACROS_props, ['foo', 'bar']); + return <>{[__MACROS_props.foo, __MACROS_props.bar, rest]} }" `; diff --git a/packages/jsx-macros/tests/fixtures/setup-fc.tsx b/packages/jsx-macros/tests/fixtures/setup-fc.tsx new file mode 100644 index 000000000..dcadde0dd --- /dev/null +++ b/packages/jsx-macros/tests/fixtures/setup-fc.tsx @@ -0,0 +1,16 @@ +const Comp = defineComponent(({ bar }: { bar: string }) => { + const foo = defineModel('foo') + return () => { + return
{[foo.value, bar]}
+ } +}) + +const SetupComp = defineSetupComponent(({ foo }: { foo: string }) => { + return () => { + return
{foo}
+ } +}) + +const SetupCompType: SetupFC = ({ foo }: { foo: string }) => { + return
{foo}
+} diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index d220c1ced..457b1279a 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -13,6 +13,10 @@ type RootMap = Map< defineModel?: string[] defineSlots?: string defineExpose?: string + setupFC?: { + start: number + end: number + } } > @@ -87,6 +91,12 @@ function getRootMap( node: import('typescript').Node, parents: import('typescript').Node[], ) { + ts.forEachChild(node, (child) => { + parents.unshift(node) + walk(child, parents) + parents.shift() + }) + const root = parents[1] && (ts.isArrowFunction(parents[1]) || @@ -94,92 +104,100 @@ function getRootMap( ts.isFunctionDeclaration(parents[1])) ? parents[1] : undefined + if (!root) return + if ( - root && - !ts.isFunctionDeclaration(root) && + parents[2] && ts.isVariableDeclaration(parents[2]) && parents[2].type && getText(parents[2].type, options) === 'SetupFC' ) { - replaceSourceRange( - codes, - source, - parents[2].name.end, - parents[2].type.end, + if (!rootMap.has(root)) rootMap.set(root, {}) + rootMap.get(root)!.setupFC = { + start: parents[2].name.end, + end: parents[2].type.end, + } + } + if ( + parents[2] && + ts.isCallExpression(parents[2]) && + !parents[2].typeArguments && + ['defineComponent', 'defineSetupComponent'].includes( + getText(parents[2].expression, options), ) + ) { + if (!rootMap.has(root)) rootMap.set(root, {}) + rootMap.get(root)!.setupFC = { + start: getStart(parents[2].expression, options), + end: parents[2].expression.end, + } } - const macro = root && getMacro(node, ts, vueCompilerOptions) - if (macro) { - const { expression, isReactivityTransform, initializer } = macro - if (!rootMap.has(root)) rootMap.set(root, { defineModel: [] }) - const name = getText(expression.expression, options) - if (vueCompilerOptions.macros.defineModel.includes(name)) { - const modelName = - expression.arguments[0] && - ts.isStringLiteralLike(expression.arguments[0]) - ? expression.arguments[0].text - : 'modelValue' - const modelOptions = - expression.arguments[0] && - ts.isStringLiteralLike(expression.arguments[0]) - ? expression.arguments[1] - : expression.arguments[0] - let required = false - if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { - for (const prop of modelOptions.properties) { - if ( - ts.isPropertyAssignment(prop) && - getText(prop.name, options) === 'required' - ) { - required = prop.initializer.kind === ts.SyntaxKind.TrueKeyword - } + const macro = getMacro(node, ts, vueCompilerOptions) + if (!macro) return + + const { expression, isReactivityTransform, initializer } = macro + if (!rootMap.has(root)) rootMap.set(root, {}) + const name = getText(expression.expression, options) + if (vueCompilerOptions.macros.defineModel.includes(name)) { + const modelName = + expression.arguments[0] && + ts.isStringLiteralLike(expression.arguments[0]) + ? expression.arguments[0].text + : 'modelValue' + const modelOptions = + expression.arguments[0] && + ts.isStringLiteralLike(expression.arguments[0]) + ? expression.arguments[1] + : expression.arguments[0] + let required = false + if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { + for (const prop of modelOptions.properties) { + if ( + ts.isPropertyAssignment(prop) && + getText(prop.name, options) === 'required' + ) { + required = prop.initializer.kind === ts.SyntaxKind.TrueKeyword } } - const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) - const typeString = `import("vue").UnwrapRef` - const requiredString = required ? ':' : '?:' - rootMap - .get(root)! - .defineModel?.push( - `${modelName}${requiredString} ${typeString}`, - `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, - ) - replaceSourceRange( - codes, - source, - getStart(isReactivityTransform ? initializer : expression, options), - getStart(isReactivityTransform ? initializer : expression, options), - `// @ts-ignore\n${id};\nlet ${id} =`, - ) - } else if (vueCompilerOptions.macros.defineSlots.includes(name)) { - replaceSourceRange( - codes, - source, - getStart(expression, options), - getStart(expression, options), - `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, - ) - rootMap.get(root)!.defineSlots = - `{ vSlots?: typeof ${HELPER_PREFIX}slots }` - } else if (vueCompilerOptions.macros.defineExpose.includes(name)) { - replaceSourceRange( - codes, - source, - getStart(expression, options), - getStart(expression, options), - `const ${HELPER_PREFIX}expose = ${getText(expression.arguments[0], options)};`, - ) - rootMap.get(root)!.defineExpose = - `(exposed: typeof ${HELPER_PREFIX}expose) => {}` } + const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) + const typeString = `import("vue").UnwrapRef` + const requiredString = required ? ':' : '?:' + ;(rootMap.get(root)!.defineModel ??= [])!.push( + `${modelName}${requiredString} ${typeString}`, + `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, + ) + replaceSourceRange( + codes, + source, + getStart(isReactivityTransform ? initializer : expression, options), + getStart(isReactivityTransform ? initializer : expression, options), + `// @ts-ignore\n${id};\nlet ${id} =`, + ) + } else if (vueCompilerOptions.macros.defineSlots.includes(name)) { + replaceSourceRange( + codes, + source, + getStart(expression, options), + getStart(expression, options), + `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, + ) + rootMap.get(root)!.defineSlots = + `{ vSlots?: typeof ${HELPER_PREFIX}slots }` + } else if (vueCompilerOptions.macros.defineExpose.includes(name)) { + replaceSourceRange( + codes, + source, + getStart(expression, options), + getStart(expression, options), + `const ${HELPER_PREFIX}expose = ${getText(expression.arguments[0], options)};`, + ) + rootMap.get(root)!.defineExpose = + `(exposed: typeof ${HELPER_PREFIX}expose) => {}` } - ts.forEachChild(node, (child) => { - parents.unshift(node) - walk(child, parents) - parents.shift() - }) } + ts.forEachChild(sfc[source]!.ast, (node) => walk(node, [])) return rootMap } @@ -187,13 +205,13 @@ function getRootMap( function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { const { ts, source, codes } = options - for (const [root, props] of rootMap) { + for (const [root, map] of rootMap) { if (!root.body) continue - const asyncPrefix = root.modifiers?.find( + const asyncModifier = root.modifiers?.find( (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, ) - if (asyncPrefix) - replaceSourceRange(codes, source, asyncPrefix.pos, asyncPrefix.end, '') + if (asyncModifier) + replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) const result = `({}) as __VLS_MaybeReturnType['render']> & { __ctx: Awaited }` @@ -208,7 +226,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` : '', - `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncPrefix ? 'async' : ''}(`, + `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, ) replaceSourceRange( codes, @@ -228,7 +246,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { root.parameters[0]?.type ? `${getText(root.parameters[0].type, options)} & ` : '', - `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncPrefix}(`, + `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, ) replaceSourceRange( codes, @@ -247,6 +265,13 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) } + if ( + map.setupFC && + (root.parameters.length || Object.keys(map).length > 1) + ) { + replaceSourceRange(codes, source, map.setupFC.start, map.setupFC.end) + } + ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { replaceSourceRange( @@ -255,11 +280,9 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { getStart(node, options), getStart(node.expression, options), `return {\nprops: {} as `, - props.defineModel?.length - ? `{ ${props.defineModel?.join(', ')} }` - : '{}', - props.defineSlots ? ` & ${props.defineSlots}` : '', - props.defineExpose ? `,\nexpose: ${props.defineExpose}` : '', + map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', + map.defineSlots ? ` & ${map.defineSlots}` : '', + map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', `,\nrender: `, ) replaceSourceRange( From 821434192caf5d1ad7c9e9a1709a8d6cee0b80ee Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 22 Sep 2024 15:50:14 +0800 Subject: [PATCH 021/156] feat: support default for restructure --- packages/jsx-macros/src/api.ts | 2 + packages/jsx-macros/src/core/helper/index.ts | 3 + .../src/core/helper/with-defaults.ts | 21 +++ packages/jsx-macros/src/core/index.ts | 21 +-- .../src/core/setup-fc/restructure.ts | 157 +++++++++++++----- packages/jsx-macros/src/index.ts | 3 + .../tests/__snapshots__/fixtures.test.ts.snap | 10 +- .../__snapshots__/restructure.spec.ts.snap | 22 ++- packages/jsx-macros/tests/restructure.spec.ts | 6 +- 9 files changed, 175 insertions(+), 70 deletions(-) create mode 100644 packages/jsx-macros/src/core/helper/with-defaults.ts diff --git a/packages/jsx-macros/src/api.ts b/packages/jsx-macros/src/api.ts index 46d458ad7..03e8106c0 100644 --- a/packages/jsx-macros/src/api.ts +++ b/packages/jsx-macros/src/api.ts @@ -1 +1,3 @@ export * from './core' +export { restructure } from './core/setup-fc/restructure' +export { createDefaultPropsProxy } from './core/helper/with-defaults' diff --git a/packages/jsx-macros/src/core/helper/index.ts b/packages/jsx-macros/src/core/helper/index.ts index 26896a0b9..bdd5fc1ab 100644 --- a/packages/jsx-macros/src/core/helper/index.ts +++ b/packages/jsx-macros/src/core/helper/index.ts @@ -7,3 +7,6 @@ export { default as useExposeHelperCode } from './use-expose?raw' export const useModelHelperId: '/vue-macros/jsx-macros/use-model' = `${helperPrefix}/use-model` export { default as useModelHelperCode } from './use-model?raw' + +export const withDefaultsHelperId: '/vue-macros/jsx-macros/with-defaults' = `${helperPrefix}/with-defaults` +export { default as withDefaultsCode } from './with-defaults?raw' diff --git a/packages/jsx-macros/src/core/helper/with-defaults.ts b/packages/jsx-macros/src/core/helper/with-defaults.ts new file mode 100644 index 000000000..38dacad14 --- /dev/null +++ b/packages/jsx-macros/src/core/helper/with-defaults.ts @@ -0,0 +1,21 @@ +function getByPath(obj: any, path: string[] = []) { + while (path.length) { + obj = obj[path.shift()!] + } + return obj +} + +export function createDefaultPropsProxy( + props: any, + defaults?: any, +): Record { + const ret: Record = {} + for (const key of Object.keys(defaults)) { + const path = key.split(/[.?[\]]/).filter(Boolean) + Object.defineProperty(ret, key, { + enumerable: true, + get: () => getByPath(props, path) ?? getByPath(defaults, path), + }) + } + return ret +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 55ff10215..69af81cb7 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -9,10 +9,7 @@ import { type CodeTransform, } from '@vue-macros/common' import type { OptionsResolved } from '..' -import { - transformReactDefineExpose, - transformVueDefineExpose, -} from './define-expose' +import { transformDefineExpose } from './define-expose' import { transformDefineModel } from './define-model' import { transformDefineSlots } from './define-slots' import { transformSetupFC } from './setup-fc' @@ -24,8 +21,6 @@ import type { Node, } from '@babel/types' -export { restructure } from './setup-fc/restructure' - export type FunctionalNode = | FunctionDeclaration | FunctionExpression @@ -55,12 +50,6 @@ function getRootMap(s: MagicStringAST, id: string) { walkAST(babelParse(s.original, getLang(id)), { enter(node, parent) { parents.unshift(parent) - const expression = - node.type === 'VariableDeclaration' - ? node.declarations[0].init - : node.type === 'ExpressionStatement' - ? node.expression - : undefined const root = parents[1] && (parents[1].type === 'ArrowFunctionExpression' || @@ -86,6 +75,12 @@ function getRootMap(s: MagicStringAST, id: string) { rootMap.get(root)!.isSetupFC = true } + const expression = + node.type === 'VariableDeclaration' + ? node.declarations[0].init + : node.type === 'ExpressionStatement' + ? node.expression + : undefined if (!isMacro(expression)) return if (!rootMap.has(root)) rootMap.set(root, {}) const macro = @@ -161,7 +156,7 @@ export function transformJsxMacros( transformDefineSlots(map.defineSlots, propsName, s, options.lib) } if (map.defineExpose) { - transformReactDefineExpose(map.defineExpose, root, s, options.lib) + transformDefineExpose(map.defineExpose, root, s, options.lib) } } diff --git a/packages/jsx-macros/src/core/setup-fc/restructure.ts b/packages/jsx-macros/src/core/setup-fc/restructure.ts index 1f0321ca7..423a7ee05 100644 --- a/packages/jsx-macros/src/core/setup-fc/restructure.ts +++ b/packages/jsx-macros/src/core/setup-fc/restructure.ts @@ -4,19 +4,23 @@ import { type MagicString, } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' +import { withDefaultsHelperId } from '../helper' import type { FunctionalNode } from '..' import type { Node } from '@babel/types' -type PropMap = Map< - string, - { path: string; value: string; defaultValue?: string; isRest?: boolean } -> +type Prop = { + path: string + name: string + value: string + defaultValue?: string + isRest?: boolean +} -function collectProps( +function getProps( node: Node, path: string = '', s: MagicString, - propMap: PropMap, + props: Prop[] = [], ) { const properties = node.type === 'ObjectPattern' @@ -29,14 +33,17 @@ function collectProps( const propNames: string[] = [] properties.forEach((prop, index) => { if (prop?.type === 'Identifier') { - propMap.set(prop.name, { path, value: `[${index}]` }) + // { foo } + props.push({ name: prop.name, path, value: `[${index}]` }) propNames.push(`'${prop.name}'`) } else if ( prop?.type === 'AssignmentPattern' && prop.left.type === 'Identifier' ) { - propMap.set(prop.left.name, { + // [foo = 'foo'] + props.push({ path, + name: prop.left.name, value: `.${prop.left.name}`, defaultValue: s.slice(prop.right.start!, prop.right.end!), }) @@ -45,71 +52,137 @@ function collectProps( prop?.type === 'ObjectProperty' && prop.key.type === 'Identifier' ) { - if (prop.value.type === 'AssignmentPattern') { - propMap.set(prop.key.name, { + if ( + prop.value.type === 'AssignmentPattern' && + prop.value.left.type === 'Identifier' + ) { + // { foo: bar = 'foo' } + props.push({ path, + name: prop.value.left.name, value: `.${prop.key.name}`, defaultValue: s.slice(prop.value.right.start!, prop.value.right.end!), }) - } else if ( - !collectProps(prop.value, `${path}.${prop.key.name}`, s, propMap) - ) { - propMap.set(prop.key.name, { path, value: `.${prop.key.name}` }) + } else if (!getProps(prop.value, `${path}.${prop.key.name}`, s, props)) { + // { foo: bar } + props.push({ + path, + name: + prop.value.type === 'Identifier' ? prop.value.name : prop.key.name, + value: `.${prop.key.name}`, + }) } propNames.push(`'${prop.key.name}'`) } else if ( prop?.type === 'RestElement' && - prop?.argument.type === 'Identifier' + prop.argument.type === 'Identifier' && + !prop.argument.name.startsWith(`${HELPER_PREFIX}props`) ) { - propMap.set(prop.argument.name, { + // { ...rest } + props.push({ path, + name: prop.argument.name, value: propNames.join(', '), isRest: true, }) } else if (prop) { - collectProps(prop, `${path}[${index}]`, s, propMap) + getProps(prop, `${path}[${index}]`, s, props) } }) - return true + return props.length ? props : undefined +} + +export function prependFunctionalNode( + node: FunctionalNode, + s: MagicString, + result: string, +): void { + const isBlockStatement = node.body.type === 'BlockStatement' + const start = node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start! + s.prependRight( + start + (isBlockStatement ? 1 : 0), + `${result};${!isBlockStatement ? 'return ' : ''}`, + ) + if (!isBlockStatement) { + s.prependLeft(start, '{') + s.prependRight(node.end! + 1, '}') + } } -export function restructure(s: MagicString, node: FunctionalNode): void { +export function restructure( + s: MagicString, + node: FunctionalNode, + withDefaultsFrom: string = withDefaultsHelperId, +): void { let index = 0 - const propMap: PropMap = new Map() + const propList: Prop[] = [] for (const param of node.params) { - const path = `${HELPER_PREFIX}props${index ? index++ : ''}` - if (collectProps(param, path, s, propMap)) { + const path = `${HELPER_PREFIX}props${index++ || ''}` + const props = getProps(param, path, s) + if (props) { + const hasDefaultValue = props.some((i) => i.defaultValue) s.overwrite(param.start!, param.end!, path) + propList.push( + ...(hasDefaultValue + ? props.map((i) => ({ + ...i, + path: i.path.replace(HELPER_PREFIX, `${HELPER_PREFIX}defaults_`), + })) + : props), + ) } } - if (propMap.size) { - for (const [key, { path, value, defaultValue, isRest }] of propMap) { - if (!(defaultValue || isRest)) continue - - const result = defaultValue - ? `Object.defineProperty(${path}, '${key}', { enumerable: true, get: () => ${path}['${key}'] ?? ${defaultValue} })` - : `const ${key} = ${importHelperFn(s, 0, 'createPropsRestProxy', 'vue')}(${path}, [${value}])` - const isBlockStatement = node.body.type === 'BlockStatement' - const start = node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start! - if (!isBlockStatement) { - s.appendLeft(start, '{') + if (propList.length) { + const defaultValues: Record = {} + for (const prop of propList) { + if (prop.defaultValue) { + const basePath = prop.path.split(/\.|\[/)[0] + ;(defaultValues[basePath] ??= []).push(prop) } - s.appendRight( - start + (isBlockStatement ? 1 : 0), - `${result};${!isBlockStatement ? 'return ' : ''}`, - ) - if (!isBlockStatement) { - s.appendRight(node.end! + 1, '}') + if (prop.isRest) { + const createPropsRestProxy = importHelperFn( + s, + 0, + 'createPropsRestProxy', + 'vue', + ) + prependFunctionalNode( + node, + s, + `\nconst ${prop.name} = ${createPropsRestProxy}(${prop.path}, [${prop.value}])`, + ) } } + for (const [path, values] of Object.entries(defaultValues)) { + const createDefaultPropsProxy = importHelperFn( + s, + 0, + 'createDefaultPropsProxy', + withDefaultsFrom, + ) + const resolvedPath = path.replace( + `${HELPER_PREFIX}defaults_`, + HELPER_PREFIX, + ) + const resolvedValues = values + .map( + (i) => `'${i.path.replace(path, '')}${i.value}': ${i.defaultValue}`, + ) + .join(', ') + prependFunctionalNode( + node, + s, + `\nconst ${path} = ${createDefaultPropsProxy}(${resolvedPath}, {${resolvedValues}})`, + ) + } walkIdentifiers( node.body, (id, parent, __, ___, isLocal) => { - const prop = propMap.get(id.name) + const prop = propList.find((i) => i.name === id.name) if (!isLocal && prop && !prop.isRest) { s.overwrite( id.start!, diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index ba5ac28ae..180a6c748 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -21,6 +21,8 @@ import { useExposeHelperId, useModelHelperCode, useModelHelperId, + withDefaultsCode, + withDefaultsHelperId, } from './core/helper' export type Options = BaseOptions & { @@ -68,6 +70,7 @@ const plugin: UnpluginInstance = createUnplugin( const id = normalizePath(_id) if (id === useExposeHelperId) return useExposeHelperCode else if (id === useModelHelperId) return useModelHelperCode + else if (id === withDefaultsHelperId) return withDefaultsCode }, transformInclude: filter, diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 7572e581e..25734e542 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -2,13 +2,13 @@ exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { forwardRef as __MACROS_forwardRef } from "vue"; -import { useImperativeHandle as __MACROS_useImperativeHandle } from "vue";export default __MACROS_forwardRef(function (__MACROS_props, __MACROS_ref) { - __MACROS_useImperativeHandle(__MACROS_ref, () =>({ +import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { + __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, - }), []) + }) return
-}) +} " `; diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap index c949f48f3..b742adecd 100644 --- a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap @@ -1,11 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`transform > reconstruct 1`] = ` -"const App = (__MACROS_props, __MACROS_props) => { +"const App = (__MACROS_props, __MACROS_props1) => { function onClick(__MACROS_props){ - return { foo: __MACROS_props.foo, baz: __MACROS_props.baz.baz } + return { foo: __MACROS_props.foo, baz: __MACROS_props1.baz.baz } }; - return [ __MACROS_props[0][0][1], __MACROS_props[1].id.foo[0], __MACROS_props.baz ] + return [ __MACROS_props[0][0][1], __MACROS_props[1].id.foo[0], __MACROS_props1.baz ] }" `; @@ -16,14 +16,22 @@ exports[`transform > reconstruct arrowFunctionExpression 1`] = ` `; exports[`transform > reconstruct default-prop 1`] = ` -"function App(__MACROS_props, __MACROS_props){Object.defineProperty(__MACROS_props, 'foo', { enumerable: true, get: () => __MACROS_props['foo'] ?? [] });Object.defineProperty(__MACROS_props, 'bar', { enumerable: true, get: () => __MACROS_props['bar'] ?? 1 }); - return <>{[__MACROS_props.foo, __MACROS_props.bar, __MACROS_props[1]]} +" +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; +import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults";function App(__MACROS_props, __MACROS_props1){ +const __MACROS_defaults_props1 = __MACROS_createDefaultPropsProxy(__MACROS_props1, {'.foo': 'foo'}); +const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.foo': 'bar'}); +const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'baz']); + return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.baz, rest, __MACROS_defaults_props1.foo]} }" `; exports[`transform > reconstruct rest-prop 1`] = ` " -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props){Object.defineProperty(__MACROS_props, 'bar', { enumerable: true, get: () => __MACROS_props['bar'] ?? 1 });const rest = __MACROS_createPropsRestProxy(__MACROS_props, ['foo', 'bar']); - return <>{[__MACROS_props.foo, __MACROS_props.bar, rest]} +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; +import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults";function App(__MACROS_props){ +const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 1}); +const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'bar']); + return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.bar, rest]} }" `; diff --git a/packages/jsx-macros/tests/restructure.spec.ts b/packages/jsx-macros/tests/restructure.spec.ts index 9aa102465..9eb23a086 100644 --- a/packages/jsx-macros/tests/restructure.spec.ts +++ b/packages/jsx-macros/tests/restructure.spec.ts @@ -1,7 +1,7 @@ import { babelParse, walkAST } from '@vue-macros/common' import { describe, expect, test } from 'vitest' import { MagicString } from 'vue/compiler-sfc' -import { restructure } from '../src/core' +import { restructure } from '../src/api' import type { Node } from '@babel/types' export function transformRestructure(code: string) { @@ -45,8 +45,8 @@ describe('transform', () => { test('reconstruct default-prop', () => { const code = transformRestructure( - `function App({foo = []}, [bar = 1, baz]){ - return <>{[foo, bar, baz]} + `function App({foo: bar = 'bar', baz: qux, ...rest}, [foo = 'foo']){ + return <>{[bar, qux, rest, foo]} }`, )! expect(code).toMatchSnapshot() From 41ae601fef2210984ddb769f7da530d6846bb678 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 23 Sep 2024 01:26:06 +0800 Subject: [PATCH 022/156] feat: add defineComponent macro --- packages/jsx-macros/src/core/index.ts | 34 +++++++---- .../jsx-macros/src/core/setup-fc/index.ts | 56 ++++++++++++++++--- .../src/core/setup-fc/restructure.ts | 47 ++++++---------- .../tests/__snapshots__/fixtures.test.ts.snap | 24 +++----- .../__snapshots__/restructure.spec.ts.snap | 10 ++-- .../jsx-macros/tests/fixtures/setup-fc.tsx | 8 +-- packages/volar/src/jsx-macros.ts | 39 ++++++++++--- 7 files changed, 137 insertions(+), 81 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 69af81cb7..9c810ceff 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -3,6 +3,7 @@ import { generateTransform, getLang, HELPER_PREFIX, + importHelperFn, isCallOf, MagicStringAST, walkAST, @@ -60,20 +61,31 @@ function getRootMap(s: MagicStringAST, id: string) { if (!root) return if ( - (root.type !== 'FunctionDeclaration' && - parents[2]?.type === 'VariableDeclarator' && - parents[2].id.type === 'Identifier' && - parents[2].id.typeAnnotation?.type === 'TSTypeAnnotation' && - s.sliceNode(parents[2].id.typeAnnotation.typeAnnotation) === - 'SetupFC') || - (parents[2]?.type === 'CallExpression' && - ['defineComponent', 'defineSetupComponent'].includes( - s.sliceNode(parents[2].callee), - )) + root.type !== 'FunctionDeclaration' && + parents[2]?.type === 'VariableDeclarator' && + parents[2].id.type === 'Identifier' && + parents[2].id.typeAnnotation?.type === 'TSTypeAnnotation' && + s.sliceNode(parents[2].id.typeAnnotation.typeAnnotation) === 'SetupFC' ) { if (!rootMap.has(root)) rootMap.set(root, {}) rootMap.get(root)!.isSetupFC = true } + if ( + parents[2]?.type === 'CallExpression' && + ['defineComponent', 'defineSetupComponent'].includes( + s.sliceNode(parents[2].callee), + ) + ) { + if (!rootMap.has(root)) rootMap.set(root, {}) + if (rootMap.get(root)!.isSetupFC) return + rootMap.get(root)!.isSetupFC = true + if (s.sliceNode(parents[2].callee) === 'defineComponent') { + s.overwriteNode( + parents[2].callee, + importHelperFn(s, 0, 'defineComponent', 'vue'), + ) + } + } const expression = node.type === 'VariableDeclaration' @@ -123,7 +135,7 @@ export function transformJsxMacros( for (const [root, map] of rootMap) { let propsName = `${HELPER_PREFIX}props` if (map.isSetupFC) { - transformSetupFC(root, s) + transformSetupFC(root, s, options.lib) } else if (root.params[0]) { if (root.params[0].type === 'Identifier') { propsName = root.params[0].name diff --git a/packages/jsx-macros/src/core/setup-fc/index.ts b/packages/jsx-macros/src/core/setup-fc/index.ts index cbe38de85..0cc0e9fb7 100644 --- a/packages/jsx-macros/src/core/setup-fc/index.ts +++ b/packages/jsx-macros/src/core/setup-fc/index.ts @@ -1,32 +1,74 @@ import { HELPER_PREFIX, importHelperFn, + type MagicString, type MagicStringAST, } from '@vue-macros/common' import type { FunctionalNode } from '..' import { restructure } from './restructure' -export function transformSetupFC( +export function prependFunctionalNode( node: FunctionalNode, - s: MagicStringAST, + s: MagicString, + result: string, ): void { const isBlockStatement = node.body.type === 'BlockStatement' const start = node.body.extra?.parenthesized ? (node.body.extra.parenStart as number) : node.body.start! - if (!isBlockStatement) { - s.appendLeft(start, '{') - } - const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') s.appendRight( start + (isBlockStatement ? 1 : 0), - `\nconst ${HELPER_PREFIX}props = ${useAttrs}();${!isBlockStatement ? 'return ' : ''}`, + `${result};${!isBlockStatement ? 'return ' : ''}`, ) if (!isBlockStatement) { + s.appendLeft(start, '{') s.appendRight(node.end!, '}') } +} + +export function transformSetupFC( + node: FunctionalNode, + s: MagicStringAST, + lib: string, +): void { + const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') + prependFunctionalNode( + node, + s, + `\nconst ${HELPER_PREFIX}props = ${useAttrs}()`, + ) restructure(s, node) if (node.params[0]) s.removeNode(node.params[0]) + + if (lib !== 'vue') return + + if (node.body.type === 'BlockStatement') { + const returnStatement = node.body.body.find( + (node) => node.type === 'ReturnStatement', + ) + if ( + returnStatement && + returnStatement.argument && + !( + returnStatement.argument?.type === 'ArrowFunctionExpression' || + returnStatement.argument?.type === 'FunctionExpression' + ) + ) { + s.appendRight( + returnStatement.argument.extra?.parenthesized + ? (returnStatement.argument.extra.parenStart as number) + : returnStatement.argument.start!, + '() => ', + ) + } + } else { + s.appendRight( + node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start!, + '() => ', + ) + } } diff --git a/packages/jsx-macros/src/core/setup-fc/restructure.ts b/packages/jsx-macros/src/core/setup-fc/restructure.ts index 423a7ee05..fbafebebf 100644 --- a/packages/jsx-macros/src/core/setup-fc/restructure.ts +++ b/packages/jsx-macros/src/core/setup-fc/restructure.ts @@ -6,6 +6,7 @@ import { import { walkIdentifiers } from '@vue/compiler-core' import { withDefaultsHelperId } from '../helper' import type { FunctionalNode } from '..' +import { prependFunctionalNode } from '.' import type { Node } from '@babel/types' type Prop = { @@ -92,25 +93,6 @@ function getProps( return props.length ? props : undefined } -export function prependFunctionalNode( - node: FunctionalNode, - s: MagicString, - result: string, -): void { - const isBlockStatement = node.body.type === 'BlockStatement' - const start = node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start! - s.prependRight( - start + (isBlockStatement ? 1 : 0), - `${result};${!isBlockStatement ? 'return ' : ''}`, - ) - if (!isBlockStatement) { - s.prependLeft(start, '{') - s.prependRight(node.end! + 1, '}') - } -} - export function restructure( s: MagicString, node: FunctionalNode, @@ -137,23 +119,14 @@ export function restructure( if (propList.length) { const defaultValues: Record = {} + const rests = [] for (const prop of propList) { if (prop.defaultValue) { const basePath = prop.path.split(/\.|\[/)[0] ;(defaultValues[basePath] ??= []).push(prop) } if (prop.isRest) { - const createPropsRestProxy = importHelperFn( - s, - 0, - 'createPropsRestProxy', - 'vue', - ) - prependFunctionalNode( - node, - s, - `\nconst ${prop.name} = ${createPropsRestProxy}(${prop.path}, [${prop.value}])`, - ) + rests.push(prop) } } for (const [path, values] of Object.entries(defaultValues)) { @@ -179,6 +152,20 @@ export function restructure( ) } + for (const prop of rests) { + const createPropsRestProxy = importHelperFn( + s, + 0, + 'createPropsRestProxy', + 'vue', + ) + prependFunctionalNode( + node, + s, + `\nconst ${prop.name} = ${createPropsRestProxy}(${prop.path}, [${prop.value}])`, + ) + } + walkIdentifiers( node.body, (id, parent, __, ___, isLocal) => { diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 25734e542..35a34de01 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -46,25 +46,22 @@ export default function (__MACROS_props) { exports[`fixtures > ./fixtures/setup-fc.tsx 1`] = ` " +import { defineComponent as __MACROS_defineComponent } from "vue"; import { useAttrs as __MACROS_useAttrs } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = defineComponent(() => { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent(() => { const __MACROS_props = __MACROS_useAttrs(); const foo = __MACROS_useModel(__MACROS_props, 'foo') - return () => { - return
{[foo.value, __MACROS_props.bar]}
- } + return () =>
{[foo.value, __MACROS_props.bar]}
}) const SetupComp = defineSetupComponent(() => { const __MACROS_props = __MACROS_useAttrs(); - return () => { - return
{__MACROS_props.foo}
- } + return () =>
{__MACROS_props.foo}
}) const SetupCompType: SetupFC = () => { const __MACROS_props = __MACROS_useAttrs(); - return
{__MACROS_props.foo}
+ return () =>
{__MACROS_props.foo}
} " `; @@ -114,20 +111,17 @@ export default function (__MACROS_props) { exports[`react fixtures > ./fixtures/setup-fc.tsx 1`] = ` " +import { defineComponent as __MACROS_defineComponent } from "vue"; import { useAttrs as __MACROS_useAttrs } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = defineComponent(() => { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent(() => { const __MACROS_props = __MACROS_useAttrs(); const foo = __MACROS_useModel(__MACROS_props, 'foo') - return () => { - return
{[foo.value, __MACROS_props.bar]}
- } + return
{[foo.value, __MACROS_props.bar]}
}) const SetupComp = defineSetupComponent(() => { const __MACROS_props = __MACROS_useAttrs(); - return () => { - return
{__MACROS_props.foo}
- } + return
{__MACROS_props.foo}
}) const SetupCompType: SetupFC = () => { diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap index b742adecd..b68cdc42e 100644 --- a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap @@ -17,10 +17,10 @@ exports[`transform > reconstruct arrowFunctionExpression 1`] = ` exports[`transform > reconstruct default-prop 1`] = ` " -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; -import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults";function App(__MACROS_props, __MACROS_props1){ -const __MACROS_defaults_props1 = __MACROS_createDefaultPropsProxy(__MACROS_props1, {'.foo': 'foo'}); +import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props, __MACROS_props1){ const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.foo': 'bar'}); +const __MACROS_defaults_props1 = __MACROS_createDefaultPropsProxy(__MACROS_props1, {'.foo': 'foo'}); const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'baz']); return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.baz, rest, __MACROS_defaults_props1.foo]} }" @@ -28,8 +28,8 @@ const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'baz exports[`transform > reconstruct rest-prop 1`] = ` " -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; -import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults";function App(__MACROS_props){ +import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props){ const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 1}); const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'bar']); return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.bar, rest]} diff --git a/packages/jsx-macros/tests/fixtures/setup-fc.tsx b/packages/jsx-macros/tests/fixtures/setup-fc.tsx index dcadde0dd..233ee2a47 100644 --- a/packages/jsx-macros/tests/fixtures/setup-fc.tsx +++ b/packages/jsx-macros/tests/fixtures/setup-fc.tsx @@ -1,14 +1,10 @@ const Comp = defineComponent(({ bar }: { bar: string }) => { const foo = defineModel('foo') - return () => { - return
{[foo.value, bar]}
- } + return
{[foo.value, bar]}
}) const SetupComp = defineSetupComponent(({ foo }: { foo: string }) => { - return () => { - return
{foo}
- } + return
{foo}
}) const SetupCompType: SetupFC = ({ foo }: { foo: string }) => { diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 457b1279a..49268e6f6 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -265,11 +265,37 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) } - if ( - map.setupFC && - (root.parameters.length || Object.keys(map).length > 1) - ) { + if (map.setupFC) { replaceSourceRange(codes, source, map.setupFC.start, map.setupFC.end) + + if (ts.isStatement(root.body)) { + ts.forEachChild(root.body, (node) => { + if ( + ts.isReturnStatement(node) && + node.expression && + !( + ts.isArrowFunction(node.expression) || + ts.isFunctionExpression(node.expression) + ) + ) { + replaceSourceRange( + codes, + source, + getStart(node.expression, options), + getStart(node.expression, options), + `() =>`, + ) + } + }) + } else { + replaceSourceRange( + codes, + source, + getStart(root.body, options), + getStart(root.body, options), + `() =>`, + ) + } } ts.forEachChild(root.body, (node) => { @@ -302,9 +328,8 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) { codes.push( ` -declare function defineSlots>(slots?: T): T -declare const defineExpose: typeof import('vue').defineExpose; -declare const defineModel: typeof import('vue').defineModel; +import { defineComponent, defineModel, defineExpose } from 'vue'; +declare function defineSlots>(slots?: T): T; declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, ) From 120d089b96369ebf42aa59928c572b7617b7533e Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 23 Sep 2024 23:33:12 +0800 Subject: [PATCH 023/156] fix: type --- packages/volar/src/jsx-macros.ts | 71 +++++++++++--------------------- 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 49268e6f6..b6ea81702 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -13,10 +13,8 @@ type RootMap = Map< defineModel?: string[] defineSlots?: string defineExpose?: string - setupFC?: { - start: number - end: number - } + isComponent?: true + isSetupFC?: true } > @@ -113,9 +111,14 @@ function getRootMap( getText(parents[2].type, options) === 'SetupFC' ) { if (!rootMap.has(root)) rootMap.set(root, {}) - rootMap.get(root)!.setupFC = { - start: parents[2].name.end, - end: parents[2].type.end, + if (!rootMap.get(root)!.isSetupFC) { + rootMap.get(root)!.isSetupFC = true + replaceSourceRange( + codes, + source, + parents[2].name.end, + parents[2].type.end, + ) } } if ( @@ -127,9 +130,16 @@ function getRootMap( ) ) { if (!rootMap.has(root)) rootMap.set(root, {}) - rootMap.get(root)!.setupFC = { - start: getStart(parents[2].expression, options), - end: parents[2].expression.end, + if (!rootMap.get(root)!.isComponent) { + rootMap.get(root)!.isComponent = true + + replaceSourceRange( + codes, + source, + getStart(parents[2], options), + getStart(parents[2], options), + HELPER_PREFIX, + ) } } @@ -212,7 +222,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) if (asyncModifier) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as __VLS_MaybeReturnType['render']> & { __ctx: Awaited['render'] & { __ctx: Awaited }` @@ -265,39 +275,6 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) } - if (map.setupFC) { - replaceSourceRange(codes, source, map.setupFC.start, map.setupFC.end) - - if (ts.isStatement(root.body)) { - ts.forEachChild(root.body, (node) => { - if ( - ts.isReturnStatement(node) && - node.expression && - !( - ts.isArrowFunction(node.expression) || - ts.isFunctionExpression(node.expression) - ) - ) { - replaceSourceRange( - codes, - source, - getStart(node.expression, options), - getStart(node.expression, options), - `() =>`, - ) - } - }) - } else { - replaceSourceRange( - codes, - source, - getStart(root.body, options), - getStart(root.body, options), - `() =>`, - ) - } - } - ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { replaceSourceRange( @@ -324,12 +301,14 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { if ( rootMap.size && - !codes.toString().includes(`declare function ${HELPER_PREFIX}defineSlots`) + !codes.toString().includes(`declare function defineSlots`) ) { codes.push( ` -import { defineComponent, defineModel, defineExpose } from 'vue'; +const { defineModel, defineExpose } = await import('vue') declare function defineSlots>(slots?: T): T; +declare function ${HELPER_PREFIX}defineComponent any)>(setup: T): T +declare function ${HELPER_PREFIX}defineSetupComponent any)>(setup: T): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, ) From 571307ece05d04906d4e5f389684e2318c5a1012 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 24 Sep 2024 09:46:20 +0800 Subject: [PATCH 024/156] feat: support default props type --- packages/volar/src/jsx-macros.ts | 44 +++++++++++++++++--------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index b6ea81702..c87f42473 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -222,41 +222,30 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) if (asyncModifier) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as Awaited['render'] & { __ctx: Awaited>['render'] & { __ctx: Awaited }` + }setup>> }` + const propsType = root.parameters[0]?.type + ? String(getText(root.parameters[0].type, options)) + : '{}' + const params = `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType}, ${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(` if (ts.isArrowFunction(root)) { replaceSourceRange( codes, source, getStart(root.parameters, options), getStart(root.parameters, options), - `${HELPER_PREFIX}props: `, - root.parameters[0]?.type - ? `${getText(root.parameters[0].type, options)} & ` - : '', - `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, - ) - replaceSourceRange( - codes, - source, - root.end, - root.end, - `)({} as any)) => `, - result, + params, ) + replaceSourceRange(codes, source, root.end, root.end, `)) => `, result) } else { replaceSourceRange( codes, source, root.parameters.pos, root.parameters.pos, - `${HELPER_PREFIX}props: `, - root.parameters[0]?.type - ? `${getText(root.parameters[0].type, options)} & ` - : '', - `Awaited['props'], ${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, + params, ) replaceSourceRange( codes, @@ -277,12 +266,25 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { + const defaultProps = + root.parameters[0] && + !root.parameters[0].type && + ts.isObjectBindingPattern(root.parameters[0].name) + ? root.parameters[0].name.elements + .map((element) => + ts.isIdentifier(element.name) + ? `${element.name.text}${element.initializer ? '?:' : ':'} typeof ${element.name.text}` + : '', + ) + .filter(Boolean) + .join(', ') + : '' replaceSourceRange( codes, source, getStart(node, options), getStart(node.expression, options), - `return {\nprops: {} as `, + `return {\nprops: {} as {${defaultProps}} & `, map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', From cc13970755b9bef4c38e6d6ec190ec40616443b5 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 27 Sep 2024 22:05:33 +0800 Subject: [PATCH 025/156] feat: add defineComponent --- packages/jsx-macros/package.json | 1 + packages/jsx-macros/src/api.ts | 2 +- .../src/core/define-component/index.ts | 130 ++++++++++++++++++ .../restructure.ts | 28 +++- packages/jsx-macros/src/core/define-model.ts | 6 +- .../jsx-macros/src/core/helper/use-model.ts | 87 +++++++++--- .../src/core/helper/with-defaults.ts | 53 ++++--- packages/jsx-macros/src/core/index.ts | 50 +++---- .../jsx-macros/src/core/setup-fc/index.ts | 74 ---------- .../tests/__snapshots__/fixtures.test.ts.snap | 68 ++++----- .../tests/fixtures/define-component.tsx | 9 ++ .../jsx-macros/tests/fixtures/setup-fc.tsx | 12 -- packages/macros/src/index.ts | 2 +- packages/volar/src/jsx-macros.ts | 51 +++---- 14 files changed, 339 insertions(+), 234 deletions(-) create mode 100644 packages/jsx-macros/src/core/define-component/index.ts rename packages/jsx-macros/src/core/{setup-fc => define-component}/restructure.ts (89%) delete mode 100644 packages/jsx-macros/src/core/setup-fc/index.ts create mode 100644 packages/jsx-macros/tests/fixtures/define-component.tsx delete mode 100644 packages/jsx-macros/tests/fixtures/setup-fc.tsx diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 492d2d2d7..09ddc5cdf 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -139,6 +139,7 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue/compiler-core": "catalog:", + "@vue/shared": "catalog:", "unplugin": "catalog:" }, "devDependencies": { diff --git a/packages/jsx-macros/src/api.ts b/packages/jsx-macros/src/api.ts index 03e8106c0..163360c76 100644 --- a/packages/jsx-macros/src/api.ts +++ b/packages/jsx-macros/src/api.ts @@ -1,3 +1,3 @@ export * from './core' -export { restructure } from './core/setup-fc/restructure' +export { restructure } from './core/define-component/restructure' export { createDefaultPropsProxy } from './core/helper/with-defaults' diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts new file mode 100644 index 000000000..99cbd745e --- /dev/null +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -0,0 +1,130 @@ +import { + HELPER_PREFIX, + importHelperFn, + type MagicStringAST, +} from '@vue-macros/common' +import { walkIdentifiers } from '@vue/compiler-core' +import { camelize } from 'vue' +import type { FunctionalNode, RootMapValue } from '..' +import { restructure } from './restructure' + +function getWalkedIds(root: FunctionalNode, propsName: string) { + const walkedIds = new Set() + walkIdentifiers( + root.body, + (id, parent) => { + if ( + id.name === propsName && + (parent?.type === 'MemberExpression' || + parent?.type === 'OptionalMemberExpression') + ) { + walkedIds.add( + parent.property.type === 'Identifier' + ? `'${parent.property.name}'` + : parent.property.type === 'StringLiteral' + ? parent.property.value + : '', + ) + } + }, + false, + ) + return walkedIds +} + +export function transformDefineComponent( + root: FunctionalNode, + propsName: string, + map: RootMapValue, + s: MagicStringAST, + lib: string, +): void { + if (!map.defineComponent) return + s.overwriteNode( + map.defineComponent.callee, + importHelperFn(s, 0, 'defineComponent', 'vue'), + ) + + let propsSet = new Set() + if (root.params[0]) { + if (root.params[0].type === 'Identifier') { + propsSet = getWalkedIds(root, propsName) + } else { + const props = restructure(s, root) + for (const prop of props) { + if (prop.path === `${HELPER_PREFIX}props`) { + if (prop.isRest) { + getWalkedIds(root, prop.name).forEach((id) => propsSet.add(id)) + } else { + propsSet.add(`'${prop.name}'`) + } + } + } + } + } + + for (const prop of map.defineModel || []) { + const name = camelize( + prop.arguments[0].type === 'StringLiteral' + ? prop.arguments[0].value + : 'modelValue', + ) + propsSet.add(`'${name}'`) + propsSet.add(`'onUpdate:${name}'`) + } + + const result = Array.from(propsSet).filter(Boolean).join(', ') + if (result) { + const argument = map.defineComponent.arguments[1] + if (!argument) { + s.appendRight(root.end!, `, { props: [ ${result} ] }`) + } else if ( + argument.type === 'ObjectExpression' && + !argument.properties?.find( + (prop) => + prop.type === 'ObjectProperty' && + prop.key.type === 'Identifier' && + prop.key.name === 'props', + ) + ) { + s.appendLeft( + argument.end! - 1, + `${ + !argument.properties.length || argument.extra?.trailingComma + ? '' + : ',' + } props: [ ${result} ]`, + ) + } + } + + if (lib === 'vue') { + if (root.body.type === 'BlockStatement') { + const returnStatement = root.body.body.find( + (node) => node.type === 'ReturnStatement', + ) + if ( + returnStatement && + returnStatement.argument && + !( + returnStatement.argument?.type === 'ArrowFunctionExpression' || + returnStatement.argument?.type === 'FunctionExpression' + ) + ) { + s.appendRight( + returnStatement.argument.extra?.parenthesized + ? (returnStatement.argument.extra.parenStart as number) + : returnStatement.argument.start!, + '() => ', + ) + } + } else { + s.appendRight( + root.body.extra?.parenthesized + ? (root.body.extra.parenStart as number) + : root.body.start!, + '() => ', + ) + } + } +} diff --git a/packages/jsx-macros/src/core/setup-fc/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts similarity index 89% rename from packages/jsx-macros/src/core/setup-fc/restructure.ts rename to packages/jsx-macros/src/core/define-component/restructure.ts index fbafebebf..6c527256c 100644 --- a/packages/jsx-macros/src/core/setup-fc/restructure.ts +++ b/packages/jsx-macros/src/core/define-component/restructure.ts @@ -6,7 +6,6 @@ import { import { walkIdentifiers } from '@vue/compiler-core' import { withDefaultsHelperId } from '../helper' import type { FunctionalNode } from '..' -import { prependFunctionalNode } from '.' import type { Node } from '@babel/types' type Prop = { @@ -93,11 +92,30 @@ function getProps( return props.length ? props : undefined } +export function prependFunctionalNode( + node: FunctionalNode, + s: MagicString, + result: string, +): void { + const isBlockStatement = node.body.type === 'BlockStatement' + const start = node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start! + s.appendRight( + start + (isBlockStatement ? 1 : 0), + `${result};${!isBlockStatement ? 'return ' : ''}`, + ) + if (!isBlockStatement) { + s.appendLeft(start, '{') + s.appendRight(node.end!, '}') + } +} + export function restructure( s: MagicString, node: FunctionalNode, withDefaultsFrom: string = withDefaultsHelperId, -): void { +): Prop[] { let index = 0 const propList: Prop[] = [] for (const param of node.params) { @@ -168,9 +186,9 @@ export function restructure( walkIdentifiers( node.body, - (id, parent, __, ___, isLocal) => { + (id, parent) => { const prop = propList.find((i) => i.name === id.name) - if (!isLocal && prop && !prop.isRest) { + if (prop && !prop.isRest) { s.overwrite( id.start!, id.end!, @@ -185,4 +203,6 @@ export function restructure( false, ) } + + return propList } diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index 56e1ce339..12ff006c3 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -13,6 +13,10 @@ export function transformDefineModel( ) s.appendRight( node.arguments[0]?.start || node.end! - 1, - `${propsName}, ${node.arguments.length && node.arguments[0].type !== 'StringLiteral' ? `'modelValue',` : ''}`, + `${propsName}, ${ + node.arguments.length && node.arguments[0].type !== 'StringLiteral' + ? `'modelValue',` + : '' + }`, ) } diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts index 629a44e83..be5e133c9 100644 --- a/packages/jsx-macros/src/core/helper/use-model.ts +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -1,4 +1,7 @@ -import { camelize, type ModelRef } from 'vue' +// Copy from: https://github.com/vuejs/core/blob/main/packages/runtime-core/src/helpers/useModel.ts + +import { camelize, hasChanged, hyphenate } from '@vue/shared' +import { customRef, watchSyncEffect, type ModelRef } from 'vue' type DefineModelOptions> = { default?: any @@ -15,18 +18,68 @@ export function useModel( name: string = 'modelValue', options: DefineModelOptions = {}, ): any { - name = camelize(name) + const camelizedName = camelize(name) + const hyphenatedName = hyphenate(name) const modifiers = getModelModifiers(props, name) - const res = { - get value() { - const result = props[name] ?? options?.default - return options?.get ? options.get(result) : result - }, - set value(v) { - props[`onUpdate:${name}`]?.(v) - }, - __v_isRef: true, - } + + const res = customRef((track, trigger) => { + let localValue: any = options?.default + let prevSetValue: any + let prevEmittedValue: any + + watchSyncEffect(() => { + const propValue = props[name] + if (hasChanged(localValue, propValue)) { + localValue = propValue + trigger() + } + }) + + return { + get() { + track() + return options.get ? options.get(localValue) : localValue + }, + + set(value) { + if (!hasChanged(value, localValue)) { + return + } + if ( + !( + // check if parent has passed v-model + ( + (name in props || + camelizedName in props || + hyphenatedName in props) && + (`onUpdate:${name}` in props || + `onUpdate:${camelizedName}` in props || + `onUpdate:${hyphenatedName}` in props) + ) + ) + ) { + // no v-model, local update + localValue = value + trigger() + } + const emittedValue = options.set ? options.set(value) : value + props[`onUpdate:${name}`]?.(emittedValue) + // #10279: if the local value is converted via a setter but the value + // emitted to parent was the same, the parent will not trigger any + // updates and there will be no prop sync. However the local input state + // may be out of sync, so we need to force an update here. + if ( + value !== emittedValue && + value !== prevSetValue && + emittedValue === prevEmittedValue + ) { + trigger() + } + prevSetValue = value + prevEmittedValue = emittedValue + }, + } + }) // @ts-expect-error res[Symbol.iterator] = () => { @@ -44,11 +97,13 @@ export function useModel( return res } -export const getModelModifiers = ( +const getModelModifiers = ( props: Record, modelName: string, -): Record | undefined => { - return modelName === 'modelValue' +): Record | undefined => { + return modelName === 'modelValue' || modelName === 'model-value' ? props.modelModifiers - : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] + : props[`${modelName}Modifiers`] || + props[`${camelize(modelName)}Modifiers`] || + props[`${hyphenate(modelName)}Modifiers`] } diff --git a/packages/jsx-macros/src/core/helper/with-defaults.ts b/packages/jsx-macros/src/core/helper/with-defaults.ts index 38dacad14..e2b2e1a3a 100644 --- a/packages/jsx-macros/src/core/helper/with-defaults.ts +++ b/packages/jsx-macros/src/core/helper/with-defaults.ts @@ -1,21 +1,40 @@ -function getByPath(obj: any, path: string[] = []) { - while (path.length) { - obj = obj[path.shift()!] +function resolveDefaultProps(paths: Record): any { + const result: any = {} + + for (const path of Object.keys(paths)) { + const segments = path.split(/[?.[\]]/).filter(Boolean) + let current = result + + for (let i = 0; i < segments.length; i++) { + const segment = segments[i] + if (i === segments.length - 1) { + current[segment] = paths[path] + } else { + if (!current[segment]) { + current[segment] = Number.isNaN(Number(segments[i + 1])) ? {} : [] + } + current = current[segment] + } + } } - return obj + + return result } -export function createDefaultPropsProxy( - props: any, - defaults?: any, -): Record { - const ret: Record = {} - for (const key of Object.keys(defaults)) { - const path = key.split(/[.?[\]]/).filter(Boolean) - Object.defineProperty(ret, key, { - enumerable: true, - get: () => getByPath(props, path) ?? getByPath(defaults, path), - }) - } - return ret +function defaultPropsProxy(props: any, defaultProps: any): any { + return new Proxy(props, { + get(target, prop) { + const value = + target[prop] === undefined ? defaultProps?.[prop] : target?.[prop] + if (typeof value === 'object' && value !== null) { + return defaultPropsProxy(value, defaultProps[prop]) + } + return value + }, + }) +} + +export function createDefaultPropsProxy(props: any, defaultProps: any): any { + const resolvedDefaultProps = resolveDefaultProps(defaultProps) + return defaultPropsProxy(props, resolvedDefaultProps) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 9c810ceff..bf9d1c606 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -3,17 +3,16 @@ import { generateTransform, getLang, HELPER_PREFIX, - importHelperFn, isCallOf, MagicStringAST, walkAST, type CodeTransform, } from '@vue-macros/common' import type { OptionsResolved } from '..' +import { transformDefineComponent } from './define-component' import { transformDefineExpose } from './define-expose' import { transformDefineModel } from './define-model' import { transformDefineSlots } from './define-slots' -import { transformSetupFC } from './setup-fc' import type { ArrowFunctionExpression, CallExpression, @@ -37,17 +36,16 @@ function isMacro(node?: Node | null): node is CallExpression { ) } +export type RootMapValue = { + defineComponent?: CallExpression + defineModel?: CallExpression[] + defineSlots?: CallExpression + defineExpose?: CallExpression +} + function getRootMap(s: MagicStringAST, id: string) { const parents: (Node | undefined | null)[] = [] - const rootMap: Map< - FunctionalNode, - { - isSetupFC?: boolean - defineModel?: CallExpression[] - defineSlots?: CallExpression - defineExpose?: CallExpression - } - > = new Map() + const rootMap = new Map() walkAST(babelParse(s.original, getLang(id)), { enter(node, parent) { parents.unshift(parent) @@ -60,30 +58,13 @@ function getRootMap(s: MagicStringAST, id: string) { : undefined if (!root) return - if ( - root.type !== 'FunctionDeclaration' && - parents[2]?.type === 'VariableDeclarator' && - parents[2].id.type === 'Identifier' && - parents[2].id.typeAnnotation?.type === 'TSTypeAnnotation' && - s.sliceNode(parents[2].id.typeAnnotation.typeAnnotation) === 'SetupFC' - ) { - if (!rootMap.has(root)) rootMap.set(root, {}) - rootMap.get(root)!.isSetupFC = true - } if ( parents[2]?.type === 'CallExpression' && - ['defineComponent', 'defineSetupComponent'].includes( - s.sliceNode(parents[2].callee), - ) + s.sliceNode(parents[2].callee) === 'defineComponent' ) { if (!rootMap.has(root)) rootMap.set(root, {}) - if (rootMap.get(root)!.isSetupFC) return - rootMap.get(root)!.isSetupFC = true - if (s.sliceNode(parents[2].callee) === 'defineComponent') { - s.overwriteNode( - parents[2].callee, - importHelperFn(s, 0, 'defineComponent', 'vue'), - ) + if (!rootMap.get(root)!.defineComponent) { + rootMap.get(root)!.defineComponent = parents[2] } } @@ -134,9 +115,7 @@ export function transformJsxMacros( for (const [root, map] of rootMap) { let propsName = `${HELPER_PREFIX}props` - if (map.isSetupFC) { - transformSetupFC(root, s, options.lib) - } else if (root.params[0]) { + if (root.params[0]) { if (root.params[0].type === 'Identifier') { propsName = root.params[0].name } else if (root.params[0].type === 'ObjectPattern') { @@ -159,6 +138,9 @@ export function transformJsxMacros( s.appendRight(getParamsStart(root, s.original), propsName) } + if (map.defineComponent) { + transformDefineComponent(root, propsName, map, s, options.lib) + } if (map.defineModel?.length) { map.defineModel.forEach((node) => { transformDefineModel(node, propsName, s) diff --git a/packages/jsx-macros/src/core/setup-fc/index.ts b/packages/jsx-macros/src/core/setup-fc/index.ts deleted file mode 100644 index 0cc0e9fb7..000000000 --- a/packages/jsx-macros/src/core/setup-fc/index.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - HELPER_PREFIX, - importHelperFn, - type MagicString, - type MagicStringAST, -} from '@vue-macros/common' -import type { FunctionalNode } from '..' -import { restructure } from './restructure' - -export function prependFunctionalNode( - node: FunctionalNode, - s: MagicString, - result: string, -): void { - const isBlockStatement = node.body.type === 'BlockStatement' - const start = node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start! - s.appendRight( - start + (isBlockStatement ? 1 : 0), - `${result};${!isBlockStatement ? 'return ' : ''}`, - ) - if (!isBlockStatement) { - s.appendLeft(start, '{') - s.appendRight(node.end!, '}') - } -} - -export function transformSetupFC( - node: FunctionalNode, - s: MagicStringAST, - lib: string, -): void { - const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') - prependFunctionalNode( - node, - s, - `\nconst ${HELPER_PREFIX}props = ${useAttrs}()`, - ) - - restructure(s, node) - - if (node.params[0]) s.removeNode(node.params[0]) - - if (lib !== 'vue') return - - if (node.body.type === 'BlockStatement') { - const returnStatement = node.body.body.find( - (node) => node.type === 'ReturnStatement', - ) - if ( - returnStatement && - returnStatement.argument && - !( - returnStatement.argument?.type === 'ArrowFunctionExpression' || - returnStatement.argument?.type === 'FunctionExpression' - ) - ) { - s.appendRight( - returnStatement.argument.extra?.parenthesized - ? (returnStatement.argument.extra.parenStart as number) - : returnStatement.argument.start!, - '() => ', - ) - } - } else { - s.appendRight( - node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start!, - '() => ', - ) - } -} diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 35a34de01..b459d31ce 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -1,5 +1,22 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` +" +import { defineComponent as __MACROS_defineComponent } from "vue"; +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent((__MACROS_props) => { +const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); + const foo = __MACROS_useModel(props, 'foo') + return () =>
{[foo.value, __MACROS_props.bar, props.baz]}
+}, { inheritAttrs: false, props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}) + +const Comp1 = __MACROS_defineComponent((props) => { + const foo = __MACROS_useModel(props, 'foo') + return () =>
{[foo.value, props['bar']]}
+}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) +" +`; + exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; @@ -44,25 +61,20 @@ export default function (__MACROS_props) { " `; -exports[`fixtures > ./fixtures/setup-fc.tsx 1`] = ` +exports[`react fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; -import { useAttrs as __MACROS_useAttrs } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent(() => { -const __MACROS_props = __MACROS_useAttrs(); - const foo = __MACROS_useModel(__MACROS_props, 'foo') - return () =>
{[foo.value, __MACROS_props.bar]}
-}) - -const SetupComp = defineSetupComponent(() => { -const __MACROS_props = __MACROS_useAttrs(); - return () =>
{__MACROS_props.foo}
-}) - -const SetupCompType: SetupFC = () => { -const __MACROS_props = __MACROS_useAttrs(); - return () =>
{__MACROS_props.foo}
-} +import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent((__MACROS_props) => { +const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); + const foo = __MACROS_useModel(props, 'foo') + return
{[foo.value, __MACROS_props.bar, props.baz]}
+}, { inheritAttrs: false, props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}) + +const Comp1 = __MACROS_defineComponent((props) => { + const foo = __MACROS_useModel(props, 'foo') + return
{[foo.value, props['bar']]}
+}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) " `; @@ -108,25 +120,3 @@ export default function (__MACROS_props) { } " `; - -exports[`react fixtures > ./fixtures/setup-fc.tsx 1`] = ` -" -import { defineComponent as __MACROS_defineComponent } from "vue"; -import { useAttrs as __MACROS_useAttrs } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent(() => { -const __MACROS_props = __MACROS_useAttrs(); - const foo = __MACROS_useModel(__MACROS_props, 'foo') - return
{[foo.value, __MACROS_props.bar]}
-}) - -const SetupComp = defineSetupComponent(() => { -const __MACROS_props = __MACROS_useAttrs(); - return
{__MACROS_props.foo}
-}) - -const SetupCompType: SetupFC = () => { -const __MACROS_props = __MACROS_useAttrs(); - return
{__MACROS_props.foo}
-} -" -`; diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx new file mode 100644 index 000000000..466507f46 --- /dev/null +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -0,0 +1,9 @@ +const Comp = defineComponent(({ bar, ...props }) => { + const foo = defineModel('foo') + return
{[foo.value, bar, props.baz]}
+}, { inheritAttrs: false, }) + +const Comp1 = defineComponent((props) => { + const foo = defineModel('foo') + return
{[foo.value, props['bar']]}
+}) diff --git a/packages/jsx-macros/tests/fixtures/setup-fc.tsx b/packages/jsx-macros/tests/fixtures/setup-fc.tsx deleted file mode 100644 index 233ee2a47..000000000 --- a/packages/jsx-macros/tests/fixtures/setup-fc.tsx +++ /dev/null @@ -1,12 +0,0 @@ -const Comp = defineComponent(({ bar }: { bar: string }) => { - const foo = defineModel('foo') - return
{[foo.value, bar]}
-}) - -const SetupComp = defineSetupComponent(({ foo }: { foo: string }) => { - return
{foo}
-}) - -const SetupCompType: SetupFC = ({ foo }: { foo: string }) => { - return
{foo}
-} diff --git a/packages/macros/src/index.ts b/packages/macros/src/index.ts index 8ff1a5395..fa90bcbba 100644 --- a/packages/macros/src/index.ts +++ b/packages/macros/src/index.ts @@ -67,7 +67,6 @@ const plugin: UnpluginCombineInstance = ) const plugins: OptionsPlugin[] = [ - resolvePlugin(VueJsxMacros, framework, options.jsxMacros), resolvePlugin(VueSetupSFC, framework, options.setupSFC), setupComponentPlugins?.[0], resolvePlugin(VueSetupBlock, framework, options.setupBlock), @@ -131,6 +130,7 @@ const plugin: UnpluginCombineInstance = : []), options.plugins.vue, + resolvePlugin(VueJsxMacros, framework, options.jsxMacros), resolvePlugin(VueJsxDirective, framework, options.jsxDirective), options.plugins.vueJsx, resolvePlugin(VueDefineRender, framework, options.defineRender), diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index c87f42473..1b1f672a6 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -13,8 +13,7 @@ type RootMap = Map< defineModel?: string[] defineSlots?: string defineExpose?: string - isComponent?: true - isSetupFC?: true + defineComponent?: true } > @@ -104,35 +103,15 @@ function getRootMap( : undefined if (!root) return - if ( - parents[2] && - ts.isVariableDeclaration(parents[2]) && - parents[2].type && - getText(parents[2].type, options) === 'SetupFC' - ) { - if (!rootMap.has(root)) rootMap.set(root, {}) - if (!rootMap.get(root)!.isSetupFC) { - rootMap.get(root)!.isSetupFC = true - replaceSourceRange( - codes, - source, - parents[2].name.end, - parents[2].type.end, - ) - } - } if ( parents[2] && ts.isCallExpression(parents[2]) && !parents[2].typeArguments && - ['defineComponent', 'defineSetupComponent'].includes( - getText(parents[2].expression, options), - ) + getText(parents[2].expression, options) === 'defineComponent' ) { if (!rootMap.has(root)) rootMap.set(root, {}) - if (!rootMap.get(root)!.isComponent) { - rootMap.get(root)!.isComponent = true - + if (!rootMap.get(root)!.defineComponent) { + rootMap.get(root)!.defineComponent = true replaceSourceRange( codes, source, @@ -222,7 +201,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) if (asyncModifier) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as Awaited>['render'] & { __ctx: Awaited>['render']> & { __ctx: Awaited> }` @@ -259,7 +238,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { source, root.body.end - 1, root.body.end - 1, - `})({} as any)){ return `, + `})){ return `, result, ) } @@ -271,11 +250,14 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { !root.parameters[0].type && ts.isObjectBindingPattern(root.parameters[0].name) ? root.parameters[0].name.elements - .map((element) => - ts.isIdentifier(element.name) - ? `${element.name.text}${element.initializer ? '?:' : ':'} typeof ${element.name.text}` - : '', - ) + .map((element) => { + const isRequired = element.initializer + ? ts.isNonNullExpression(element.initializer) + : false + return ts.isIdentifier(element.name) + ? `${element.name.text}${isRequired ? ':' : '?:'} typeof ${element.name.text}` + : '' + }) .filter(Boolean) .join(', ') : '' @@ -284,7 +266,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { source, getStart(node, options), getStart(node.expression, options), - `return {\nprops: {} as {${defaultProps}} & `, + ` return {\nprops: {} as {${defaultProps}} & `, map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', @@ -309,8 +291,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ` const { defineModel, defineExpose } = await import('vue') declare function defineSlots>(slots?: T): T; -declare function ${HELPER_PREFIX}defineComponent any)>(setup: T): T -declare function ${HELPER_PREFIX}defineSetupComponent any)>(setup: T): T +declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, ) From 07b00b7ab4d46eac5a0ee18e996d95117f6c89a6 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 27 Sep 2024 22:50:40 +0800 Subject: [PATCH 026/156] fix: format --- .../src/core/define-component/index.ts | 2 +- .../tests/__snapshots__/fixtures.test.ts.snap | 30 ++++++++++++------- .../tests/fixtures/define-component.tsx | 15 ++++++---- .../vue3/src/examples/jsx-macros/comp.tsx | 4 +-- .../src/examples/setup-component/index.tsx | 6 +--- .../examples/setup-component/type-decl.tsx | 14 ++------- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 99cbd745e..5e1807913 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -4,7 +4,7 @@ import { type MagicStringAST, } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' -import { camelize } from 'vue' +import { camelize } from '@vue/shared' import type { FunctionalNode, RootMapValue } from '..' import { restructure } from './restructure' diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index b459d31ce..afd267a8c 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -4,13 +4,18 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent((__MACROS_props) => { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";import { defineComponent } from 'vue' + +const Comp = __MACROS_defineComponent( + (__MACROS_props) => { const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); - const foo = __MACROS_useModel(props, 'foo') - return () =>
{[foo.value, __MACROS_props.bar, props.baz]}
-}, { inheritAttrs: false, props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}) + const foo = __MACROS_useModel(props, 'foo') + return () =>
{[foo.value, __MACROS_props.bar, props.baz]}
+ }, + { inheritAttrs: false , props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}, +) -const Comp1 = __MACROS_defineComponent((props) => { +const Comp1 = __MACROS_defineComponent((props: {bar: 'bar'}) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar']]}
}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) @@ -65,13 +70,18 @@ exports[`react fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";const Comp = __MACROS_defineComponent((__MACROS_props) => { +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";import { defineComponent } from 'vue' + +const Comp = __MACROS_defineComponent( + (__MACROS_props) => { const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); - const foo = __MACROS_useModel(props, 'foo') - return
{[foo.value, __MACROS_props.bar, props.baz]}
-}, { inheritAttrs: false, props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}) + const foo = __MACROS_useModel(props, 'foo') + return
{[foo.value, __MACROS_props.bar, props.baz]}
+ }, + { inheritAttrs: false , props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}, +) -const Comp1 = __MACROS_defineComponent((props) => { +const Comp1 = __MACROS_defineComponent((props: {bar: 'bar'}) => { const foo = __MACROS_useModel(props, 'foo') return
{[foo.value, props['bar']]}
}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 466507f46..3b2929f6b 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -1,9 +1,14 @@ -const Comp = defineComponent(({ bar, ...props }) => { - const foo = defineModel('foo') - return
{[foo.value, bar, props.baz]}
-}, { inheritAttrs: false, }) +import { defineComponent } from 'vue' + +const Comp = defineComponent( + ({ bar, ...props }: {bar: 'bar', baz: 'baz'}) => { + const foo = defineModel('foo') + return
{[foo.value, bar, props.baz]}
+ }, + { inheritAttrs: false }, +) -const Comp1 = defineComponent((props) => { +const Comp1 = defineComponent((props: {bar: 'bar'}) => { const foo = defineModel('foo') return
{[foo.value, props['bar']]}
}) diff --git a/playground/vue3/src/examples/jsx-macros/comp.tsx b/playground/vue3/src/examples/jsx-macros/comp.tsx index e68d5f223..4cf572d64 100644 --- a/playground/vue3/src/examples/jsx-macros/comp.tsx +++ b/playground/vue3/src/examples/jsx-macros/comp.tsx @@ -1,6 +1,6 @@ import { watch } from 'vue' -export function Comp({ foo }: { foo: T }) { +export const Comp = defineComponent(function ({ foo }: { foo: T }) { const slots = defineSlots({ default: (props: { bar: string }) =>
{props.bar}
, }) @@ -34,4 +34,4 @@ export function Comp({ foo }: { foo: T }) {
) -} +}) diff --git a/playground/vue3/src/examples/setup-component/index.tsx b/playground/vue3/src/examples/setup-component/index.tsx index d7ce1f6c0..fb68acb11 100644 --- a/playground/vue3/src/examples/setup-component/index.tsx +++ b/playground/vue3/src/examples/setup-component/index.tsx @@ -1,15 +1,11 @@ -import { useRef } from 'unplugin-vue-macros/runtime' import Context from './context' import { SetupComponentTypeDecl } from './type-decl' export const SetupComponentFoo = defineSetupComponent(() => { const Ctx = Context() - const compRef = useRef() return () => ( <> - -
double: {Number(compRef.value?.double) * foo}
-
+ ) diff --git a/playground/vue3/src/examples/setup-component/type-decl.tsx b/playground/vue3/src/examples/setup-component/type-decl.tsx index 2d74315a7..62f0b39f4 100644 --- a/playground/vue3/src/examples/setup-component/type-decl.tsx +++ b/playground/vue3/src/examples/setup-component/type-decl.tsx @@ -3,24 +3,16 @@ import { foo } from './foo' console.log(foo) -const Comp: SetupFC = ({ foo }: { foo: number }) => {foo} - export const SetupComponentTypeDecl: SetupFC = () => { - const count = ref(1) + const count = ref(0) const double = computed(() => count.value * 2) - defineExpose({ double }) - const slots = defineSlots({ - default: Comp, - }) - const foo = ref(1) return () => (
Type Declaration - - count: - +
count: {count.value}
+
double: {double.value}
) } From 3af36d1dcda518312bf7980b122452ecd4554b93 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 27 Sep 2024 22:55:10 +0800 Subject: [PATCH 027/156] fix: format --- packages/jsx-macros/tests/fixtures/define-component.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 3b2929f6b..5922b76a4 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -1,14 +1,14 @@ import { defineComponent } from 'vue' const Comp = defineComponent( - ({ bar, ...props }: {bar: 'bar', baz: 'baz'}) => { + ({ bar, ...props }: { bar: 'bar'; baz: 'baz' }) => { const foo = defineModel('foo') return
{[foo.value, bar, props.baz]}
}, { inheritAttrs: false }, ) -const Comp1 = defineComponent((props: {bar: 'bar'}) => { +const Comp1 = defineComponent((props: { bar: 'bar' }) => { const foo = defineModel('foo') return
{[foo.value, props['bar']]}
}) From c90d9633402eab0d62f3127d26f7393362683db6 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 28 Sep 2024 00:12:39 +0800 Subject: [PATCH 028/156] feat: remove $ --- packages/jsx-macros/package.json | 5 -- packages/jsx-macros/src/core/index.ts | 11 +--- packages/jsx-macros/src/helpers.ts | 2 - packages/jsx-macros/src/index.ts | 2 +- .../tests/__snapshots__/fixtures.test.ts.snap | 57 +------------------ packages/jsx-macros/tests/fixtures.test.ts | 2 +- .../tests/fixtures/define-model.tsx | 2 +- packages/volar/src/jsx-macros.ts | 7 ++- 8 files changed, 12 insertions(+), 76 deletions(-) delete mode 100644 packages/jsx-macros/src/helpers.ts diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 09ddc5cdf..397f0749b 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -47,11 +47,6 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, - "./helpers": { - "dev": "./src/helpers.ts", - "require": "./dist/helpers.cjs", - "import": "./dist/helpers.js" - }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.cjs", diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index bf9d1c606..160cf506b 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -3,7 +3,6 @@ import { generateTransform, getLang, HELPER_PREFIX, - isCallOf, MagicStringAST, walkAST, type CodeTransform, @@ -27,7 +26,6 @@ export type FunctionalNode = | ArrowFunctionExpression function isMacro(node?: Node | null): node is CallExpression { - node = isCallOf(node, '$') ? node.arguments[0] : node return !!( node && node.type === 'CallExpression' && @@ -76,15 +74,10 @@ function getRootMap(s: MagicStringAST, id: string) { : undefined if (!isMacro(expression)) return if (!rootMap.has(root)) rootMap.set(root, {}) - const macro = - isCallOf(expression, '$') && - expression.arguments[0].type === 'CallExpression' - ? expression.arguments[0] - : expression - const macroName = s.sliceNode(macro.callee) + const macroName = s.sliceNode(expression.callee) if (macroName) { if (macroName === 'defineModel') - (rootMap.get(root)!.defineModel ??= []).push(macro) + (rootMap.get(root)!.defineModel ??= []).push(expression) else if (macroName === 'defineSlots' || macroName === 'defineExpose') rootMap.get(root)![macroName] = expression } diff --git a/packages/jsx-macros/src/helpers.ts b/packages/jsx-macros/src/helpers.ts deleted file mode 100644 index c68c820de..000000000 --- a/packages/jsx-macros/src/helpers.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { useExpose } from './core/helper/use-expose' -export { useModel } from './core/helper/use-model' diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 180a6c748..e1552a8f7 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -26,7 +26,7 @@ import { } from './core/helper' export type Options = BaseOptions & { - lib?: string + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' } export type OptionsResolved = MarkRequired< Options, diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index afd267a8c..3d2589142 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -15,7 +15,7 @@ const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); { inheritAttrs: false , props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}, ) -const Comp1 = __MACROS_defineComponent((props: {bar: 'bar'}) => { +const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar']]}
}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) @@ -42,7 +42,7 @@ import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model" } export default function (__MACROS_props) { - const foo = $(__MACROS_useModel(__MACROS_props, 'foo')) + const foo = __MACROS_useModel(__MACROS_props, 'foo') return
{foo}
} " @@ -66,28 +66,6 @@ export default function (__MACROS_props) { " `; -exports[`react fixtures > ./fixtures/define-component.tsx 1`] = ` -" -import { defineComponent as __MACROS_defineComponent } from "vue"; -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";import { defineComponent } from 'vue' - -const Comp = __MACROS_defineComponent( - (__MACROS_props) => { -const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); - const foo = __MACROS_useModel(props, 'foo') - return
{[foo.value, __MACROS_props.bar, props.baz]}
- }, - { inheritAttrs: false , props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}, -) - -const Comp1 = __MACROS_defineComponent((props: {bar: 'bar'}) => { - const foo = __MACROS_useModel(props, 'foo') - return
{[foo.value, props['bar']]}
-}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) -" -`; - exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { forwardRef as __MACROS_forwardRef } from "react"; @@ -99,34 +77,3 @@ import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";expo }) " `; - -exports[`react fixtures > ./fixtures/define-model.tsx 1`] = ` -" -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { - const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) - return
{foo.value}
-} - -export default function (__MACROS_props) { - const foo = $(__MACROS_useModel(__MACROS_props, 'foo')) - return
{foo}
-} -" -`; - -exports[`react fixtures > ./fixtures/define-slots.tsx 1`] = ` -"export const Comp = (__MACROS_props) => { - const slots = Object.assign<{ - default: () => any - }>({}, __MACROS_props.vSlots) - return
{slots.default()}
-} - -export default function (__MACROS_props) { - const slots = Object.assign({ - default: () =>
default
, - },__MACROS_props.vSlots) - return
{slots.default()}
-} -" -`; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index 63244e34c..4bf696646 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -19,7 +19,7 @@ describe('fixtures', async () => { describe('react fixtures', async () => { await testFixtures( - import.meta.glob('./fixtures/**/*.tsx', { + import.meta.glob('./fixtures/**/define-expose.tsx', { eager: true, as: 'raw', }), diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 13ff9885a..1861f4d4d 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -4,6 +4,6 @@ export const Comp = ({ bar }: { bar: string }) => { } export default function () { - const foo = $(defineModel('foo')) + const foo = defineModel('foo') return
{foo}
} diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 1b1f672a6..abef933f4 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -266,7 +266,9 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { source, getStart(node, options), getStart(node.expression, options), - ` return {\nprops: {} as {${defaultProps}} & `, + `return {\nprops: {} as `, + options.vueVersion ? `import('vue').PublicProps & ` : '', + `{${defaultProps}} & `, map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', @@ -289,8 +291,9 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) { codes.push( ` -const { defineModel, defineExpose } = await import('vue') +const { defineModel } = await import('vue') declare function defineSlots>(slots?: T): T; +declare function defineExpose = Record>(exposed?: Exposed): void; declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, From 42a810652037940ac4f752aed0c10768b444f057 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 28 Sep 2024 10:23:35 +0800 Subject: [PATCH 029/156] fix: mono --- packages/jsx-macros/package.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 397f0749b..5007eaecc 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,7 +1,7 @@ { "name": "@vue-macros/jsx-macros", "version": "0.0.0", - "packageManager": "pnpm@9.10.0", + "packageManager": "pnpm@9.11.0", "description": "jsx-macros feature from Vue Macros.", "type": "module", "keywords": [ @@ -97,10 +97,6 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, - "./helpers": { - "require": "./dist/helpers.cjs", - "import": "./dist/helpers.js" - }, "./rolldown": { "require": "./dist/rolldown.cjs", "import": "./dist/rolldown.js" From da6e129a1a49e49839ea5b52c2e4a8664fcea84d Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 28 Sep 2024 10:59:19 +0800 Subject: [PATCH 030/156] fix: version --- packages/volar/src/jsx-macros.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index abef933f4..6f4c82d72 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -305,12 +305,13 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { if (!options) return [] const filter = createFilter(options) + const { version: vueVersion } = options return { name: 'vue-macros-jsx-macros', version: 2.1, resolveEmbeddedCode(fileName, sfc, embeddedFile) { - if (!filter(fileName) || !['tsx'].includes(embeddedFile.lang)) return + if (!filter(fileName) || embeddedFile.lang !== 'tsx') return for (const source of ['script', 'scriptSetup'] as const) { if (!sfc[source]) continue @@ -319,6 +320,7 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { source, ts: ctx.modules.typescript, codes: embeddedFile.content, + vueVersion, } const rootMap = getRootMap(options, ctx.vueCompilerOptions) if (rootMap.size) transformJsxMacros(rootMap, options) From 75b72fb637577b12eb20edb7f83fb30661deabc9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 28 Sep 2024 11:45:59 +0800 Subject: [PATCH 031/156] feat: support reactivity expose --- packages/jsx-macros/src/core/helper/use-expose.ts | 3 ++- packages/volar/src/jsx-macros.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/jsx-macros/src/core/helper/use-expose.ts b/packages/jsx-macros/src/core/helper/use-expose.ts index e9633a73f..6cb28ef94 100644 --- a/packages/jsx-macros/src/core/helper/use-expose.ts +++ b/packages/jsx-macros/src/core/helper/use-expose.ts @@ -1,6 +1,7 @@ -export function useExpose(i: any, exposed = {}): void { +export function useExpose(i: any, exposed = {}): any { if (i) { i.exposed = exposed if (i.vnode) i.vnode.shapeFlag = 4 } + return exposed } diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 6f4c82d72..1ddb726c6 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -180,7 +180,7 @@ function getRootMap( source, getStart(expression, options), getStart(expression, options), - `const ${HELPER_PREFIX}expose = ${getText(expression.arguments[0], options)};`, + `// @ts-ignore\n${HELPER_PREFIX}expose;\nconst ${HELPER_PREFIX}expose =`, ) rootMap.get(root)!.defineExpose = `(exposed: typeof ${HELPER_PREFIX}expose) => {}` @@ -293,7 +293,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ` const { defineModel } = await import('vue') declare function defineSlots>(slots?: T): T; -declare function defineExpose = Record>(exposed?: Exposed): void; +declare function defineExpose = Record>(exposed?: Exposed): Exposed; declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, From b482dd9356700755db5f31e7d12edcbcf5691f65 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 30 Sep 2024 17:38:18 +0800 Subject: [PATCH 032/156] feat: support defineModel()! --- .../src/core/define-component/index.ts | 4 +- packages/jsx-macros/src/core/define-model.ts | 4 +- packages/jsx-macros/src/core/index.ts | 19 +++-- .../tests/__snapshots__/fixtures.test.ts.snap | 6 +- .../tests/fixtures/define-component.tsx | 2 +- packages/volar/src/jsx-macros.ts | 82 ++++++++++++------- 6 files changed, 73 insertions(+), 44 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 5e1807913..ea76d86e1 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -52,7 +52,7 @@ export function transformDefineComponent( } else { const props = restructure(s, root) for (const prop of props) { - if (prop.path === `${HELPER_PREFIX}props`) { + if (prop.path.endsWith('props')) { if (prop.isRest) { getWalkedIds(root, prop.name).forEach((id) => propsSet.add(id)) } else { @@ -65,7 +65,7 @@ export function transformDefineComponent( for (const prop of map.defineModel || []) { const name = camelize( - prop.arguments[0].type === 'StringLiteral' + prop.arguments[0]?.type === 'StringLiteral' ? prop.arguments[0].value : 'modelValue', ) diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index 12ff006c3..cbf5ce577 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -14,9 +14,7 @@ export function transformDefineModel( s.appendRight( node.arguments[0]?.start || node.end! - 1, `${propsName}, ${ - node.arguments.length && node.arguments[0].type !== 'StringLiteral' - ? `'modelValue',` - : '' + node.arguments[0]?.type !== 'StringLiteral' ? `'modelValue',` : '' }`, ) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 160cf506b..7af75c3c1 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -25,12 +25,15 @@ export type FunctionalNode = | FunctionExpression | ArrowFunctionExpression -function isMacro(node?: Node | null): node is CallExpression { - return !!( - node && - node.type === 'CallExpression' && +function getMacroExpression(node?: Node | null) { + if (node?.type === 'TSNonNullExpression') { + node = node.expression + } + return ( + node?.type === 'CallExpression' && node.callee.type === 'Identifier' && - ['defineSlots', 'defineModel', 'defineExpose'].includes(node.callee.name) + ['defineSlots', 'defineModel', 'defineExpose'].includes(node.callee.name) && + node ) } @@ -66,13 +69,15 @@ function getRootMap(s: MagicStringAST, id: string) { } } - const expression = + let expression = node.type === 'VariableDeclaration' ? node.declarations[0].init : node.type === 'ExpressionStatement' ? node.expression : undefined - if (!isMacro(expression)) return + const macroExpression = getMacroExpression(expression) + if (!macroExpression) return + expression = macroExpression if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = s.sliceNode(expression.callee) if (macroName) { diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 3d2589142..a10a5da32 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -3,14 +3,16 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; +import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";import { defineComponent } from 'vue' const Comp = __MACROS_defineComponent( (__MACROS_props) => { -const props = __MACROS_createPropsRestProxy(__MACROS_props, ['bar']); +const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 'bar'}); +const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); const foo = __MACROS_useModel(props, 'foo') - return () =>
{[foo.value, __MACROS_props.bar, props.baz]}
+ return () =>
{[foo.value, __MACROS_defaults_props.bar, props.baz]}
}, { inheritAttrs: false , props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}, ) diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 5922b76a4..176fc09fb 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -1,7 +1,7 @@ import { defineComponent } from 'vue' const Comp = defineComponent( - ({ bar, ...props }: { bar: 'bar'; baz: 'baz' }) => { + ({ bar = 'bar', ...props }: { bar: 'bar'; baz: 'baz' }) => { const foo = defineModel('foo') return
{[foo.value, bar, props.baz]}
}, diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 1ddb726c6..b1e636543 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -25,7 +25,7 @@ function getMacro( | { expression: import('typescript').CallExpression initializer: import('typescript').Node - isReactivityTransform?: boolean + isRequired: boolean } | undefined { if (!node) return @@ -37,42 +37,46 @@ function getMacro( } function getExpression(decl: import('typescript').Node) { - if ( - ts.isVariableDeclaration(decl) && - decl.initializer && - ts.isCallExpression(decl.initializer) && - ts.isIdentifier(decl.initializer.expression) - ) { - const isReactivityTransform = - decl.initializer.expression.escapedText === '$' - const expression = isReactivityTransform - ? decl.initializer.arguments[0] - : decl.initializer - if (isMacro(expression)) + if (ts.isVariableDeclaration(decl) && decl.initializer) { + const initializer = + ts.isCallExpression(decl.initializer) && + ts.isIdentifier(decl.initializer.expression) && + decl.initializer.expression.escapedText === '$' && + decl.initializer.arguments[0] + ? decl.initializer.arguments[0] + : decl.initializer + const expression = getMacroExpression(initializer) + if (expression) { return { expression, - isReactivityTransform, initializer: decl.initializer, + isRequired: ts.isNonNullExpression(initializer), } - } else if (ts.isExpressionStatement(decl) && isMacro(decl.expression)) { - return { - expression: decl.expression, - initializer: decl, } + } else if (ts.isExpressionStatement(decl)) { + const expression = getMacroExpression(decl.expression) + if (expression) + return { + expression, + initializer: decl.expression, + isRequired: ts.isNonNullExpression(decl.expression), + } } } - function isMacro( - node: import('typescript').Node, - ): node is import('typescript').CallExpression { - return !!( + function getMacroExpression(node: import('typescript').Node) { + if (ts.isNonNullExpression(node)) { + node = node.expression + } + return ( ts.isCallExpression(node) && ts.isIdentifier(node.expression) && [ ...vueCompilerOptions.macros.defineModel, ...vueCompilerOptions.macros.defineExpose, ...vueCompilerOptions.macros.defineSlots, - ].includes(node.expression.escapedText!) + ].includes(node.expression.escapedText!) && + node ) } } @@ -125,7 +129,7 @@ function getRootMap( const macro = getMacro(node, ts, vueCompilerOptions) if (!macro) return - const { expression, isReactivityTransform, initializer } = macro + let { expression, initializer, isRequired } = macro if (!rootMap.has(root)) rootMap.set(root, {}) const name = getText(expression.expression, options) if (vueCompilerOptions.macros.defineModel.includes(name)) { @@ -139,20 +143,40 @@ function getRootMap( ts.isStringLiteralLike(expression.arguments[0]) ? expression.arguments[1] : expression.arguments[0] - let required = false if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { + let hasRequired = false for (const prop of modelOptions.properties) { if ( ts.isPropertyAssignment(prop) && getText(prop.name, options) === 'required' ) { - required = prop.initializer.kind === ts.SyntaxKind.TrueKeyword + hasRequired = true + isRequired = prop.initializer.kind === ts.SyntaxKind.TrueKeyword } } + + if (!hasRequired && isRequired) { + replaceSourceRange( + codes, + source, + modelOptions.end - 1, + modelOptions.end - 1, + `${expression.arguments.hasTrailingComma ? '' : ','} required: true`, + ) + } + } else if (isRequired) { + replaceSourceRange( + codes, + source, + expression.arguments.end, + expression.arguments.end, + `${expression.arguments.hasTrailingComma ? '' : ','} { required: true }`, + ) } + const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) const typeString = `import("vue").UnwrapRef` - const requiredString = required ? ':' : '?:' + const requiredString = isRequired ? ':' : '?:' ;(rootMap.get(root)!.defineModel ??= [])!.push( `${modelName}${requiredString} ${typeString}`, `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, @@ -160,8 +184,8 @@ function getRootMap( replaceSourceRange( codes, source, - getStart(isReactivityTransform ? initializer : expression, options), - getStart(isReactivityTransform ? initializer : expression, options), + getStart(initializer, options), + getStart(initializer, options), `// @ts-ignore\n${id};\nlet ${id} =`, ) } else if (vueCompilerOptions.macros.defineSlots.includes(name)) { From 222cd87df589b517bdd0b84d683751ba79bbb102 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 30 Sep 2024 19:57:09 +0800 Subject: [PATCH 033/156] fix: lint --- packages/jsx-macros/src/core/define-component/index.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index ea76d86e1..28475d79c 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,8 +1,4 @@ -import { - HELPER_PREFIX, - importHelperFn, - type MagicStringAST, -} from '@vue-macros/common' +import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' import { camelize } from '@vue/shared' import type { FunctionalNode, RootMapValue } from '..' From a628b6b8c22f69a55812fc280c8bd6af2f438a71 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 9 Oct 2024 17:09:13 +0800 Subject: [PATCH 034/156] fix: build error --- packages/jsx-macros/package.json | 1 - .../jsx-macros/src/core/define-component/index.ts | 2 +- packages/jsx-macros/src/core/helper/use-model.ts | 12 +++++++++--- pnpm-lock.yaml | 3 --- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 0ffdd98a8..f5b920a98 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -130,7 +130,6 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue/compiler-core": "catalog:", - "@vue/shared": "catalog:", "unplugin": "catalog:" }, "devDependencies": { diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 28475d79c..3714567bd 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,6 +1,6 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' -import { camelize } from '@vue/shared' +import { camelize } from 'vue' import type { FunctionalNode, RootMapValue } from '..' import { restructure } from './restructure' diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts index be5e133c9..ae5561459 100644 --- a/packages/jsx-macros/src/core/helper/use-model.ts +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -1,7 +1,13 @@ -// Copy from: https://github.com/vuejs/core/blob/main/packages/runtime-core/src/helpers/useModel.ts +// Modified from: https://github.com/vuejs/core/blob/main/packages/runtime-core/src/helpers/useModel.ts -import { camelize, hasChanged, hyphenate } from '@vue/shared' -import { customRef, watchSyncEffect, type ModelRef } from 'vue' +import { camelize, customRef, watchSyncEffect, type ModelRef } from 'vue' + +const hasChanged = (value: any, oldValue: any): boolean => + !Object.is(value, oldValue) + +const hyphenateRE = /\B([A-Z])/g +const hyphenate: (str: string) => string = (str: string) => + str.replaceAll(hyphenateRE, '-$1').toLowerCase() type DefineModelOptions> = { default?: any diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed09afab2..c0bfa0a1c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -633,9 +633,6 @@ importers: '@vue/compiler-core': specifier: 'catalog:' version: 3.5.11 - '@vue/shared': - specifier: 'catalog:' - version: 3.5.11 unplugin: specifier: 'catalog:' version: 1.14.1(webpack-sources@3.2.3) From ffdc3aea3d987ac5f05dc80b1467b2f1ee667aec Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 9 Oct 2024 17:36:34 +0800 Subject: [PATCH 035/156] fix: typecheck --- packages/jsx-macros/package.json | 1 + packages/jsx-macros/src/core/define-component/index.ts | 2 +- pnpm-lock.yaml | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index f5b920a98..0ffdd98a8 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -130,6 +130,7 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue/compiler-core": "catalog:", + "@vue/shared": "catalog:", "unplugin": "catalog:" }, "devDependencies": { diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 3714567bd..28475d79c 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,6 +1,6 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' -import { camelize } from 'vue' +import { camelize } from '@vue/shared' import type { FunctionalNode, RootMapValue } from '..' import { restructure } from './restructure' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c0bfa0a1c..ed09afab2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -633,6 +633,9 @@ importers: '@vue/compiler-core': specifier: 'catalog:' version: 3.5.11 + '@vue/shared': + specifier: 'catalog:' + version: 3.5.11 unplugin: specifier: 'catalog:' version: 1.14.1(webpack-sources@3.2.3) From 632bab68373efe963c270933b367ea1104c641ce Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 10 Oct 2024 10:25:33 +0800 Subject: [PATCH 036/156] fix: undefined error --- packages/jsx-macros/src/core/helper/with-defaults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsx-macros/src/core/helper/with-defaults.ts b/packages/jsx-macros/src/core/helper/with-defaults.ts index e2b2e1a3a..e313ce6d0 100644 --- a/packages/jsx-macros/src/core/helper/with-defaults.ts +++ b/packages/jsx-macros/src/core/helper/with-defaults.ts @@ -27,7 +27,7 @@ function defaultPropsProxy(props: any, defaultProps: any): any { const value = target[prop] === undefined ? defaultProps?.[prop] : target?.[prop] if (typeof value === 'object' && value !== null) { - return defaultPropsProxy(value, defaultProps[prop]) + return defaultPropsProxy(value, defaultProps?.[prop]) } return value }, From e1f6d72b7eae2c8ddc6647824f6eabb54b4288b5 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 10 Oct 2024 18:14:56 +0800 Subject: [PATCH 037/156] feat: prevent depth proxy --- .../src/core/helper/with-defaults.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/jsx-macros/src/core/helper/with-defaults.ts b/packages/jsx-macros/src/core/helper/with-defaults.ts index e313ce6d0..1054de00c 100644 --- a/packages/jsx-macros/src/core/helper/with-defaults.ts +++ b/packages/jsx-macros/src/core/helper/with-defaults.ts @@ -21,20 +21,18 @@ function resolveDefaultProps(paths: Record): any { return result } -function defaultPropsProxy(props: any, defaultProps: any): any { - return new Proxy(props, { - get(target, prop) { - const value = - target[prop] === undefined ? defaultProps?.[prop] : target?.[prop] - if (typeof value === 'object' && value !== null) { - return defaultPropsProxy(value, defaultProps?.[prop]) - } - return value - }, - }) -} +export function createDefaultPropsProxy(props: any, defaults: any): any { + const defaultProps = resolveDefaultProps(defaults) + const result: Record = {} -export function createDefaultPropsProxy(props: any, defaultProps: any): any { - const resolvedDefaultProps = resolveDefaultProps(defaultProps) - return defaultPropsProxy(props, resolvedDefaultProps) + for (const key of [ + ...new Set([...Object.keys(props), ...Object.keys(defaultProps)]), + ]) { + Object.defineProperty(result, key, { + enumerable: true, + get: () => (props[key] === undefined ? defaultProps[key] : props[key]), + }) + } + + return result } From 8a361d77be2a9dabb8156cb009828e6e3ab672b7 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 12 Oct 2024 01:38:36 +0800 Subject: [PATCH 038/156] feat: don't support hyphenation modelName --- .../jsx-macros/src/core/helper/use-model.ts | 49 ++++++------------- packages/volar/src/jsx-macros.ts | 2 +- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts index ae5561459..ed6aa2a29 100644 --- a/packages/jsx-macros/src/core/helper/use-model.ts +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -1,14 +1,10 @@ // Modified from: https://github.com/vuejs/core/blob/main/packages/runtime-core/src/helpers/useModel.ts -import { camelize, customRef, watchSyncEffect, type ModelRef } from 'vue' +import { customRef, watchSyncEffect, type ModelRef } from 'vue' const hasChanged = (value: any, oldValue: any): boolean => !Object.is(value, oldValue) -const hyphenateRE = /\B([A-Z])/g -const hyphenate: (str: string) => string = (str: string) => - str.replaceAll(hyphenateRE, '-$1').toLowerCase() - type DefineModelOptions> = { default?: any get?: (v: T) => any @@ -21,12 +17,11 @@ export function useModel< >(props: T, name: K, options?: DefineModelOptions): ModelRef export function useModel( props: Record, - name: string = 'modelValue', + name: string, options: DefineModelOptions = {}, ): any { - const camelizedName = camelize(name) - const hyphenatedName = hyphenate(name) - const modifiers = getModelModifiers(props, name) + const modifiers = + name === 'modelValue' ? props.modelModifiers : props[`${name}Modifiers`] const res = customRef((track, trigger) => { let localValue: any = options?.default @@ -48,36 +43,35 @@ export function useModel( }, set(value) { - if (!hasChanged(value, localValue)) { + const emittedValue = options.set ? options.set(value) : value + if ( + !hasChanged(emittedValue, localValue) && + !(prevSetValue !== undefined && hasChanged(value, prevSetValue)) + ) { return } if ( !( + props && // check if parent has passed v-model - ( - (name in props || - camelizedName in props || - hyphenatedName in props) && - (`onUpdate:${name}` in props || - `onUpdate:${camelizedName}` in props || - `onUpdate:${hyphenatedName}` in props) - ) + props[name] !== undefined && + props[`onUpdate:${name}`] !== undefined ) ) { // no v-model, local update localValue = value trigger() } - const emittedValue = options.set ? options.set(value) : value + props[`onUpdate:${name}`]?.(emittedValue) // #10279: if the local value is converted via a setter but the value // emitted to parent was the same, the parent will not trigger any // updates and there will be no prop sync. However the local input state // may be out of sync, so we need to force an update here. if ( - value !== emittedValue && - value !== prevSetValue && - emittedValue === prevEmittedValue + hasChanged(value, emittedValue) && + hasChanged(value, prevSetValue) && + !hasChanged(emittedValue, prevEmittedValue) ) { trigger() } @@ -102,14 +96,3 @@ export function useModel( } return res } - -const getModelModifiers = ( - props: Record, - modelName: string, -): Record | undefined => { - return modelName === 'modelValue' || modelName === 'model-value' - ? props.modelModifiers - : props[`${modelName}Modifiers`] || - props[`${camelize(modelName)}Modifiers`] || - props[`${hyphenate(modelName)}Modifiers`] -} diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index b1e636543..d4d2846ac 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -178,7 +178,7 @@ function getRootMap( const typeString = `import("vue").UnwrapRef` const requiredString = isRequired ? ':' : '?:' ;(rootMap.get(root)!.defineModel ??= [])!.push( - `${modelName}${requiredString} ${typeString}`, + `'${modelName}'${requiredString} ${typeString}`, `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, ) replaceSourceRange( From 0e6d0af97da18a07316fba422065041c369bd2b9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 12 Oct 2024 16:20:29 +0800 Subject: [PATCH 039/156] feat: inferred modelName from variable name --- .../src/core/define-component/index.ts | 8 +- packages/jsx-macros/src/core/define-model.ts | 3 +- packages/jsx-macros/src/core/index.ts | 32 ++++--- .../tests/__snapshots__/fixtures.test.ts.snap | 14 ++-- .../tests/fixtures/define-model.tsx | 14 ++-- packages/volar/src/jsx-macros.ts | 84 +++++++++---------- 6 files changed, 88 insertions(+), 67 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 28475d79c..30a28acf0 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -59,11 +59,11 @@ export function transformDefineComponent( } } - for (const prop of map.defineModel || []) { + for (const { expression, modelName } of map.defineModel || []) { const name = camelize( - prop.arguments[0]?.type === 'StringLiteral' - ? prop.arguments[0].value - : 'modelValue', + expression.arguments[0]?.type === 'StringLiteral' + ? expression.arguments[0].value + : modelName, ) propsSet.add(`'${name}'`) propsSet.add(`'onUpdate:${name}'`) diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index cbf5ce577..4ffa9904f 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -4,6 +4,7 @@ import type { CallExpression } from '@babel/types' export function transformDefineModel( node: CallExpression, + modelName: string, propsName: string, s: MagicStringAST, ): void { @@ -14,7 +15,7 @@ export function transformDefineModel( s.appendRight( node.arguments[0]?.start || node.end! - 1, `${propsName}, ${ - node.arguments[0]?.type !== 'StringLiteral' ? `'modelValue',` : '' + node.arguments[0]?.type !== 'StringLiteral' ? `'${modelName}',` : '' }`, ) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 7af75c3c1..9b7404399 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -39,7 +39,7 @@ function getMacroExpression(node?: Node | null) { export type RootMapValue = { defineComponent?: CallExpression - defineModel?: CallExpression[] + defineModel?: { expression: CallExpression; modelName: string }[] defineSlots?: CallExpression defineExpose?: CallExpression } @@ -69,7 +69,7 @@ function getRootMap(s: MagicStringAST, id: string) { } } - let expression = + const expression = node.type === 'VariableDeclaration' ? node.declarations[0].init : node.type === 'ExpressionStatement' @@ -77,14 +77,26 @@ function getRootMap(s: MagicStringAST, id: string) { : undefined const macroExpression = getMacroExpression(expression) if (!macroExpression) return - expression = macroExpression if (!rootMap.has(root)) rootMap.set(root, {}) - const macroName = s.sliceNode(expression.callee) + const macroName = s.sliceNode(macroExpression.callee) if (macroName) { - if (macroName === 'defineModel') - (rootMap.get(root)!.defineModel ??= []).push(expression) - else if (macroName === 'defineSlots' || macroName === 'defineExpose') - rootMap.get(root)![macroName] = expression + if (macroName === 'defineModel') { + const modelName = + node.type === 'VariableDeclaration' && + node.declarations[0]?.type === 'VariableDeclarator' && + node.declarations[0].id.type === 'Identifier' + ? node.declarations[0].id.name + : 'modelValue' + ;(rootMap.get(root)!.defineModel ??= []).push({ + expression: macroExpression, + modelName, + }) + } else if ( + macroName === 'defineSlots' || + macroName === 'defineExpose' + ) { + rootMap.get(root)![macroName] = macroExpression + } } }, leave() { @@ -140,8 +152,8 @@ export function transformJsxMacros( transformDefineComponent(root, propsName, map, s, options.lib) } if (map.defineModel?.length) { - map.defineModel.forEach((node) => { - transformDefineModel(node, propsName, s) + map.defineModel.forEach(({ expression, modelName }) => { + transformDefineModel(expression, modelName, propsName, s) }) } if (map.defineSlots) { diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index a10a5da32..cdbd28f54 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -39,13 +39,17 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { - const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) - return
{foo.value}
+ const foo = __MACROS_useModel(__MACROS_props, 'foo',{ default: bar })! + return
{foo}
} -export default function (__MACROS_props) { - const foo = __MACROS_useModel(__MACROS_props, 'foo') - return
{foo}
+export default function ({}) { + const modelValue = __MACROS_useModel(__MACROS_props, 'modelValue',)! + return ( + + {modelValue.value} + + ) } " `; diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 1861f4d4d..dce1f7223 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -1,9 +1,13 @@ export const Comp = ({ bar }: { bar: string }) => { - const foo = defineModel('foo', { default: bar }) - return
{foo.value}
+ const foo = defineModel({ default: bar })! + return
{foo}
} -export default function () { - const foo = defineModel('foo') - return
{foo}
+export default function ({}) { + const modelValue = defineModel()! + return ( + + {modelValue.value} + + ) } diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index d4d2846ac..e5c668744 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -23,6 +23,7 @@ function getMacro( vueCompilerOptions: VueCompilerOptions, ): | { + name?: string expression: import('typescript').CallExpression initializer: import('typescript').Node isRequired: boolean @@ -48,6 +49,7 @@ function getMacro( const expression = getMacroExpression(initializer) if (expression) { return { + name: ts.isIdentifier(decl.name) ? decl.name.text : undefined, expression, initializer: decl.initializer, isRequired: ts.isNonNullExpression(initializer), @@ -129,15 +131,15 @@ function getRootMap( const macro = getMacro(node, ts, vueCompilerOptions) if (!macro) return - let { expression, initializer, isRequired } = macro + let { name, expression, initializer, isRequired } = macro if (!rootMap.has(root)) rootMap.set(root, {}) - const name = getText(expression.expression, options) - if (vueCompilerOptions.macros.defineModel.includes(name)) { + const macroName = getText(expression.expression, options) + if (vueCompilerOptions.macros.defineModel.includes(macroName)) { const modelName = expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) ? expression.arguments[0].text - : 'modelValue' + : name || 'modelValue' const modelOptions = expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) @@ -170,16 +172,15 @@ function getRootMap( source, expression.arguments.end, expression.arguments.end, - `${expression.arguments.hasTrailingComma ? '' : ','} { required: true }`, + `${!expression.arguments.hasTrailingComma && expression.arguments.length ? ',' : ''} { required: true }`, ) } const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) const typeString = `import("vue").UnwrapRef` - const requiredString = isRequired ? ':' : '?:' ;(rootMap.get(root)!.defineModel ??= [])!.push( - `'${modelName}'${requiredString} ${typeString}`, - `'onUpdate:${modelName}'${requiredString} ($event: ${typeString}) => any`, + `'${modelName}'${isRequired ? ':' : '?:'} ${typeString}`, + `'onUpdate:${modelName}'?: ($event: ${typeString}) => any`, ) replaceSourceRange( codes, @@ -188,7 +189,7 @@ function getRootMap( getStart(initializer, options), `// @ts-ignore\n${id};\nlet ${id} =`, ) - } else if (vueCompilerOptions.macros.defineSlots.includes(name)) { + } else if (vueCompilerOptions.macros.defineSlots.includes(macroName)) { replaceSourceRange( codes, source, @@ -198,7 +199,7 @@ function getRootMap( ) rootMap.get(root)!.defineSlots = `{ vSlots?: typeof ${HELPER_PREFIX}slots }` - } else if (vueCompilerOptions.macros.defineExpose.includes(name)) { + } else if (vueCompilerOptions.macros.defineExpose.includes(macroName)) { replaceSourceRange( codes, source, @@ -225,31 +226,26 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) if (asyncModifier) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as __VLS_MaybeReturnType>['render']> & { __ctx: Awaited>['render']> & { __ctx: Awaited> }` const propsType = root.parameters[0]?.type ? String(getText(root.parameters[0].type, options)) : '{}' - const params = `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType}, ${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(` + replaceSourceRange( + codes, + source, + getStart(root.parameters, options), + getStart(root.parameters, options), + `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType},`, + `${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, + ) if (ts.isArrowFunction(root)) { - replaceSourceRange( - codes, - source, - getStart(root.parameters, options), - getStart(root.parameters, options), - params, - ) replaceSourceRange(codes, source, root.end, root.end, `)) => `, result) } else { - replaceSourceRange( - codes, - source, - root.parameters.pos, - root.parameters.pos, - params, - ) replaceSourceRange( codes, source, @@ -260,31 +256,35 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { replaceSourceRange( codes, source, - root.body.end - 1, - root.body.end - 1, - `})){ return `, + root.end, + root.end, + `)){ return `, result, + '}', ) } ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { - const defaultProps = + const defaultProps = [] + const elements = root.parameters[0] && !root.parameters[0].type && ts.isObjectBindingPattern(root.parameters[0].name) ? root.parameters[0].name.elements - .map((element) => { - const isRequired = element.initializer - ? ts.isNonNullExpression(element.initializer) - : false - return ts.isIdentifier(element.name) - ? `${element.name.text}${isRequired ? ':' : '?:'} typeof ${element.name.text}` - : '' - }) - .filter(Boolean) - .join(', ') - : '' + : [] + for (const element of elements) { + if (ts.isIdentifier(element.name)) + defaultProps.push( + `${element.name.text}${ + element.initializer && + ts.isNonNullExpression(element.initializer) + ? ':' + : '?:' + } typeof ${element.name.text}`, + ) + } + replaceSourceRange( codes, source, @@ -292,7 +292,7 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { getStart(node.expression, options), `return {\nprops: {} as `, options.vueVersion ? `import('vue').PublicProps & ` : '', - `{${defaultProps}} & `, + `{${defaultProps.join(', ')}} & `, map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', From f3787c9bfc1cc01bf8f2e0d3941b55abdfc0f421 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 14 Oct 2024 10:07:12 +0800 Subject: [PATCH 040/156] feat: support validator --- .../src/core/define-component/index.ts | 57 +++++++++++++------ .../src/core/define-component/restructure.ts | 2 + packages/jsx-macros/src/core/index.ts | 7 ++- .../tests/__snapshots__/fixtures.test.ts.snap | 16 ++++-- .../tests/fixtures/define-component.tsx | 10 +++- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 30a28acf0..46d89e7c5 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -14,13 +14,13 @@ function getWalkedIds(root: FunctionalNode, propsName: string) { (parent?.type === 'MemberExpression' || parent?.type === 'OptionalMemberExpression') ) { - walkedIds.add( + const prop = parent.property.type === 'Identifier' - ? `'${parent.property.name}'` + ? parent.property.name : parent.property.type === 'StringLiteral' ? parent.property.value - : '', - ) + : '' + if (prop) walkedIds.add(prop) } }, false, @@ -41,39 +41,61 @@ export function transformDefineComponent( importHelperFn(s, 0, 'defineComponent', 'vue'), ) - let propsSet = new Set() + const props: Record = {} if (root.params[0]) { if (root.params[0].type === 'Identifier') { - propsSet = getWalkedIds(root, propsName) + getWalkedIds(root, propsName).forEach((id) => (props[id] = null)) } else { - const props = restructure(s, root) - for (const prop of props) { + for (const prop of restructure(s, root)) { if (prop.path.endsWith('props')) { if (prop.isRest) { - getWalkedIds(root, prop.name).forEach((id) => propsSet.add(id)) + getWalkedIds(root, prop.name).forEach((id) => (props[id] = null)) } else { - propsSet.add(`'${prop.name}'`) + props[prop.name] = prop.isRequired ? '{ required: true }' : null } } } } } - for (const { expression, modelName } of map.defineModel || []) { + for (const { expression, modelName, isRequired } of map.defineModel || []) { const name = camelize( expression.arguments[0]?.type === 'StringLiteral' ? expression.arguments[0].value : modelName, ) - propsSet.add(`'${name}'`) - propsSet.add(`'onUpdate:${name}'`) + const modelOptions = + expression.arguments[0]?.type === 'ObjectExpression' + ? expression.arguments[0] + : expression.arguments[1]?.type === 'ObjectExpression' + ? expression.arguments[1] + : undefined + const options: any = {} + if (isRequired) options.required = true + for (const prop of modelOptions?.properties || []) { + if ( + prop.type === 'ObjectProperty' && + prop.key.type === 'Identifier' && + ['validator', 'type', 'required'].includes(prop.key.name) + ) { + options[prop.key.name] = s.sliceNode(prop.value) + } + } + props[name] = Object.keys(options).length + ? `{ ${Object.entries(options) + .map(([key, value]) => `${key}: ${value}`) + .join(', ')} }` + : null + props[`'onUpdate:${name}'`] = null } - const result = Array.from(propsSet).filter(Boolean).join(', ') - if (result) { + const propsString = Object.entries(props) + .map(([key, value]) => `${key}: ${value}`) + .join(', ') + if (propsString) { const argument = map.defineComponent.arguments[1] if (!argument) { - s.appendRight(root.end!, `, { props: [ ${result} ] }`) + s.appendRight(root.end!, `, { props: { ${propsString} } }`) } else if ( argument.type === 'ObjectExpression' && !argument.properties?.find( @@ -89,11 +111,12 @@ export function transformDefineComponent( !argument.properties.length || argument.extra?.trailingComma ? '' : ',' - } props: [ ${result} ]`, + } props: { ${propsString} }`, ) } } + // Auto add `() => ` for return statement if (lib === 'vue') { if (root.body.type === 'BlockStatement') { const returnStatement = root.body.body.find( diff --git a/packages/jsx-macros/src/core/define-component/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts index 6c527256c..ddddfdf53 100644 --- a/packages/jsx-macros/src/core/define-component/restructure.ts +++ b/packages/jsx-macros/src/core/define-component/restructure.ts @@ -14,6 +14,7 @@ type Prop = { value: string defaultValue?: string isRest?: boolean + isRequired?: boolean } function getProps( @@ -62,6 +63,7 @@ function getProps( name: prop.value.left.name, value: `.${prop.key.name}`, defaultValue: s.slice(prop.value.right.start!, prop.value.right.end!), + isRequired: prop.value.right.type === 'TSNonNullExpression', }) } else if (!getProps(prop.value, `${path}.${prop.key.name}`, s, props)) { // { foo: bar } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 9b7404399..cc901440e 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -39,7 +39,11 @@ function getMacroExpression(node?: Node | null) { export type RootMapValue = { defineComponent?: CallExpression - defineModel?: { expression: CallExpression; modelName: string }[] + defineModel?: { + expression: CallExpression + modelName: string + isRequired: boolean + }[] defineSlots?: CallExpression defineExpose?: CallExpression } @@ -90,6 +94,7 @@ function getRootMap(s: MagicStringAST, id: string) { ;(rootMap.get(root)!.defineModel ??= []).push({ expression: macroExpression, modelName, + isRequired: expression?.type === 'TSNonNullExpression', }) } else if ( macroName === 'defineSlots' || diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index cdbd28f54..66209a458 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -9,18 +9,26 @@ import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model" const Comp = __MACROS_defineComponent( (__MACROS_props) => { -const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 'bar'}); +const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 'bar'!}); const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); - const foo = __MACROS_useModel(props, 'foo') + const foo = __MACROS_useModel(props, 'foo', { + validator: (value) => { + return value === 'foo' + }, + required: false, + type: String, + }) return () =>
{[foo.value, __MACROS_defaults_props.bar, props.baz]}
}, - { inheritAttrs: false , props: [ 'bar', 'baz', 'foo', 'onUpdate:foo' ]}, + { inheritAttrs: false , props: { bar: { required: true }, baz: null, foo: { validator: (value) => { + return value === 'foo' + }, required: false, type: String }, 'onUpdate:foo': null }}, ) const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar']]}
-}, { props: [ bar, 'foo', 'onUpdate:foo' ] }) +}, { props: { bar: null, foo: null, 'onUpdate:foo': null } }) " `; diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 176fc09fb..bde33c474 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -1,8 +1,14 @@ import { defineComponent } from 'vue' const Comp = defineComponent( - ({ bar = 'bar', ...props }: { bar: 'bar'; baz: 'baz' }) => { - const foo = defineModel('foo') + ({ bar = 'bar'!, ...props }: { bar: 'bar'; baz: 'baz' }) => { + const foo = defineModel('foo', { + validator: (value) => { + return value === 'foo' + }, + required: false, + type: String, + }) return
{[foo.value, bar, props.baz]}
}, { inheritAttrs: false }, From 2ce6fe8a87e23e394b7dafb07aa04ca742f958f7 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 14 Oct 2024 10:30:31 +0800 Subject: [PATCH 041/156] fix: typecheck --- .../jsx-macros/src/core/define-component/index.ts | 6 +++--- packages/jsx-macros/src/core/index.ts | 11 ++++++++--- .../tests/__snapshots__/fixtures.test.ts.snap | 2 +- packages/jsx-macros/tests/fixtures/define-model.tsx | 2 +- packages/volar/src/jsx-macros.ts | 6 +++--- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 46d89e7c5..5e2dbc77e 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -108,9 +108,9 @@ export function transformDefineComponent( s.appendLeft( argument.end! - 1, `${ - !argument.properties.length || argument.extra?.trailingComma - ? '' - : ',' + !argument.extra?.trailingComma && argument.properties.length + ? ',' + : '' } props: { ${propsString} }`, ) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index cc901440e..75437d92e 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -140,12 +140,17 @@ export function transformJsxMacros( lastProp.argument.type === 'Identifier' ) { propsName = lastProp.argument.name - } else if (lastProp) { + } else { s.appendRight( root.params[0].extra?.trailingComma ? (root.params[0].extra?.trailingComma as number) + 1 - : lastProp.end!, - `${root.params[0].extra?.trailingComma ? '' : ','} ...${HELPER_PREFIX}props`, + : lastProp?.end || root.params[0].end! - 1, + `${ + !root.params[0].extra?.trailingComma && + root.params[0].properties.length + ? ',' + : '' + } ...${HELPER_PREFIX}props`, ) } } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 66209a458..e9d607a3a 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -51,7 +51,7 @@ import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model" return
{foo}
} -export default function ({}) { +export default function (__MACROS_props) { const modelValue = __MACROS_useModel(__MACROS_props, 'modelValue',)! return ( diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index dce1f7223..0208a3121 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -3,7 +3,7 @@ export const Comp = ({ bar }: { bar: string }) => { return
{foo}
} -export default function ({}) { +export default function () { const modelValue = defineModel()! return ( diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index e5c668744..70c4300fb 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -49,7 +49,7 @@ function getMacro( const expression = getMacroExpression(initializer) if (expression) { return { - name: ts.isIdentifier(decl.name) ? decl.name.text : undefined, + name: ts.isIdentifier(decl.name) ? decl.name.escapedText! : undefined, expression, initializer: decl.initializer, isRequired: ts.isNonNullExpression(initializer), @@ -276,12 +276,12 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { for (const element of elements) { if (ts.isIdentifier(element.name)) defaultProps.push( - `${element.name.text}${ + `${element.name.escapedText}${ element.initializer && ts.isNonNullExpression(element.initializer) ? ':' : '?:' - } typeof ${element.name.text}`, + } typeof ${element.name.escapedText}`, ) } From 4f49e4a02373af974cb13f74616206162d3fa39c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 14 Oct 2024 16:23:09 +0800 Subject: [PATCH 042/156] refactor: rename to createPropsDefaultProxy --- packages/jsx-macros/package.json | 1 - packages/jsx-macros/src/api.ts | 2 +- .../jsx-macros/src/core/define-component/index.ts | 15 ++++++--------- .../src/core/define-component/restructure.ts | 6 +++--- .../jsx-macros/src/core/helper/with-defaults.ts | 2 +- .../tests/__snapshots__/fixtures.test.ts.snap | 8 ++++---- .../tests/__snapshots__/restructure.spec.ts.snap | 10 +++++----- pnpm-lock.yaml | 3 --- 8 files changed, 20 insertions(+), 27 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index a3334a1eb..89916274a 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -130,7 +130,6 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue/compiler-core": "catalog:", - "@vue/shared": "catalog:", "unplugin": "catalog:" }, "devDependencies": { diff --git a/packages/jsx-macros/src/api.ts b/packages/jsx-macros/src/api.ts index 163360c76..d06b255c6 100644 --- a/packages/jsx-macros/src/api.ts +++ b/packages/jsx-macros/src/api.ts @@ -1,3 +1,3 @@ export * from './core' export { restructure } from './core/define-component/restructure' -export { createDefaultPropsProxy } from './core/helper/with-defaults' +export { createPropsDefaultProxy } from './core/helper/with-defaults' diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 5e2dbc77e..b7cc70e2e 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,6 +1,5 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' -import { camelize } from '@vue/shared' import type { FunctionalNode, RootMapValue } from '..' import { restructure } from './restructure' @@ -57,13 +56,7 @@ export function transformDefineComponent( } } } - for (const { expression, modelName, isRequired } of map.defineModel || []) { - const name = camelize( - expression.arguments[0]?.type === 'StringLiteral' - ? expression.arguments[0].value - : modelName, - ) const modelOptions = expression.arguments[0]?.type === 'ObjectExpression' ? expression.arguments[0] @@ -81,12 +74,16 @@ export function transformDefineComponent( options[prop.key.name] = s.sliceNode(prop.value) } } - props[name] = Object.keys(options).length + const propName = + expression.arguments[0]?.type === 'StringLiteral' + ? expression.arguments[0].value + : modelName + props[`'${propName}'`] = Object.keys(options).length ? `{ ${Object.entries(options) .map(([key, value]) => `${key}: ${value}`) .join(', ')} }` : null - props[`'onUpdate:${name}'`] = null + props[`'onUpdate:${propName}'`] = null } const propsString = Object.entries(props) diff --git a/packages/jsx-macros/src/core/define-component/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts index ddddfdf53..7c8c7384f 100644 --- a/packages/jsx-macros/src/core/define-component/restructure.ts +++ b/packages/jsx-macros/src/core/define-component/restructure.ts @@ -150,10 +150,10 @@ export function restructure( } } for (const [path, values] of Object.entries(defaultValues)) { - const createDefaultPropsProxy = importHelperFn( + const createPropsDefaultProxy = importHelperFn( s, 0, - 'createDefaultPropsProxy', + 'createPropsDefaultProxy', withDefaultsFrom, ) const resolvedPath = path.replace( @@ -168,7 +168,7 @@ export function restructure( prependFunctionalNode( node, s, - `\nconst ${path} = ${createDefaultPropsProxy}(${resolvedPath}, {${resolvedValues}})`, + `\nconst ${path} = ${createPropsDefaultProxy}(${resolvedPath}, {${resolvedValues}})`, ) } diff --git a/packages/jsx-macros/src/core/helper/with-defaults.ts b/packages/jsx-macros/src/core/helper/with-defaults.ts index 1054de00c..0d805e762 100644 --- a/packages/jsx-macros/src/core/helper/with-defaults.ts +++ b/packages/jsx-macros/src/core/helper/with-defaults.ts @@ -21,7 +21,7 @@ function resolveDefaultProps(paths: Record): any { return result } -export function createDefaultPropsProxy(props: any, defaults: any): any { +export function createPropsDefaultProxy(props: any, defaults: any): any { const defaultProps = resolveDefaultProps(defaults) const result: Record = {} diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index e9d607a3a..05e2408f2 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -3,13 +3,13 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; -import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";import { defineComponent } from 'vue' const Comp = __MACROS_defineComponent( (__MACROS_props) => { -const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 'bar'!}); +const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!}); const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); const foo = __MACROS_useModel(props, 'foo', { validator: (value) => { @@ -20,7 +20,7 @@ const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); }) return () =>
{[foo.value, __MACROS_defaults_props.bar, props.baz]}
}, - { inheritAttrs: false , props: { bar: { required: true }, baz: null, foo: { validator: (value) => { + { inheritAttrs: false , props: { bar: { required: true }, baz: null, 'foo': { validator: (value) => { return value === 'foo' }, required: false, type: String }, 'onUpdate:foo': null }}, ) @@ -28,7 +28,7 @@ const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar']]}
-}, { props: { bar: null, foo: null, 'onUpdate:foo': null } }) +}, { props: { bar: null, 'foo': null, 'onUpdate:foo': null } }) " `; diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap index b68cdc42e..aa1ea110b 100644 --- a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap @@ -17,10 +17,10 @@ exports[`transform > reconstruct arrowFunctionExpression 1`] = ` exports[`transform > reconstruct default-prop 1`] = ` " -import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props, __MACROS_props1){ -const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.foo': 'bar'}); -const __MACROS_defaults_props1 = __MACROS_createDefaultPropsProxy(__MACROS_props1, {'.foo': 'foo'}); +const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.foo': 'bar'}); +const __MACROS_defaults_props1 = __MACROS_createPropsDefaultProxy(__MACROS_props1, {'.foo': 'foo'}); const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'baz']); return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.baz, rest, __MACROS_defaults_props1.foo]} }" @@ -28,9 +28,9 @@ const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'baz exports[`transform > reconstruct rest-prop 1`] = ` " -import { createDefaultPropsProxy as __MACROS_createDefaultPropsProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props){ -const __MACROS_defaults_props = __MACROS_createDefaultPropsProxy(__MACROS_props, {'.bar': 1}); +const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 1}); const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'bar']); return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.bar, rest]} }" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf1703e94..8662d63ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -633,9 +633,6 @@ importers: '@vue/compiler-core': specifier: 'catalog:' version: 3.5.11 - '@vue/shared': - specifier: 'catalog:' - version: 3.5.11 unplugin: specifier: 'catalog:' version: 1.14.1(webpack-sources@3.2.3) From 431cbb38c6ee8e2f4d15dd379a6848b771d0f4a7 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 14 Oct 2024 18:44:53 +0800 Subject: [PATCH 043/156] revert: remove auto inferred modelName --- .../jsx-macros/src/core/define-component/index.ts | 4 ++-- packages/jsx-macros/src/core/define-model.ts | 3 +-- packages/jsx-macros/src/core/index.ts | 12 ++---------- .../tests/__snapshots__/fixtures.test.ts.snap | 4 ++-- packages/jsx-macros/tests/fixtures/define-model.tsx | 4 ++-- packages/volar/src/jsx-macros.ts | 7 +++---- 6 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index b7cc70e2e..68f66e579 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -56,7 +56,7 @@ export function transformDefineComponent( } } } - for (const { expression, modelName, isRequired } of map.defineModel || []) { + for (const { expression, isRequired } of map.defineModel || []) { const modelOptions = expression.arguments[0]?.type === 'ObjectExpression' ? expression.arguments[0] @@ -77,7 +77,7 @@ export function transformDefineComponent( const propName = expression.arguments[0]?.type === 'StringLiteral' ? expression.arguments[0].value - : modelName + : 'modelValue' props[`'${propName}'`] = Object.keys(options).length ? `{ ${Object.entries(options) .map(([key, value]) => `${key}: ${value}`) diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index 4ffa9904f..cbf5ce577 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -4,7 +4,6 @@ import type { CallExpression } from '@babel/types' export function transformDefineModel( node: CallExpression, - modelName: string, propsName: string, s: MagicStringAST, ): void { @@ -15,7 +14,7 @@ export function transformDefineModel( s.appendRight( node.arguments[0]?.start || node.end! - 1, `${propsName}, ${ - node.arguments[0]?.type !== 'StringLiteral' ? `'${modelName}',` : '' + node.arguments[0]?.type !== 'StringLiteral' ? `'modelValue',` : '' }`, ) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 75437d92e..e7620babb 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -41,7 +41,6 @@ export type RootMapValue = { defineComponent?: CallExpression defineModel?: { expression: CallExpression - modelName: string isRequired: boolean }[] defineSlots?: CallExpression @@ -85,15 +84,8 @@ function getRootMap(s: MagicStringAST, id: string) { const macroName = s.sliceNode(macroExpression.callee) if (macroName) { if (macroName === 'defineModel') { - const modelName = - node.type === 'VariableDeclaration' && - node.declarations[0]?.type === 'VariableDeclarator' && - node.declarations[0].id.type === 'Identifier' - ? node.declarations[0].id.name - : 'modelValue' ;(rootMap.get(root)!.defineModel ??= []).push({ expression: macroExpression, - modelName, isRequired: expression?.type === 'TSNonNullExpression', }) } else if ( @@ -162,8 +154,8 @@ export function transformJsxMacros( transformDefineComponent(root, propsName, map, s, options.lib) } if (map.defineModel?.length) { - map.defineModel.forEach(({ expression, modelName }) => { - transformDefineModel(expression, modelName, propsName, s) + map.defineModel.forEach(({ expression }) => { + transformDefineModel(expression, propsName, s) }) } if (map.defineSlots) { diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 05e2408f2..4a8baf89c 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -47,8 +47,8 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { - const foo = __MACROS_useModel(__MACROS_props, 'foo',{ default: bar })! - return
{foo}
+ const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar })! + return
{foo.value}
} export default function (__MACROS_props) { diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 0208a3121..0ef6a10c7 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -1,6 +1,6 @@ export const Comp = ({ bar }: { bar: string }) => { - const foo = defineModel({ default: bar })! - return
{foo}
+ const foo = defineModel('foo', { default: bar })! + return
{foo.value}
} export default function () { diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 70c4300fb..6de2c88be 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -23,7 +23,6 @@ function getMacro( vueCompilerOptions: VueCompilerOptions, ): | { - name?: string expression: import('typescript').CallExpression initializer: import('typescript').Node isRequired: boolean @@ -49,7 +48,6 @@ function getMacro( const expression = getMacroExpression(initializer) if (expression) { return { - name: ts.isIdentifier(decl.name) ? decl.name.escapedText! : undefined, expression, initializer: decl.initializer, isRequired: ts.isNonNullExpression(initializer), @@ -131,7 +129,8 @@ function getRootMap( const macro = getMacro(node, ts, vueCompilerOptions) if (!macro) return - let { name, expression, initializer, isRequired } = macro + const { expression, initializer } = macro + let isRequired = macro.isRequired if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = getText(expression.expression, options) if (vueCompilerOptions.macros.defineModel.includes(macroName)) { @@ -139,7 +138,7 @@ function getRootMap( expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) ? expression.arguments[0].text - : name || 'modelValue' + : 'modelValue' const modelOptions = expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) From c2552662c4b64a6cecc5582da7d08ae5926b3fb2 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 15 Oct 2024 09:09:55 +0800 Subject: [PATCH 044/156] feat: use props instead of rest-props --- packages/jsx-macros/src/core/index.ts | 7 +------ .../jsx-macros/tests/__snapshots__/fixtures.test.ts.snap | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index e7620babb..e3ed82b6b 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -127,12 +127,7 @@ export function transformJsxMacros( propsName = root.params[0].name } else if (root.params[0].type === 'ObjectPattern') { const lastProp = root.params[0].properties.at(-1) - if ( - lastProp?.type === 'RestElement' && - lastProp.argument.type === 'Identifier' - ) { - propsName = lastProp.argument.name - } else { + if (lastProp?.type !== 'RestElement') { s.appendRight( root.params[0].extra?.trailingComma ? (root.params[0].extra?.trailingComma as number) + 1 diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 4a8baf89c..6646f4faa 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -11,7 +11,7 @@ const Comp = __MACROS_defineComponent( (__MACROS_props) => { const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!}); const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); - const foo = __MACROS_useModel(props, 'foo', { + const foo = __MACROS_useModel(__MACROS_props, 'foo', { validator: (value) => { return value === 'foo' }, From 485ebb01ea09d67ccaa65044a72891f31f055d77 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 15 Oct 2024 22:58:02 +0800 Subject: [PATCH 045/156] chore: update package-name --- packages/jsx-macros/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 89916274a..21ef2debc 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -2,7 +2,7 @@ "name": "@vue-macros/jsx-macros", "version": "0.0.0", "packageManager": "pnpm@9.12.1", - "description": "jsx-macros feature from Vue Macros.", + "description": "jsxMacros feature from Vue Macros.", "type": "module", "keywords": [ "vue-macros", From ddabcd91974a5c4c46cf34068a61fce201d4c5a8 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 17 Oct 2024 17:44:45 +0800 Subject: [PATCH 046/156] fix: typo --- .../src/core/define-component/restructure.ts | 4 ++-- .../tests/__snapshots__/fixtures.test.ts.snap | 6 +++--- .../tests/__snapshots__/restructure.spec.ts.snap | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts index 7c8c7384f..161ea3326 100644 --- a/packages/jsx-macros/src/core/define-component/restructure.ts +++ b/packages/jsx-macros/src/core/define-component/restructure.ts @@ -130,7 +130,7 @@ export function restructure( ...(hasDefaultValue ? props.map((i) => ({ ...i, - path: i.path.replace(HELPER_PREFIX, `${HELPER_PREFIX}defaults_`), + path: i.path.replace(HELPER_PREFIX, `${HELPER_PREFIX}default_`), })) : props), ) @@ -157,7 +157,7 @@ export function restructure( withDefaultsFrom, ) const resolvedPath = path.replace( - `${HELPER_PREFIX}defaults_`, + `${HELPER_PREFIX}default_`, HELPER_PREFIX, ) const resolvedValues = values diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 6646f4faa..2778a7e81 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -9,8 +9,8 @@ import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model" const Comp = __MACROS_defineComponent( (__MACROS_props) => { -const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!}); -const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); +const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!}); +const props = __MACROS_createPropsRestProxy(__MACROS_default_props, ['bar']); const foo = __MACROS_useModel(__MACROS_props, 'foo', { validator: (value) => { return value === 'foo' @@ -18,7 +18,7 @@ const props = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['bar']); required: false, type: String, }) - return () =>
{[foo.value, __MACROS_defaults_props.bar, props.baz]}
+ return () =>
{[foo.value, __MACROS_default_props.bar, props.baz]}
}, { inheritAttrs: false , props: { bar: { required: true }, baz: null, 'foo': { validator: (value) => { return value === 'foo' diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap index aa1ea110b..19ddadec8 100644 --- a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap @@ -19,10 +19,10 @@ exports[`transform > reconstruct default-prop 1`] = ` " import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props, __MACROS_props1){ -const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.foo': 'bar'}); -const __MACROS_defaults_props1 = __MACROS_createPropsDefaultProxy(__MACROS_props1, {'.foo': 'foo'}); -const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'baz']); - return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.baz, rest, __MACROS_defaults_props1.foo]} +const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.foo': 'bar'}); +const __MACROS_default_props1 = __MACROS_createPropsDefaultProxy(__MACROS_props1, {'.foo': 'foo'}); +const rest = __MACROS_createPropsRestProxy(__MACROS_default_props, ['foo', 'baz']); + return <>{[__MACROS_default_props.foo, __MACROS_default_props.baz, rest, __MACROS_default_props1.foo]} }" `; @@ -30,8 +30,8 @@ exports[`transform > reconstruct rest-prop 1`] = ` " import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props){ -const __MACROS_defaults_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 1}); -const rest = __MACROS_createPropsRestProxy(__MACROS_defaults_props, ['foo', 'bar']); - return <>{[__MACROS_defaults_props.foo, __MACROS_defaults_props.bar, rest]} +const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 1}); +const rest = __MACROS_createPropsRestProxy(__MACROS_default_props, ['foo', 'bar']); + return <>{[__MACROS_default_props.foo, __MACROS_default_props.bar, rest]} }" `; From 31a31d6fbe612064e2beab343c7e631ff0a090d6 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 18 Oct 2024 01:16:57 +0800 Subject: [PATCH 047/156] feat: support await --- .../src/core/define-component/await.ts | 94 +++++++++++++++++++ .../src/core/define-component/index.ts | 66 +++++++------ .../tests/__snapshots__/fixtures.test.ts.snap | 22 ++++- .../tests/fixtures/define-component.tsx | 10 +- 4 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 packages/jsx-macros/src/core/define-component/await.ts diff --git a/packages/jsx-macros/src/core/define-component/await.ts b/packages/jsx-macros/src/core/define-component/await.ts new file mode 100644 index 000000000..2f1655eec --- /dev/null +++ b/packages/jsx-macros/src/core/define-component/await.ts @@ -0,0 +1,94 @@ +// Modified from: https://github.com/vuejs/core/blob/main/packages/compiler-sfc/src/script/topLevelAwait.ts + +import { + importHelperFn, + walkAST, + type MagicStringAST, +} from '@vue-macros/common' +import { isFunctionType } from '@vue/compiler-core' +import type { FunctionalNode } from '..' +import type { AwaitExpression, Node, Statement } from '@babel/types' + +function processAwait( + s: MagicStringAST, + node: AwaitExpression, + needSemi: boolean, + isStatement: boolean, +): void { + const argumentStart = + node.argument.extra && node.argument.extra.parenthesized + ? (node.argument.extra.parenStart as number) + : node.argument.start! + + const argumentStr = s.slice(argumentStart, node.argument.end!) + + const containsNestedAwait = /\bawait\b/.test(argumentStr) + + s.overwrite( + node.start!, + argumentStart, + `${needSemi ? `;` : ``}(\n ([__temp,__restore] = ${importHelperFn( + s, + 0, + `withAsyncContext`, + 'vue', + )}(${containsNestedAwait ? `async ` : ``}() => `, + ) + s.appendLeft( + node.end!, + `)),\n ${isStatement ? `` : `__temp = `}await __temp,\n __restore()${ + isStatement ? `` : `,\n __temp` + }\n)`, + ) +} + +export function transformAwait(root: FunctionalNode, s: MagicStringAST): void { + if (root.body.type !== 'BlockStatement') return + let hasAwait = false + for (const node of root.body.body) { + if ( + (node.type === 'VariableDeclaration' && !node.declare) || + node.type.endsWith('Statement') + ) { + const scope: Statement[][] = [root.body.body] + walkAST(node, { + enter(child, parent) { + if (isFunctionType(child)) { + this.skip() + } + if (child.type === 'BlockStatement') { + scope.push(child.body) + } + if (child.type === 'AwaitExpression') { + hasAwait = true + // if the await expression is an expression statement and + // - is in the root scope + // - or is not the first statement in a nested block scope + // then it needs a semicolon before the generated code. + const currentScope = scope.at(-1) + const needsSemi = !!currentScope?.some((n, i) => { + return ( + (scope.length === 1 || i > 0) && + n.type === 'ExpressionStatement' && + n.start === child.start + ) + }) + processAwait( + s, + child, + needsSemi, + parent!.type === 'ExpressionStatement', + ) + } + }, + leave(node: Node) { + if (node.type === 'BlockStatement') scope.pop() + }, + }) + } + } + + if (hasAwait) { + s.prependLeft(root.body.start! + 1, `\nlet __temp, __restore\n`) + } +} diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 68f66e579..6f904df50 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,6 +1,7 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' import type { FunctionalNode, RootMapValue } from '..' +import { transformAwait } from './await' import { restructure } from './restructure' function getWalkedIds(root: FunctionalNode, propsName: string) { @@ -27,6 +28,39 @@ function getWalkedIds(root: FunctionalNode, propsName: string) { return walkedIds } +// Auto add `() => ` for return statement +function transformReturn(root: FunctionalNode, s: MagicStringAST, lib: string) { + if (lib === 'vue') { + if (root.body.type === 'BlockStatement') { + const returnStatement = root.body.body.find( + (node) => node.type === 'ReturnStatement', + ) + if ( + returnStatement && + returnStatement.argument && + !( + returnStatement.argument?.type === 'ArrowFunctionExpression' || + returnStatement.argument?.type === 'FunctionExpression' + ) + ) { + s.appendRight( + returnStatement.argument.extra?.parenthesized + ? (returnStatement.argument.extra.parenStart as number) + : returnStatement.argument.start!, + '() => ', + ) + } + } else { + s.appendRight( + root.body.extra?.parenthesized + ? (root.body.extra.parenStart as number) + : root.body.start!, + '() => ', + ) + } + } +} + export function transformDefineComponent( root: FunctionalNode, propsName: string, @@ -113,34 +147,6 @@ export function transformDefineComponent( } } - // Auto add `() => ` for return statement - if (lib === 'vue') { - if (root.body.type === 'BlockStatement') { - const returnStatement = root.body.body.find( - (node) => node.type === 'ReturnStatement', - ) - if ( - returnStatement && - returnStatement.argument && - !( - returnStatement.argument?.type === 'ArrowFunctionExpression' || - returnStatement.argument?.type === 'FunctionExpression' - ) - ) { - s.appendRight( - returnStatement.argument.extra?.parenthesized - ? (returnStatement.argument.extra.parenStart as number) - : returnStatement.argument.start!, - '() => ', - ) - } - } else { - s.appendRight( - root.body.extra?.parenthesized - ? (root.body.extra.parenStart as number) - : root.body.start!, - '() => ', - ) - } - } + transformAwait(root, s) + transformReturn(root, s, lib) } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 2778a7e81..9ee73d3aa 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -5,7 +5,8 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";import { defineComponent } from 'vue' +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; +import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' const Comp = __MACROS_defineComponent( (__MACROS_props) => { @@ -29,6 +30,25 @@ const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar']]}
}, { props: { bar: null, 'foo': null, 'onUpdate:foo': null } }) + +const Comp2 = __MACROS_defineComponent(async (__MACROS_props) => { +let __temp, __restore + + ;( + ([__temp,__restore] = __MACROS_withAsyncContext(() => nextTick())), + await __temp, + __restore() +) + let foo = ( + ([__temp,__restore] = __MACROS_withAsyncContext(() => new Promise((resolve) => { + setTimeout(() => resolve('foo'), 1000) + }))), + __temp = await __temp, + __restore(), + __temp +) + return () =>
{foo}
+}) " `; diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index bde33c474..b38ccd5f3 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue' +import { defineComponent, nextTick } from 'vue' const Comp = defineComponent( ({ bar = 'bar'!, ...props }: { bar: 'bar'; baz: 'baz' }) => { @@ -18,3 +18,11 @@ const Comp1 = defineComponent((props: { bar: 'bar' }) => { const foo = defineModel('foo') return
{[foo.value, props['bar']]}
}) + +const Comp2 = defineComponent(async () => { + await nextTick() + let foo = await new Promise((resolve) => { + setTimeout(() => resolve('foo'), 1000) + }) + return
{foo}
+}) From f24e17ee9982b43b44b82a9fc6d6e1b440dd0d84 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 19 Oct 2024 16:34:17 +0800 Subject: [PATCH 048/156] feat: add define-style macro --- packages/jsx-macros/package.json | 2 + packages/jsx-macros/src/core/define-style.ts | 110 ++++++++++++++++++ packages/jsx-macros/src/core/index.ts | 32 +++-- packages/jsx-macros/src/core/style.ts | 19 +++ packages/jsx-macros/src/index.ts | 80 +++++++++---- .../tests/__snapshots__/fixtures.test.ts.snap | 25 ++++ packages/jsx-macros/tests/fixtures.test.ts | 4 + .../tests/fixtures/define-style.tsx | 31 +++++ packages/volar/src/jsx-macros.ts | 34 +++--- .../vue3/src/examples/jsx-macros/comp.tsx | 13 ++- pnpm-lock.yaml | 43 +++---- 11 files changed, 320 insertions(+), 73 deletions(-) create mode 100644 packages/jsx-macros/src/core/define-style.ts create mode 100644 packages/jsx-macros/src/core/style.ts create mode 100644 packages/jsx-macros/tests/fixtures/define-style.tsx diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 21ef2debc..423d064a5 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -130,9 +130,11 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue/compiler-core": "catalog:", + "hash-sum": "^2.0.0", "unplugin": "catalog:" }, "devDependencies": { + "@types/hash-sum": "^1.0.2", "vue": "catalog:" }, "engines": { diff --git a/packages/jsx-macros/src/core/define-style.ts b/packages/jsx-macros/src/core/define-style.ts new file mode 100644 index 000000000..ef1e3b711 --- /dev/null +++ b/packages/jsx-macros/src/core/define-style.ts @@ -0,0 +1,110 @@ +import { walkAST, type MagicStringAST } from '@vue-macros/common' +import hash from 'hash-sum' +import type { OptionsResolved } from '..' +import { helperPrefix } from './helper' +import { isFunctionalNode, type FunctionalNode } from '.' +import type { CallExpression, Node } from '@babel/types' + +export function transformDefineStyle( + node: CallExpression, + root: FunctionalNode, + defineStyleIndex: number, + s: MagicStringAST, + options: OptionsResolved, +): void { + if (node.arguments[0]?.type !== 'TemplateLiteral') return + + let css = s.sliceNode(node.arguments[0]).slice(1, -1) + const scopeId = hash(css) + const vars = new Map() + node.arguments[0].expressions.forEach((expression) => { + const cssVar = s.sliceNode(expression) + const cssVarId = toCssVarId(cssVar, `--${scopeId}-`) + s.overwrite(expression.start! - 2, expression.end! + 1, `var(${cssVarId})`) + vars.set(cssVarId, cssVar) + }) + + let returnExpression = getReturnStatement(root) + if (isFunctionalNode(returnExpression)) { + returnExpression = getReturnStatement(returnExpression) + } + if (vars.size && returnExpression) { + const children = + returnExpression.type === 'JSXElement' + ? [returnExpression] + : returnExpression.type === 'JSXFragment' + ? returnExpression.children + : [] + const varString = Array.from(vars.entries()) + .map(([key, value]) => `'${key}': ${value}`) + .join(', ') + for (const child of children) { + if (child.type === 'JSXElement') { + s.appendRight( + child.openingElement.name.end!, + ` {...{style:{${varString}}}}`, + ) + } + } + } + + let lang = options.defineStyle.lang + let scoped = false + if (node.arguments[1]?.type === 'ObjectExpression') { + for (const prop of node.arguments[1].properties) { + if (prop.type === 'ObjectProperty' && prop.key.type === 'Identifier') { + if (prop.key.name === 'lang' && prop.value.type === 'StringLiteral') { + lang = prop.value.value + } else if ( + prop.key.name === 'scoped' && + prop.value.type === 'BooleanLiteral' + ) { + scoped = prop.value.value + } + } + } + } + + if (scoped && returnExpression) { + walkAST(returnExpression, { + enter(node) { + if ( + node.type === 'JSXElement' && + s.sliceNode(node.openingElement.name) !== 'template' + ) { + s.appendRight(node.openingElement.name.end!, ` data-v-${scopeId}=""`) + } + }, + }) + } + + css = s.sliceNode(node.arguments[0]).slice(1, -1) + const importId = `${helperPrefix}/define-style?index=${defineStyleIndex}&scopeId=${scopeId}&scoped=${scoped}&lang.${lang}` + options.importMap.set(importId, css) + s.appendLeft(0, `import "${importId}";`) + s.removeNode(node) +} + +function getReturnStatement(root: FunctionalNode) { + if (root.body.type === 'BlockStatement') { + const returnStatement = root.body.body.find( + (node) => node.type === 'ReturnStatement', + ) + if (returnStatement) { + return returnStatement.argument + } + } else { + return root.body + } +} + +function toCssVarId(name: string, prefix = '') { + return ( + prefix + + name.replaceAll(/\W/g, (searchValue, replaceValue) => { + return searchValue === '.' + ? '-' + : name.charCodeAt(replaceValue).toString() + }) + ) +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index e3ed82b6b..2f155bc3e 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -12,6 +12,7 @@ import { transformDefineComponent } from './define-component' import { transformDefineExpose } from './define-expose' import { transformDefineModel } from './define-model' import { transformDefineSlots } from './define-slots' +import { transformDefineStyle } from './define-style' import type { ArrowFunctionExpression, CallExpression, @@ -25,14 +26,25 @@ export type FunctionalNode = | FunctionExpression | ArrowFunctionExpression -function getMacroExpression(node?: Node | null) { +export function isFunctionalNode(node?: Node | null): node is FunctionalNode { + return !!( + node && + (node.type === 'ArrowFunctionExpression' || + node.type === 'FunctionDeclaration' || + node.type === 'FunctionExpression') + ) +} + +export function getMacroExpression(node?: Node | null): CallExpression | false { if (node?.type === 'TSNonNullExpression') { node = node.expression } return ( node?.type === 'CallExpression' && node.callee.type === 'Identifier' && - ['defineSlots', 'defineModel', 'defineExpose'].includes(node.callee.name) && + ['defineSlots', 'defineModel', 'defineExpose', 'defineStyle'].includes( + node.callee.name, + ) && node ) } @@ -45,6 +57,7 @@ export type RootMapValue = { }[] defineSlots?: CallExpression defineExpose?: CallExpression + defineStyle?: CallExpression[] } function getRootMap(s: MagicStringAST, id: string) { @@ -54,12 +67,7 @@ function getRootMap(s: MagicStringAST, id: string) { enter(node, parent) { parents.unshift(parent) const root = - parents[1] && - (parents[1].type === 'ArrowFunctionExpression' || - parents[1].type === 'FunctionDeclaration' || - parents[1].type === 'FunctionExpression') - ? parents[1] - : undefined + parents[1] && isFunctionalNode(parents[1]) ? parents[1] : undefined if (!root) return if ( @@ -88,6 +96,8 @@ function getRootMap(s: MagicStringAST, id: string) { expression: macroExpression, isRequired: expression?.type === 'TSNonNullExpression', }) + } else if (macroName === 'defineStyle') { + ;(rootMap.get(root)![macroName] ??= []).push(macroExpression) } else if ( macroName === 'defineSlots' || macroName === 'defineExpose' @@ -119,6 +129,7 @@ export function transformJsxMacros( ): CodeTransform | undefined { const s = new MagicStringAST(code) const rootMap = getRootMap(s, id) + let defineStyleIndex = 0 for (const [root, map] of rootMap) { let propsName = `${HELPER_PREFIX}props` @@ -159,6 +170,11 @@ export function transformJsxMacros( if (map.defineExpose) { transformDefineExpose(map.defineExpose, root, s, options.lib) } + if (map.defineStyle?.length) { + map.defineStyle.forEach((node) => { + transformDefineStyle(node, root, defineStyleIndex++, s, options) + }) + } } return generateTransform(s, id) diff --git a/packages/jsx-macros/src/core/style.ts b/packages/jsx-macros/src/core/style.ts new file mode 100644 index 000000000..f936f94b9 --- /dev/null +++ b/packages/jsx-macros/src/core/style.ts @@ -0,0 +1,19 @@ +import { compileStyleAsync } from 'vue/compiler-sfc' +import type { OptionsResolved } from '..' + +export async function transformStyle( + code: string, + id: string, + options: OptionsResolved, +): Promise { + const query = new URLSearchParams(id.split('?')[1]) as any + const result = await compileStyleAsync({ + filename: id, + id: `data-v-${query.get('scopeId')}`, + isProd: options.isProduction, + source: code, + scoped: query.get('scoped') === 'true', + }) + + return result.code +} diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index e1552a8f7..5794b42e4 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -24,14 +24,26 @@ import { withDefaultsCode, withDefaultsHelperId, } from './core/helper' +import { transformStyle } from './core/style' export type Options = BaseOptions & { lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + defineStyle?: { + lang?: + | 'css' + | 'postcss' + | 'scss' + | 'sass' + | 'less' + | 'stylus' + | (string & {}) + scoped?: boolean + } } export type OptionsResolved = MarkRequired< Options, - 'include' | 'version' | 'lib' -> + 'include' | 'version' | 'lib' | 'defineStyle' +> & { importMap: Map } function resolveOptions( options: Options, @@ -40,10 +52,14 @@ function resolveOptions( const version = options.version || detectVueVersion() const lib = options.lib || 'vue' const include = getFilterPattern([FilterFileType.SRC_FILE], framework) + const defineStyle = options.defineStyle || {} + defineStyle.lang ??= 'css' return { include, exclude: [REGEX_SETUP_SFC], ...options, + importMap: new Map(), + defineStyle, version, lib, } @@ -51,33 +67,53 @@ function resolveOptions( const name = generatePluginName() -const plugin: UnpluginInstance = createUnplugin( +const plugin: UnpluginInstance = createUnplugin( (userOptions = {}, { framework }) => { const options = resolveOptions(userOptions, framework) const filter = createFilter(options) - return { - name, - enforce: 'pre', + return [ + { + name, + enforce: 'pre', - resolveId(id) { - if (normalizePath(id).startsWith(helperPrefix)) return id - }, - loadInclude(id) { - return normalizePath(id).startsWith(helperPrefix) - }, - load(_id) { - const id = normalizePath(_id) - if (id === useExposeHelperId) return useExposeHelperCode - else if (id === useModelHelperId) return useModelHelperCode - else if (id === withDefaultsHelperId) return withDefaultsCode - }, + resolveId(id) { + if (normalizePath(id).startsWith(helperPrefix)) return id + }, + loadInclude(id) { + return normalizePath(id).startsWith(helperPrefix) + }, + load(_id) { + const id = normalizePath(_id) + if (id === useExposeHelperId) return useExposeHelperCode + else if (id === useModelHelperId) return useModelHelperCode + else if (id === withDefaultsHelperId) return withDefaultsCode + }, - transformInclude: filter, - transform(code, id) { - return transformJsxMacros(code, id, options) + transformInclude: filter, + transform(code, id) { + if (options.importMap.get(id)) return + return transformJsxMacros(code, id, options) + }, + }, + { + name: 'unplugin-define-style', + transformInclude: createFilter({ + include: [new RegExp(`^${helperPrefix}/define-style`)], + }), + loadInclude(id) { + return normalizePath(id).startsWith(helperPrefix) + }, + load(_id) { + const id = normalizePath(_id) + if (options.importMap.get(id)) return options.importMap.get(id) + }, + transform(code: string, id: string) { + if (options.importMap.get(id)) + return transformStyle(code, id, options) + }, }, - } + ] }, ) export default plugin diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 9ee73d3aa..08fc35a69 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -100,6 +100,31 @@ export default function (__MACROS_props) { " `; +exports[`fixtures > ./fixtures/define-style.tsx 1`] = ` +"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=false&lang.scss"; +import { defineComponent as __MACROS_defineComponent } from "vue";import "/vue-macros/jsx-macros/define-style?index=1&scopeId=102189c6&scoped=true&lang.scss";import { defineComponent, ref } from 'vue' + +export const Comp = (__MACROS_props) => { + const color = ref('red') + + return
foo
+} + +export default __MACROS_defineComponent((__MACROS_props) => { + const color = ref('red') + + return () => ( + <> +
foo
+
+ bar +
+ + ) +}) +" +`; + exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { forwardRef as __MACROS_forwardRef } from "react"; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index 4bf696646..f2a8e2433 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -13,6 +13,8 @@ describe('fixtures', async () => { lib: 'vue', include: ['*.tsx'], version: 3.5, + defineStyle: { lang: 'scss' }, + importMap: new Map(), })?.code, ) }) @@ -28,6 +30,8 @@ describe('react fixtures', async () => { lib: 'react', include: ['*.tsx'], version: 18, + defineStyle: { lang: 'scss' }, + importMap: new Map(), })?.code, ) }) diff --git a/packages/jsx-macros/tests/fixtures/define-style.tsx b/packages/jsx-macros/tests/fixtures/define-style.tsx new file mode 100644 index 000000000..bdeef9f5f --- /dev/null +++ b/packages/jsx-macros/tests/fixtures/define-style.tsx @@ -0,0 +1,31 @@ +import { defineComponent, ref } from 'vue' + +export const Comp = () => { + const color = ref('red') + defineStyle(` + .foo { + color: ${color.value}; + } + `) + return
foo
+} + +export default defineComponent(() => { + const color = ref('red') + defineStyle( + ` + .bar { + color: ${color.value}; + } + `, + { scoped: true }, + ) + return () => ( + <> +
foo
+
+ bar +
+ + ) +}) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 6de2c88be..e5507a2f1 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -75,6 +75,7 @@ function getMacro( ...vueCompilerOptions.macros.defineModel, ...vueCompilerOptions.macros.defineExpose, ...vueCompilerOptions.macros.defineSlots, + 'defineStyle', ].includes(node.expression.escapedText!) && node ) @@ -307,21 +308,6 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { } }) } - - if ( - rootMap.size && - !codes.toString().includes(`declare function defineSlots`) - ) { - codes.push( - ` -const { defineModel } = await import('vue') -declare function defineSlots>(slots?: T): T; -declare function defineExpose = Record>(exposed?: Exposed): Exposed; -declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T -declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; -`, - ) - } } const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { @@ -347,6 +333,24 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { } const rootMap = getRootMap(options, ctx.vueCompilerOptions) if (rootMap.size) transformJsxMacros(rootMap, options) + + if ( + (fileName.endsWith('.tsx') || rootMap.size) && + !embeddedFile.content + .toString() + .includes(`declare function defineSlots`) + ) { + embeddedFile.content.push( + ` +const { defineModel } = await import('vue') +declare function defineSlots>(slots?: T): T; +declare function defineExpose = Record>(exposed?: Exposed): Exposed; +declare function defineStyle(styles: string, options?: { lang?: 'css' | 'scss' | 'sass' | 'less' | 'stylus' | 'postcss' | (string & {}), scoped?: boolean }); +declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T +declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; + `, + ) + } } }, } diff --git a/playground/vue3/src/examples/jsx-macros/comp.tsx b/playground/vue3/src/examples/jsx-macros/comp.tsx index 4cf572d64..36ab31c65 100644 --- a/playground/vue3/src/examples/jsx-macros/comp.tsx +++ b/playground/vue3/src/examples/jsx-macros/comp.tsx @@ -1,4 +1,4 @@ -import { watch } from 'vue' +import { ref, watch } from 'vue' export const Comp = defineComponent(function ({ foo }: { foo: T }) { const slots = defineSlots({ @@ -28,8 +28,17 @@ export const Comp = defineComponent(function ({ foo }: { foo: T }) { foo, }) + const color = ref('green') + defineStyle(` + .foo { + color: ${color.value}; + } + `) + return ( -
+
+ color: +
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 818f34ed9..8df0e438a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -664,10 +664,19 @@ importers: '@vue/compiler-core': specifier: 'catalog:' version: 3.5.12 + '@vue/compiler-sfc': + specifier: 'catalog:' + version: 3.5.12 + hash-sum: + specifier: ^2.0.0 + version: 2.0.0 unplugin: specifier: 'catalog:' version: 1.14.1(webpack-sources@3.2.3) devDependencies: + '@types/hash-sum': + specifier: ^1.0.2 + version: 1.0.2 vue: specifier: 'catalog:' version: 3.5.12(typescript@5.6.2) @@ -2598,6 +2607,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/hash-sum@1.0.2': + resolution: {integrity: sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -2945,15 +2957,9 @@ packages: '@vue/compiler-sfc@2.7.16': resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==} - '@vue/compiler-sfc@3.5.11': - resolution: {integrity: sha512-gsbBtT4N9ANXXepprle+X9YLg2htQk1sqH/qGJ/EApl+dgpUBdTv3yP7YlR535uHZY3n6XaR0/bKo0BgwwDniw==} - '@vue/compiler-sfc@3.5.12': resolution: {integrity: sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==} - '@vue/compiler-ssr@3.5.11': - resolution: {integrity: sha512-P4+GPjOuC2aFTk1Z4WANvEhyOykcvEd5bIj2KVNGKGfM745LaXGr++5njpdBTzVz5pZifdlR1kpYSJJpIlSePA==} - '@vue/compiler-ssr@3.5.12': resolution: {integrity: sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==} @@ -6666,7 +6672,7 @@ snapshots: dependencies: '@vitejs/plugin-vue': 5.1.4(vite@5.4.9(@types/node@22.7.5)(less@4.2.0)(terser@5.34.1))(vue@3.5.12(typescript@5.6.2)) '@vitejs/plugin-vue-jsx': 4.0.1(vite@5.4.9(@types/node@22.7.5)(less@4.2.0)(terser@5.34.1))(vue@3.5.12(typescript@5.6.2)) - '@vue/compiler-sfc': 3.5.11 + '@vue/compiler-sfc': 3.5.12 astro: 4.16.3(@types/node@22.7.5)(less@4.2.0)(rollup@4.24.0)(terser@5.34.1)(typescript@5.6.2) vite-plugin-vue-devtools: 7.4.6(@nuxt/kit@3.13.2(magicast@0.3.5)(rollup@4.24.0)(webpack-sources@3.2.3))(rollup@4.24.0)(vite@5.4.9(@types/node@22.7.5)(less@4.2.0)(terser@5.34.1))(vue@3.5.12(typescript@5.6.2)) vue: 3.5.12(typescript@5.6.2) @@ -8347,6 +8353,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/hash-sum@1.0.2': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -8786,7 +8794,7 @@ snapshots: '@babel/helper-module-imports': 7.25.7 '@babel/helper-plugin-utils': 7.25.7 '@babel/parser': 7.25.8 - '@vue/compiler-sfc': 3.5.11 + '@vue/compiler-sfc': 3.5.12 transitivePeerDependencies: - supports-color @@ -8893,18 +8901,6 @@ snapshots: optionalDependencies: prettier: 2.8.8 - '@vue/compiler-sfc@3.5.11': - dependencies: - '@babel/parser': 7.25.8 - '@vue/compiler-core': 3.5.11 - '@vue/compiler-dom': 3.5.11 - '@vue/compiler-ssr': 3.5.11 - '@vue/shared': 3.5.11 - estree-walker: 2.0.2 - magic-string: 0.30.12 - postcss: 8.4.47 - source-map-js: 1.2.1 - '@vue/compiler-sfc@3.5.12': dependencies: '@babel/parser': 7.25.8 @@ -8917,11 +8913,6 @@ snapshots: postcss: 8.4.47 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.11': - dependencies: - '@vue/compiler-dom': 3.5.11 - '@vue/shared': 3.5.11 - '@vue/compiler-ssr@3.5.12': dependencies: '@vue/compiler-dom': 3.5.12 @@ -12791,7 +12782,7 @@ snapshots: '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.7) '@babel/plugin-transform-typescript': 7.25.7(@babel/core@7.25.7) '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.25.7) - '@vue/compiler-dom': 3.5.11 + '@vue/compiler-dom': 3.5.12 kolorist: 1.8.0 magic-string: 0.30.12 vite: 5.4.9(@types/node@22.7.5)(less@4.2.0)(terser@5.34.1) From 8b555cf64e6c478473f10c7a815db10a675231b2 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 19 Oct 2024 17:34:12 +0800 Subject: [PATCH 049/156] fix: ci --- pnpm-lock.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8df0e438a..2a243318c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -664,9 +664,6 @@ importers: '@vue/compiler-core': specifier: 'catalog:' version: 3.5.12 - '@vue/compiler-sfc': - specifier: 'catalog:' - version: 3.5.12 hash-sum: specifier: ^2.0.0 version: 2.0.0 From 941ab85190af1668f5857a8f7ad96bb2d2a93433 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 22 Oct 2024 10:19:16 +0800 Subject: [PATCH 050/156] refactor: defineStyle --- packages/jsx-macros/src/core/define-style.ts | 29 ++++---- packages/jsx-macros/src/core/index.ts | 66 +++++++++++++------ packages/jsx-macros/src/index.ts | 29 ++------ .../tests/__snapshots__/fixtures.test.ts.snap | 8 ++- packages/jsx-macros/tests/fixtures.test.ts | 8 +-- .../tests/fixtures/define-style.tsx | 8 ++- packages/volar/src/jsx-macros.ts | 3 +- 7 files changed, 83 insertions(+), 68 deletions(-) diff --git a/packages/jsx-macros/src/core/define-style.ts b/packages/jsx-macros/src/core/define-style.ts index ef1e3b711..f1cb8a5c5 100644 --- a/packages/jsx-macros/src/core/define-style.ts +++ b/packages/jsx-macros/src/core/define-style.ts @@ -1,16 +1,16 @@ import { walkAST, type MagicStringAST } from '@vue-macros/common' import hash from 'hash-sum' -import type { OptionsResolved } from '..' import { helperPrefix } from './helper' import { isFunctionalNode, type FunctionalNode } from '.' import type { CallExpression, Node } from '@babel/types' export function transformDefineStyle( node: CallExpression, - root: FunctionalNode, + lang: string, + root: FunctionalNode | undefined, defineStyleIndex: number, s: MagicStringAST, - options: OptionsResolved, + importMap: Map, ): void { if (node.arguments[0]?.type !== 'TemplateLiteral') return @@ -24,7 +24,7 @@ export function transformDefineStyle( vars.set(cssVarId, cssVar) }) - let returnExpression = getReturnStatement(root) + let returnExpression = root && getReturnStatement(root) if (isFunctionalNode(returnExpression)) { returnExpression = getReturnStatement(returnExpression) } @@ -48,19 +48,16 @@ export function transformDefineStyle( } } - let lang = options.defineStyle.lang - let scoped = false + let scoped = !!root if (node.arguments[1]?.type === 'ObjectExpression') { for (const prop of node.arguments[1].properties) { - if (prop.type === 'ObjectProperty' && prop.key.type === 'Identifier') { - if (prop.key.name === 'lang' && prop.value.type === 'StringLiteral') { - lang = prop.value.value - } else if ( - prop.key.name === 'scoped' && - prop.value.type === 'BooleanLiteral' - ) { - scoped = prop.value.value - } + if ( + prop.type === 'ObjectProperty' && + prop.key.type === 'Identifier' && + prop.key.name === 'scoped' && + prop.value.type === 'BooleanLiteral' + ) { + scoped = prop.value.value } } } @@ -80,7 +77,7 @@ export function transformDefineStyle( css = s.sliceNode(node.arguments[0]).slice(1, -1) const importId = `${helperPrefix}/define-style?index=${defineStyleIndex}&scopeId=${scopeId}&scoped=${scoped}&lang.${lang}` - options.importMap.set(importId, css) + importMap.set(importId, css) s.appendLeft(0, `import "${importId}";`) s.removeNode(node) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 2f155bc3e..4e2176ecf 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -35,18 +35,29 @@ export function isFunctionalNode(node?: Node | null): node is FunctionalNode { ) } -export function getMacroExpression(node?: Node | null): CallExpression | false { +export function getMacroExpression( + node: Node | null | undefined, +): CallExpression | undefined { if (node?.type === 'TSNonNullExpression') { node = node.expression } - return ( - node?.type === 'CallExpression' && - node.callee.type === 'Identifier' && - ['defineSlots', 'defineModel', 'defineExpose', 'defineStyle'].includes( - node.callee.name, - ) && - node - ) + + if (node?.type === 'CallExpression') { + if ( + node.callee.type === 'MemberExpression' && + node.callee.object.type === 'Identifier' && + node.callee.object.name === 'defineStyle' + ) { + return node + } else if ( + node.callee.type === 'Identifier' && + ['defineSlots', 'defineModel', 'defineExpose', 'defineStyle'].includes( + node.callee.name!, + ) + ) { + return node + } + } } export type RootMapValue = { @@ -57,18 +68,20 @@ export type RootMapValue = { }[] defineSlots?: CallExpression defineExpose?: CallExpression - defineStyle?: CallExpression[] + defineStyle?: { + expression: CallExpression + lang: string + }[] } function getRootMap(s: MagicStringAST, id: string) { const parents: (Node | undefined | null)[] = [] - const rootMap = new Map() + const rootMap = new Map() walkAST(babelParse(s.original, getLang(id)), { enter(node, parent) { parents.unshift(parent) const root = parents[1] && isFunctionalNode(parents[1]) ? parents[1] : undefined - if (!root) return if ( parents[2]?.type === 'CallExpression' && @@ -96,8 +109,12 @@ function getRootMap(s: MagicStringAST, id: string) { expression: macroExpression, isRequired: expression?.type === 'TSNonNullExpression', }) - } else if (macroName === 'defineStyle') { - ;(rootMap.get(root)![macroName] ??= []).push(macroExpression) + } else if (macroName.startsWith('defineStyle')) { + const [, lang = 'css'] = macroName.split('.') + ;(rootMap.get(root)!.defineStyle ??= []).push({ + expression: macroExpression, + lang, + }) } else if ( macroName === 'defineSlots' || macroName === 'defineExpose' @@ -125,6 +142,7 @@ export function getParamsStart(node: FunctionalNode, code: string): number { export function transformJsxMacros( code: string, id: string, + importMap: Map, options: OptionsResolved, ): CodeTransform | undefined { const s = new MagicStringAST(code) @@ -132,6 +150,21 @@ export function transformJsxMacros( let defineStyleIndex = 0 for (const [root, map] of rootMap) { + if (map.defineStyle?.length) { + map.defineStyle.forEach(({ expression, lang }) => { + transformDefineStyle( + expression, + lang, + root, + defineStyleIndex++, + s, + importMap, + ) + }) + } + + if (root === undefined) continue + let propsName = `${HELPER_PREFIX}props` if (root.params[0]) { if (root.params[0].type === 'Identifier') { @@ -170,11 +203,6 @@ export function transformJsxMacros( if (map.defineExpose) { transformDefineExpose(map.defineExpose, root, s, options.lib) } - if (map.defineStyle?.length) { - map.defineStyle.forEach((node) => { - transformDefineStyle(node, root, defineStyleIndex++, s, options) - }) - } } return generateTransform(s, id) diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 5794b42e4..6159f7a17 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -28,22 +28,11 @@ import { transformStyle } from './core/style' export type Options = BaseOptions & { lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' - defineStyle?: { - lang?: - | 'css' - | 'postcss' - | 'scss' - | 'sass' - | 'less' - | 'stylus' - | (string & {}) - scoped?: boolean - } } export type OptionsResolved = MarkRequired< Options, - 'include' | 'version' | 'lib' | 'defineStyle' -> & { importMap: Map } + 'include' | 'version' | 'lib' +> function resolveOptions( options: Options, @@ -52,14 +41,10 @@ function resolveOptions( const version = options.version || detectVueVersion() const lib = options.lib || 'vue' const include = getFilterPattern([FilterFileType.SRC_FILE], framework) - const defineStyle = options.defineStyle || {} - defineStyle.lang ??= 'css' return { include, exclude: [REGEX_SETUP_SFC], ...options, - importMap: new Map(), - defineStyle, version, lib, } @@ -71,6 +56,7 @@ const plugin: UnpluginInstance = createUnplugin( (userOptions = {}, { framework }) => { const options = resolveOptions(userOptions, framework) const filter = createFilter(options) + const importMap = new Map() return [ { @@ -92,8 +78,8 @@ const plugin: UnpluginInstance = createUnplugin( transformInclude: filter, transform(code, id) { - if (options.importMap.get(id)) return - return transformJsxMacros(code, id, options) + if (importMap.get(id)) return + return transformJsxMacros(code, id, importMap, options) }, }, { @@ -106,11 +92,10 @@ const plugin: UnpluginInstance = createUnplugin( }, load(_id) { const id = normalizePath(_id) - if (options.importMap.get(id)) return options.importMap.get(id) + if (importMap.get(id)) return importMap.get(id) }, transform(code: string, id: string) { - if (options.importMap.get(id)) - return transformStyle(code, id, options) + if (importMap.get(id)) return transformStyle(code, id, options) }, }, ] diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 08fc35a69..2536c4548 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -101,13 +101,13 @@ export default function (__MACROS_props) { `; exports[`fixtures > ./fixtures/define-style.tsx 1`] = ` -"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=false&lang.scss"; -import { defineComponent as __MACROS_defineComponent } from "vue";import "/vue-macros/jsx-macros/define-style?index=1&scopeId=102189c6&scoped=true&lang.scss";import { defineComponent, ref } from 'vue' +"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=true&lang.css";import "/vue-macros/jsx-macros/define-style?index=1&scopeId=102189c6&scoped=true&lang.scss"; +import { defineComponent as __MACROS_defineComponent } from "vue";import "/vue-macros/jsx-macros/define-style?index=2&scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' export const Comp = (__MACROS_props) => { const color = ref('red') - return
foo
+ return
foo
} export default __MACROS_defineComponent((__MACROS_props) => { @@ -122,6 +122,8 @@ export default __MACROS_defineComponent((__MACROS_props) => { ) }) + + " `; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index f2a8e2433..e54c6da78 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -9,12 +9,10 @@ describe('fixtures', async () => { as: 'raw', }), (args, id, code) => - transformJsxMacros(code, id, { + transformJsxMacros(code, id, new Map(), { lib: 'vue', include: ['*.tsx'], version: 3.5, - defineStyle: { lang: 'scss' }, - importMap: new Map(), })?.code, ) }) @@ -26,12 +24,10 @@ describe('react fixtures', async () => { as: 'raw', }), (args, id, code) => - transformJsxMacros(code, id, { + transformJsxMacros(code, id, new Map(), { lib: 'react', include: ['*.tsx'], version: 18, - defineStyle: { lang: 'scss' }, - importMap: new Map(), })?.code, ) }) diff --git a/packages/jsx-macros/tests/fixtures/define-style.tsx b/packages/jsx-macros/tests/fixtures/define-style.tsx index bdeef9f5f..b1568161f 100644 --- a/packages/jsx-macros/tests/fixtures/define-style.tsx +++ b/packages/jsx-macros/tests/fixtures/define-style.tsx @@ -12,7 +12,7 @@ export const Comp = () => { export default defineComponent(() => { const color = ref('red') - defineStyle( + defineStyle.scss( ` .bar { color: ${color.value}; @@ -29,3 +29,9 @@ export default defineComponent(() => { ) }) + +defineStyle.scss(` + .bar { + color: red; + } +`) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index e5507a2f1..8cd3df56c 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -345,7 +345,8 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { const { defineModel } = await import('vue') declare function defineSlots>(slots?: T): T; declare function defineExpose = Record>(exposed?: Exposed): Exposed; -declare function defineStyle(styles: string, options?: { lang?: 'css' | 'scss' | 'sass' | 'less' | 'stylus' | 'postcss' | (string & {}), scoped?: boolean }); +type __VLS_DefineStyle = (style: string, options?: { scoped: boolean }) => void; +declare const defineStyle: { (style: string): void; scss: __VLS_DefineStyle; sass: __VLS_DefineStyle; stylus: __VLS_DefineStyle; less: __VLS_DefineStyle; postcss: __VLS_DefineStyle }; declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, From 5b28a773598dc0efe4684f5d515faa3c9a59ccbd Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 22 Oct 2024 10:42:37 +0800 Subject: [PATCH 051/156] feat: add options for default defineStyle --- packages/volar/src/jsx-macros.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 8cd3df56c..5cd33990c 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -345,8 +345,8 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { const { defineModel } = await import('vue') declare function defineSlots>(slots?: T): T; declare function defineExpose = Record>(exposed?: Exposed): Exposed; -type __VLS_DefineStyle = (style: string, options?: { scoped: boolean }) => void; -declare const defineStyle: { (style: string): void; scss: __VLS_DefineStyle; sass: __VLS_DefineStyle; stylus: __VLS_DefineStyle; less: __VLS_DefineStyle; postcss: __VLS_DefineStyle }; +type __VLS_DefineStyle = (style: string, options?: { scoped?: boolean }) => void; +declare const defineStyle: { (style: string, options?: { scoped?: boolean }): void; scss: __VLS_DefineStyle; sass: __VLS_DefineStyle; stylus: __VLS_DefineStyle; less: __VLS_DefineStyle; postcss: __VLS_DefineStyle }; declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, From 08105cd96e42bb4b2d5a396cd085223a5a5ad91c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 23 Oct 2024 12:59:42 +0800 Subject: [PATCH 052/156] feat: convert restProps to attrs --- .../src/core/define-component/index.ts | 25 ++++++++++++----- .../src/core/define-component/restructure.ts | 27 ++++++++++++------- .../tests/__snapshots__/fixtures.test.ts.snap | 9 +++---- .../tests/fixtures/define-component.tsx | 4 +-- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 6f904df50..feba01180 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -79,17 +79,30 @@ export function transformDefineComponent( if (root.params[0].type === 'Identifier') { getWalkedIds(root, propsName).forEach((id) => (props[id] = null)) } else { - for (const prop of restructure(s, root)) { - if (prop.path.endsWith('props')) { - if (prop.isRest) { - getWalkedIds(root, prop.name).forEach((id) => (props[id] = null)) - } else { - props[prop.name] = prop.isRequired ? '{ required: true }' : null + const restructuredProps = restructure(s, root, { + generateRestProps: (restPropsName, index, list) => { + if (index === list.length - 1) { + const getCurrentInstance = importHelperFn( + s, + 0, + 'getCurrentInstance', + 'vue', + ) + return [ + `${getCurrentInstance}().inheritAttrs=false`, + `const ${restPropsName} = ${getCurrentInstance}().setupContext.attrs`, + ].join(';') } + }, + }) + for (const prop of restructuredProps) { + if (prop.path.endsWith('props') && !prop.isRest) { + props[prop.name] = prop.isRequired ? '{ required: true }' : null } } } } + for (const { expression, isRequired } of map.defineModel || []) { const modelOptions = expression.arguments[0]?.type === 'ObjectExpression' diff --git a/packages/jsx-macros/src/core/define-component/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts index 161ea3326..2a845b7ef 100644 --- a/packages/jsx-macros/src/core/define-component/restructure.ts +++ b/packages/jsx-macros/src/core/define-component/restructure.ts @@ -116,7 +116,14 @@ export function prependFunctionalNode( export function restructure( s: MagicString, node: FunctionalNode, - withDefaultsFrom: string = withDefaultsHelperId, + options?: { + withDefaultsFrom?: string + generateRestProps?: ( + restPropsName: string, + index: number, + list: Prop[], + ) => string | undefined + }, ): Prop[] { let index = 0 const propList: Prop[] = [] @@ -154,7 +161,7 @@ export function restructure( s, 0, 'createPropsDefaultProxy', - withDefaultsFrom, + options?.withDefaultsFrom || withDefaultsHelperId, ) const resolvedPath = path.replace( `${HELPER_PREFIX}default_`, @@ -172,17 +179,17 @@ export function restructure( ) } - for (const prop of rests) { - const createPropsRestProxy = importHelperFn( - s, - 0, - 'createPropsRestProxy', - 'vue', - ) + for (const [index, rest] of rests.entries()) { prependFunctionalNode( node, s, - `\nconst ${prop.name} = ${createPropsRestProxy}(${prop.path}, [${prop.value}])`, + options?.generateRestProps?.(rest.name, index, rests) ?? + `\nconst ${rest.name} = ${importHelperFn( + s, + 0, + 'createPropsRestProxy', + 'vue', + )}(${rest.path}, [${rest.value}])`, ) } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 2536c4548..5fa9eca88 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -4,14 +4,13 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue"; +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue"; import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' const Comp = __MACROS_defineComponent( (__MACROS_props) => { -const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!}); -const props = __MACROS_createPropsRestProxy(__MACROS_default_props, ['bar']); +const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});__MACROS_getCurrentInstance().inheritAttrs=false;const attrs = __MACROS_getCurrentInstance().setupContext.attrs; const foo = __MACROS_useModel(__MACROS_props, 'foo', { validator: (value) => { return value === 'foo' @@ -19,9 +18,9 @@ const props = __MACROS_createPropsRestProxy(__MACROS_default_props, ['bar']); required: false, type: String, }) - return () =>
{[foo.value, __MACROS_default_props.bar, props.baz]}
+ return () =>
{[foo.value, __MACROS_default_props.bar, attrs.baz]}
}, - { inheritAttrs: false , props: { bar: { required: true }, baz: null, 'foo': { validator: (value) => { + { inheritAttrs: false , props: { bar: { required: true }, 'foo': { validator: (value) => { return value === 'foo' }, required: false, type: String }, 'onUpdate:foo': null }}, ) diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index b38ccd5f3..80fff49f9 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -1,7 +1,7 @@ import { defineComponent, nextTick } from 'vue' const Comp = defineComponent( - ({ bar = 'bar'!, ...props }: { bar: 'bar'; baz: 'baz' }) => { + ({ bar = 'bar'!, ...attrs }: { bar: 'bar'; baz: 'baz' }) => { const foo = defineModel('foo', { validator: (value) => { return value === 'foo' @@ -9,7 +9,7 @@ const Comp = defineComponent( required: false, type: String, }) - return
{[foo.value, bar, props.baz]}
+ return
{[foo.value, bar, attrs.baz]}
}, { inheritAttrs: false }, ) From cab08cde716667343188753d24be75e06e8fa054 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 23 Oct 2024 15:24:44 +0800 Subject: [PATCH 053/156] feat: use useAttrs instead of getCurrentInstance --- .../src/core/define-component/await.ts | 66 +++--- .../src/core/define-component/index.ts | 172 +++++++-------- .../src/core/define-component/restructure.ts | 192 ++++++++--------- packages/jsx-macros/src/core/index.ts | 198 +++++++++--------- .../tests/__snapshots__/fixtures.test.ts.snap | 8 +- .../tests/fixtures/define-component.tsx | 2 +- 6 files changed, 321 insertions(+), 317 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/await.ts b/packages/jsx-macros/src/core/define-component/await.ts index 2f1655eec..f9f1dcd78 100644 --- a/packages/jsx-macros/src/core/define-component/await.ts +++ b/packages/jsx-macros/src/core/define-component/await.ts @@ -9,39 +9,6 @@ import { isFunctionType } from '@vue/compiler-core' import type { FunctionalNode } from '..' import type { AwaitExpression, Node, Statement } from '@babel/types' -function processAwait( - s: MagicStringAST, - node: AwaitExpression, - needSemi: boolean, - isStatement: boolean, -): void { - const argumentStart = - node.argument.extra && node.argument.extra.parenthesized - ? (node.argument.extra.parenStart as number) - : node.argument.start! - - const argumentStr = s.slice(argumentStart, node.argument.end!) - - const containsNestedAwait = /\bawait\b/.test(argumentStr) - - s.overwrite( - node.start!, - argumentStart, - `${needSemi ? `;` : ``}(\n ([__temp,__restore] = ${importHelperFn( - s, - 0, - `withAsyncContext`, - 'vue', - )}(${containsNestedAwait ? `async ` : ``}() => `, - ) - s.appendLeft( - node.end!, - `)),\n ${isStatement ? `` : `__temp = `}await __temp,\n __restore()${ - isStatement ? `` : `,\n __temp` - }\n)`, - ) -} - export function transformAwait(root: FunctionalNode, s: MagicStringAST): void { if (root.body.type !== 'BlockStatement') return let hasAwait = false @@ -92,3 +59,36 @@ export function transformAwait(root: FunctionalNode, s: MagicStringAST): void { s.prependLeft(root.body.start! + 1, `\nlet __temp, __restore\n`) } } + +function processAwait( + s: MagicStringAST, + node: AwaitExpression, + needSemi: boolean, + isStatement: boolean, +): void { + const argumentStart = + node.argument.extra && node.argument.extra.parenthesized + ? (node.argument.extra.parenStart as number) + : node.argument.start! + + const argumentStr = s.slice(argumentStart, node.argument.end!) + + const containsNestedAwait = /\bawait\b/.test(argumentStr) + + s.overwrite( + node.start!, + argumentStart, + `${needSemi ? `;` : ``}(\n ([__temp,__restore] = ${importHelperFn( + s, + 0, + `withAsyncContext`, + 'vue', + )}(${containsNestedAwait ? `async ` : ``}() => `, + ) + s.appendLeft( + node.end!, + `)),\n ${isStatement ? `` : `__temp = `}await __temp,\n __restore()${ + isStatement ? `` : `,\n __temp` + }\n)`, + ) +} diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index feba01180..917406330 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -3,63 +3,7 @@ import { walkIdentifiers } from '@vue/compiler-core' import type { FunctionalNode, RootMapValue } from '..' import { transformAwait } from './await' import { restructure } from './restructure' - -function getWalkedIds(root: FunctionalNode, propsName: string) { - const walkedIds = new Set() - walkIdentifiers( - root.body, - (id, parent) => { - if ( - id.name === propsName && - (parent?.type === 'MemberExpression' || - parent?.type === 'OptionalMemberExpression') - ) { - const prop = - parent.property.type === 'Identifier' - ? parent.property.name - : parent.property.type === 'StringLiteral' - ? parent.property.value - : '' - if (prop) walkedIds.add(prop) - } - }, - false, - ) - return walkedIds -} - -// Auto add `() => ` for return statement -function transformReturn(root: FunctionalNode, s: MagicStringAST, lib: string) { - if (lib === 'vue') { - if (root.body.type === 'BlockStatement') { - const returnStatement = root.body.body.find( - (node) => node.type === 'ReturnStatement', - ) - if ( - returnStatement && - returnStatement.argument && - !( - returnStatement.argument?.type === 'ArrowFunctionExpression' || - returnStatement.argument?.type === 'FunctionExpression' - ) - ) { - s.appendRight( - returnStatement.argument.extra?.parenthesized - ? (returnStatement.argument.extra.parenStart as number) - : returnStatement.argument.start!, - '() => ', - ) - } - } else { - s.appendRight( - root.body.extra?.parenthesized - ? (root.body.extra.parenStart as number) - : root.body.start!, - '() => ', - ) - } - } -} +import type { ObjectExpression } from '@babel/types' export function transformDefineComponent( root: FunctionalNode, @@ -74,6 +18,7 @@ export function transformDefineComponent( importHelperFn(s, 0, 'defineComponent', 'vue'), ) + let hasRestProp = false const props: Record = {} if (root.params[0]) { if (root.params[0].type === 'Identifier') { @@ -82,16 +27,9 @@ export function transformDefineComponent( const restructuredProps = restructure(s, root, { generateRestProps: (restPropsName, index, list) => { if (index === list.length - 1) { - const getCurrentInstance = importHelperFn( - s, - 0, - 'getCurrentInstance', - 'vue', - ) - return [ - `${getCurrentInstance}().inheritAttrs=false`, - `const ${restPropsName} = ${getCurrentInstance}().setupContext.attrs`, - ].join(';') + hasRestProp = true + const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') + return `const ${restPropsName} = ${useAttrs}()` } }, }) @@ -139,27 +77,93 @@ export function transformDefineComponent( if (propsString) { const argument = map.defineComponent.arguments[1] if (!argument) { - s.appendRight(root.end!, `, { props: { ${propsString} } }`) - } else if ( - argument.type === 'ObjectExpression' && - !argument.properties?.find( - (prop) => - prop.type === 'ObjectProperty' && - prop.key.type === 'Identifier' && - prop.key.name === 'props', - ) - ) { - s.appendLeft( - argument.end! - 1, - `${ - !argument.extra?.trailingComma && argument.properties.length - ? ',' - : '' - } props: { ${propsString} }`, + s.appendRight( + root.end!, + `, {${hasRestProp ? 'inheritAttrs: false,' : ''} props: { ${propsString} } }`, ) + } else if (argument.type === 'ObjectExpression') { + prependObjectExpression(argument, 'props', `{ ${propsString} }`, s) + if (hasRestProp) { + prependObjectExpression(argument, 'inheritAttrs', 'false', s) + } } } transformAwait(root, s) transformReturn(root, s, lib) } + +function prependObjectExpression( + argument: ObjectExpression, + name: string, + value: string, + s: MagicStringAST, +) { + if ( + !argument.properties?.find( + (prop) => + prop.type === 'ObjectProperty' && + prop.key.type === 'Identifier' && + prop.key.name === name, + ) + ) { + s.appendRight(argument.start! + 1, `${name}: ${value},`) + } +} + +function getWalkedIds(root: FunctionalNode, propsName: string) { + const walkedIds = new Set() + walkIdentifiers( + root.body, + (id, parent) => { + if ( + id.name === propsName && + (parent?.type === 'MemberExpression' || + parent?.type === 'OptionalMemberExpression') + ) { + const prop = + parent.property.type === 'Identifier' + ? parent.property.name + : parent.property.type === 'StringLiteral' + ? parent.property.value + : '' + if (prop) walkedIds.add(prop) + } + }, + false, + ) + return walkedIds +} + +// Auto add `() => ` for return statement +function transformReturn(root: FunctionalNode, s: MagicStringAST, lib: string) { + if (lib === 'vue') { + if (root.body.type === 'BlockStatement') { + const returnStatement = root.body.body.find( + (node) => node.type === 'ReturnStatement', + ) + if ( + returnStatement && + returnStatement.argument && + !( + returnStatement.argument?.type === 'ArrowFunctionExpression' || + returnStatement.argument?.type === 'FunctionExpression' + ) + ) { + s.appendRight( + returnStatement.argument.extra?.parenthesized + ? (returnStatement.argument.extra.parenStart as number) + : returnStatement.argument.start!, + '() => ', + ) + } + } else { + s.appendRight( + root.body.extra?.parenthesized + ? (root.body.extra.parenStart as number) + : root.body.start!, + '() => ', + ) + } + } +} diff --git a/packages/jsx-macros/src/core/define-component/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts index 2a845b7ef..2b0cc6eae 100644 --- a/packages/jsx-macros/src/core/define-component/restructure.ts +++ b/packages/jsx-macros/src/core/define-component/restructure.ts @@ -17,102 +17,6 @@ type Prop = { isRequired?: boolean } -function getProps( - node: Node, - path: string = '', - s: MagicString, - props: Prop[] = [], -) { - const properties = - node.type === 'ObjectPattern' - ? node.properties - : node.type === 'ArrayPattern' - ? node.elements - : [] - if (!properties.length) return - - const propNames: string[] = [] - properties.forEach((prop, index) => { - if (prop?.type === 'Identifier') { - // { foo } - props.push({ name: prop.name, path, value: `[${index}]` }) - propNames.push(`'${prop.name}'`) - } else if ( - prop?.type === 'AssignmentPattern' && - prop.left.type === 'Identifier' - ) { - // [foo = 'foo'] - props.push({ - path, - name: prop.left.name, - value: `.${prop.left.name}`, - defaultValue: s.slice(prop.right.start!, prop.right.end!), - }) - propNames.push(`'${prop.left.name}'`) - } else if ( - prop?.type === 'ObjectProperty' && - prop.key.type === 'Identifier' - ) { - if ( - prop.value.type === 'AssignmentPattern' && - prop.value.left.type === 'Identifier' - ) { - // { foo: bar = 'foo' } - props.push({ - path, - name: prop.value.left.name, - value: `.${prop.key.name}`, - defaultValue: s.slice(prop.value.right.start!, prop.value.right.end!), - isRequired: prop.value.right.type === 'TSNonNullExpression', - }) - } else if (!getProps(prop.value, `${path}.${prop.key.name}`, s, props)) { - // { foo: bar } - props.push({ - path, - name: - prop.value.type === 'Identifier' ? prop.value.name : prop.key.name, - value: `.${prop.key.name}`, - }) - } - propNames.push(`'${prop.key.name}'`) - } else if ( - prop?.type === 'RestElement' && - prop.argument.type === 'Identifier' && - !prop.argument.name.startsWith(`${HELPER_PREFIX}props`) - ) { - // { ...rest } - props.push({ - path, - name: prop.argument.name, - value: propNames.join(', '), - isRest: true, - }) - } else if (prop) { - getProps(prop, `${path}[${index}]`, s, props) - } - }) - return props.length ? props : undefined -} - -export function prependFunctionalNode( - node: FunctionalNode, - s: MagicString, - result: string, -): void { - const isBlockStatement = node.body.type === 'BlockStatement' - const start = node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start! - s.appendRight( - start + (isBlockStatement ? 1 : 0), - `${result};${!isBlockStatement ? 'return ' : ''}`, - ) - if (!isBlockStatement) { - s.appendLeft(start, '{') - s.appendRight(node.end!, '}') - } -} - export function restructure( s: MagicString, node: FunctionalNode, @@ -215,3 +119,99 @@ export function restructure( return propList } + +function getProps( + node: Node, + path: string = '', + s: MagicString, + props: Prop[] = [], +) { + const properties = + node.type === 'ObjectPattern' + ? node.properties + : node.type === 'ArrayPattern' + ? node.elements + : [] + if (!properties.length) return + + const propNames: string[] = [] + properties.forEach((prop, index) => { + if (prop?.type === 'Identifier') { + // { foo } + props.push({ name: prop.name, path, value: `[${index}]` }) + propNames.push(`'${prop.name}'`) + } else if ( + prop?.type === 'AssignmentPattern' && + prop.left.type === 'Identifier' + ) { + // [foo = 'foo'] + props.push({ + path, + name: prop.left.name, + value: `.${prop.left.name}`, + defaultValue: s.slice(prop.right.start!, prop.right.end!), + }) + propNames.push(`'${prop.left.name}'`) + } else if ( + prop?.type === 'ObjectProperty' && + prop.key.type === 'Identifier' + ) { + if ( + prop.value.type === 'AssignmentPattern' && + prop.value.left.type === 'Identifier' + ) { + // { foo: bar = 'foo' } + props.push({ + path, + name: prop.value.left.name, + value: `.${prop.key.name}`, + defaultValue: s.slice(prop.value.right.start!, prop.value.right.end!), + isRequired: prop.value.right.type === 'TSNonNullExpression', + }) + } else if (!getProps(prop.value, `${path}.${prop.key.name}`, s, props)) { + // { foo: bar } + props.push({ + path, + name: + prop.value.type === 'Identifier' ? prop.value.name : prop.key.name, + value: `.${prop.key.name}`, + }) + } + propNames.push(`'${prop.key.name}'`) + } else if ( + prop?.type === 'RestElement' && + prop.argument.type === 'Identifier' && + !prop.argument.name.startsWith(`${HELPER_PREFIX}props`) + ) { + // { ...rest } + props.push({ + path, + name: prop.argument.name, + value: propNames.join(', '), + isRest: true, + }) + } else if (prop) { + getProps(prop, `${path}[${index}]`, s, props) + } + }) + return props.length ? props : undefined +} + +export function prependFunctionalNode( + node: FunctionalNode, + s: MagicString, + result: string, +): void { + const isBlockStatement = node.body.type === 'BlockStatement' + const start = node.body.extra?.parenthesized + ? (node.body.extra.parenStart as number) + : node.body.start! + s.appendRight( + start + (isBlockStatement ? 1 : 0), + `${result};${!isBlockStatement ? 'return ' : ''}`, + ) + if (!isBlockStatement) { + s.appendLeft(start, '{') + s.appendRight(node.end!, '}') + } +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 4e2176ecf..290f8428a 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -26,40 +26,6 @@ export type FunctionalNode = | FunctionExpression | ArrowFunctionExpression -export function isFunctionalNode(node?: Node | null): node is FunctionalNode { - return !!( - node && - (node.type === 'ArrowFunctionExpression' || - node.type === 'FunctionDeclaration' || - node.type === 'FunctionExpression') - ) -} - -export function getMacroExpression( - node: Node | null | undefined, -): CallExpression | undefined { - if (node?.type === 'TSNonNullExpression') { - node = node.expression - } - - if (node?.type === 'CallExpression') { - if ( - node.callee.type === 'MemberExpression' && - node.callee.object.type === 'Identifier' && - node.callee.object.name === 'defineStyle' - ) { - return node - } else if ( - node.callee.type === 'Identifier' && - ['defineSlots', 'defineModel', 'defineExpose', 'defineStyle'].includes( - node.callee.name!, - ) - ) { - return node - } - } -} - export type RootMapValue = { defineComponent?: CallExpression defineModel?: { @@ -74,71 +40,6 @@ export type RootMapValue = { }[] } -function getRootMap(s: MagicStringAST, id: string) { - const parents: (Node | undefined | null)[] = [] - const rootMap = new Map() - walkAST(babelParse(s.original, getLang(id)), { - enter(node, parent) { - parents.unshift(parent) - const root = - parents[1] && isFunctionalNode(parents[1]) ? parents[1] : undefined - - if ( - parents[2]?.type === 'CallExpression' && - s.sliceNode(parents[2].callee) === 'defineComponent' - ) { - if (!rootMap.has(root)) rootMap.set(root, {}) - if (!rootMap.get(root)!.defineComponent) { - rootMap.get(root)!.defineComponent = parents[2] - } - } - - const expression = - node.type === 'VariableDeclaration' - ? node.declarations[0].init - : node.type === 'ExpressionStatement' - ? node.expression - : undefined - const macroExpression = getMacroExpression(expression) - if (!macroExpression) return - if (!rootMap.has(root)) rootMap.set(root, {}) - const macroName = s.sliceNode(macroExpression.callee) - if (macroName) { - if (macroName === 'defineModel') { - ;(rootMap.get(root)!.defineModel ??= []).push({ - expression: macroExpression, - isRequired: expression?.type === 'TSNonNullExpression', - }) - } else if (macroName.startsWith('defineStyle')) { - const [, lang = 'css'] = macroName.split('.') - ;(rootMap.get(root)!.defineStyle ??= []).push({ - expression: macroExpression, - lang, - }) - } else if ( - macroName === 'defineSlots' || - macroName === 'defineExpose' - ) { - rootMap.get(root)![macroName] = macroExpression - } - } - }, - leave() { - parents.shift() - }, - }) - return rootMap -} - -export function getParamsStart(node: FunctionalNode, code: string): number { - return node.params[0] - ? node.params[0].start! - : node.start! + - (code.slice(node.start!, node.body.start!).match(/\(\s*\)/)?.index || - 0) + - 1 -} - export function transformJsxMacros( code: string, id: string, @@ -207,3 +108,102 @@ export function transformJsxMacros( return generateTransform(s, id) } + +function getRootMap(s: MagicStringAST, id: string) { + const parents: (Node | undefined | null)[] = [] + const rootMap = new Map() + walkAST(babelParse(s.original, getLang(id)), { + enter(node, parent) { + parents.unshift(parent) + const root = + parents[1] && isFunctionalNode(parents[1]) ? parents[1] : undefined + + if ( + parents[2]?.type === 'CallExpression' && + s.sliceNode(parents[2].callee) === 'defineComponent' + ) { + if (!rootMap.has(root)) rootMap.set(root, {}) + if (!rootMap.get(root)!.defineComponent) { + rootMap.get(root)!.defineComponent = parents[2] + } + } + + const expression = + node.type === 'VariableDeclaration' + ? node.declarations[0].init + : node.type === 'ExpressionStatement' + ? node.expression + : undefined + const macroExpression = getMacroExpression(expression) + if (!macroExpression) return + if (!rootMap.has(root)) rootMap.set(root, {}) + const macroName = s.sliceNode(macroExpression.callee) + if (macroName) { + if (macroName === 'defineModel') { + ;(rootMap.get(root)!.defineModel ??= []).push({ + expression: macroExpression, + isRequired: expression?.type === 'TSNonNullExpression', + }) + } else if (macroName.startsWith('defineStyle')) { + const [, lang = 'css'] = macroName.split('.') + ;(rootMap.get(root)!.defineStyle ??= []).push({ + expression: macroExpression, + lang, + }) + } else if ( + macroName === 'defineSlots' || + macroName === 'defineExpose' + ) { + rootMap.get(root)![macroName] = macroExpression + } + } + }, + leave() { + parents.shift() + }, + }) + return rootMap +} + +export function isFunctionalNode(node?: Node | null): node is FunctionalNode { + return !!( + node && + (node.type === 'ArrowFunctionExpression' || + node.type === 'FunctionDeclaration' || + node.type === 'FunctionExpression') + ) +} + +export function getMacroExpression( + node: Node | null | undefined, +): CallExpression | undefined { + if (node?.type === 'TSNonNullExpression') { + node = node.expression + } + + if (node?.type === 'CallExpression') { + if ( + node.callee.type === 'MemberExpression' && + node.callee.object.type === 'Identifier' && + node.callee.object.name === 'defineStyle' + ) { + return node + } else if ( + node.callee.type === 'Identifier' && + ['defineSlots', 'defineModel', 'defineExpose', 'defineStyle'].includes( + node.callee.name!, + ) + ) { + return node + } + } +} + +export function getParamsStart(node: FunctionalNode, code: string): number { + return node.params[0] + ? node.params[0].start! + : node.start! + + (code.slice(node.start!, node.body.start!).match(/\(\s*\)/)?.index || + 0) + + 1 +} diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 5fa9eca88..54e612b66 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -4,13 +4,13 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue"; +import { useAttrs as __MACROS_useAttrs } from "vue"; import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' const Comp = __MACROS_defineComponent( (__MACROS_props) => { -const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});__MACROS_getCurrentInstance().inheritAttrs=false;const attrs = __MACROS_getCurrentInstance().setupContext.attrs; +const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});const attrs = __MACROS_useAttrs(); const foo = __MACROS_useModel(__MACROS_props, 'foo', { validator: (value) => { return value === 'foo' @@ -20,9 +20,9 @@ const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, }) return () =>
{[foo.value, __MACROS_default_props.bar, attrs.baz]}
}, - { inheritAttrs: false , props: { bar: { required: true }, 'foo': { validator: (value) => { + {props: { bar: { required: true }, 'foo': { validator: (value) => { return value === 'foo' - }, required: false, type: String }, 'onUpdate:foo': null }}, + }, required: false, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, ) const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 80fff49f9..b9cf8220b 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -11,7 +11,7 @@ const Comp = defineComponent( }) return
{[foo.value, bar, attrs.baz]}
}, - { inheritAttrs: false }, + { name: 'Comp' }, ) const Comp1 = defineComponent((props: { bar: 'bar' }) => { From a9d8ff2e259f7dc552fe06dafd1a404a104909f2 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 24 Oct 2024 11:40:20 +0800 Subject: [PATCH 054/156] feat: add components option --- packages/volar/src/jsx-macros.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 5cd33990c..54b6dd8f9 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -343,11 +343,11 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { embeddedFile.content.push( ` const { defineModel } = await import('vue') -declare function defineSlots>(slots?: T): T; +declare function defineSlots>(slots?: Partial): T; declare function defineExpose = Record>(exposed?: Exposed): Exposed; type __VLS_DefineStyle = (style: string, options?: { scoped?: boolean }) => void; declare const defineStyle: { (style: string, options?: { scoped?: boolean }): void; scss: __VLS_DefineStyle; sass: __VLS_DefineStyle; stylus: __VLS_DefineStyle; less: __VLS_DefineStyle; postcss: __VLS_DefineStyle }; -declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T +declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; `, ) From 6aa835fb4b3a7702b2d66737cf9df5be110ce1fc Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 24 Oct 2024 17:36:28 +0800 Subject: [PATCH 055/156] feat: prevent directly return jsx --- .../src/core/define-component/index.ts | 35 ------------------- packages/jsx-macros/src/core/index.ts | 2 +- .../tests/fixtures/define-component.tsx | 6 ++-- .../vue3/src/examples/jsx-macros/comp.tsx | 2 +- 4 files changed, 5 insertions(+), 40 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 917406330..96c8d1ddd 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -10,7 +10,6 @@ export function transformDefineComponent( propsName: string, map: RootMapValue, s: MagicStringAST, - lib: string, ): void { if (!map.defineComponent) return s.overwriteNode( @@ -90,7 +89,6 @@ export function transformDefineComponent( } transformAwait(root, s) - transformReturn(root, s, lib) } function prependObjectExpression( @@ -134,36 +132,3 @@ function getWalkedIds(root: FunctionalNode, propsName: string) { ) return walkedIds } - -// Auto add `() => ` for return statement -function transformReturn(root: FunctionalNode, s: MagicStringAST, lib: string) { - if (lib === 'vue') { - if (root.body.type === 'BlockStatement') { - const returnStatement = root.body.body.find( - (node) => node.type === 'ReturnStatement', - ) - if ( - returnStatement && - returnStatement.argument && - !( - returnStatement.argument?.type === 'ArrowFunctionExpression' || - returnStatement.argument?.type === 'FunctionExpression' - ) - ) { - s.appendRight( - returnStatement.argument.extra?.parenthesized - ? (returnStatement.argument.extra.parenStart as number) - : returnStatement.argument.start!, - '() => ', - ) - } - } else { - s.appendRight( - root.body.extra?.parenthesized - ? (root.body.extra.parenStart as number) - : root.body.start!, - '() => ', - ) - } - } -} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 290f8428a..8c9e25bce 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -91,7 +91,7 @@ export function transformJsxMacros( } if (map.defineComponent) { - transformDefineComponent(root, propsName, map, s, options.lib) + transformDefineComponent(root, propsName, map, s) } if (map.defineModel?.length) { map.defineModel.forEach(({ expression }) => { diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index b9cf8220b..9c67b4a9c 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -9,14 +9,14 @@ const Comp = defineComponent( required: false, type: String, }) - return
{[foo.value, bar, attrs.baz]}
+ return () =>
{[foo.value, bar, attrs.baz]}
}, { name: 'Comp' }, ) const Comp1 = defineComponent((props: { bar: 'bar' }) => { const foo = defineModel('foo') - return
{[foo.value, props['bar']]}
+ return () =>
{[foo.value, props['bar']]}
}) const Comp2 = defineComponent(async () => { @@ -24,5 +24,5 @@ const Comp2 = defineComponent(async () => { let foo = await new Promise((resolve) => { setTimeout(() => resolve('foo'), 1000) }) - return
{foo}
+ return () =>
{foo}
}) diff --git a/playground/vue3/src/examples/jsx-macros/comp.tsx b/playground/vue3/src/examples/jsx-macros/comp.tsx index 36ab31c65..44ab6afb6 100644 --- a/playground/vue3/src/examples/jsx-macros/comp.tsx +++ b/playground/vue3/src/examples/jsx-macros/comp.tsx @@ -35,7 +35,7 @@ export const Comp = defineComponent(function ({ foo }: { foo: T }) { } `) - return ( + return () => (
color:
From c21388b6ea99dd07e6f69e24f20737f14b9d4d91 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 25 Oct 2024 00:29:43 +0800 Subject: [PATCH 056/156] fix: type --- packages/volar/src/jsx-macros.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 54b6dd8f9..9fb29b951 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -226,9 +226,9 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) if (asyncModifier) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as __VLS_MaybeReturnType>['render']> & { __ctx: Awaited>['render']${map.defineComponent ? '>' : ''} & { __ctx: Awaited> }` From 76d4de14ab62a9824496390afd3b3e68ac78c4b3 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 25 Oct 2024 02:19:38 +0800 Subject: [PATCH 057/156] fix: type --- packages/volar/src/jsx-macros.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 9fb29b951..5659e0fa6 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -224,11 +224,11 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { const asyncModifier = root.modifiers?.find( (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, ) - if (asyncModifier) + if (asyncModifier && map.defineComponent) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as ${map.defineComponent ? '__VLS_MaybeReturnType<' : ''}Awaited>['render']${map.defineComponent ? '>' : ''} & { __ctx: Awaited>['render'] & { __ctx: Awaited> }` @@ -285,6 +285,9 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) } + const isFunctionReturn = + ts.isArrowFunction(node.expression) || + ts.isFunctionExpression(node.expression) replaceSourceRange( codes, source, @@ -297,12 +300,14 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', `,\nrender: `, + isFunctionReturn ? '(' : '', ) replaceSourceRange( codes, source, node.expression.end, node.expression.end, + isFunctionReturn ? ')()' : '', `\n}`, ) } @@ -347,8 +352,7 @@ declare function defineSlots>(slots?: Partial): declare function defineExpose = Record>(exposed?: Exposed): Exposed; type __VLS_DefineStyle = (style: string, options?: { scoped?: boolean }) => void; declare const defineStyle: { (style: string, options?: { scoped?: boolean }): void; scss: __VLS_DefineStyle; sass: __VLS_DefineStyle; stylus: __VLS_DefineStyle; less: __VLS_DefineStyle; postcss: __VLS_DefineStyle }; -declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T -declare type __VLS_MaybeReturnType = T extends (...args: any) => any ? ReturnType : T; +declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; `, ) } From 07dc03757f2d5cab379e43d679ca237bf91f6d90 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 25 Oct 2024 06:45:36 +0800 Subject: [PATCH 058/156] fix: only wrap by call for defineComponent --- packages/volar/src/jsx-macros.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 5659e0fa6..152b07ecd 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -285,9 +285,10 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { ) } - const isFunctionReturn = - ts.isArrowFunction(node.expression) || - ts.isFunctionExpression(node.expression) + const shouldWrapByCall = + (ts.isArrowFunction(node.expression) || + ts.isFunctionExpression(node.expression)) && + map.defineComponent replaceSourceRange( codes, source, @@ -300,14 +301,14 @@ function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', `,\nrender: `, - isFunctionReturn ? '(' : '', + shouldWrapByCall ? '(' : '', ) replaceSourceRange( codes, source, node.expression.end, node.expression.end, - isFunctionReturn ? ')()' : '', + shouldWrapByCall ? ')()' : '', `\n}`, ) } From f996daa3a914d240eaf55575a840daa1f1d7f6d6 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 30 Oct 2024 11:21:30 +0800 Subject: [PATCH 059/156] feat: modified model's value will be read synchronously --- .../src/core/define-component/index.ts | 6 +-- .../jsx-macros/src/core/helper/use-model.ts | 54 ++++--------------- 2 files changed, 14 insertions(+), 46 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 96c8d1ddd..68c50bdc5 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -62,16 +62,16 @@ export function transformDefineComponent( expression.arguments[0]?.type === 'StringLiteral' ? expression.arguments[0].value : 'modelValue' - props[`'${propName}'`] = Object.keys(options).length + props[propName] = Object.keys(options).length ? `{ ${Object.entries(options) .map(([key, value]) => `${key}: ${value}`) .join(', ')} }` : null - props[`'onUpdate:${propName}'`] = null + props[`onUpdate:${propName}`] = null } const propsString = Object.entries(props) - .map(([key, value]) => `${key}: ${value}`) + .map(([key, value]) => `'${key}': ${value}`) .join(', ') if (propsString) { const argument = map.defineComponent.arguments[1] diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts index ed6aa2a29..46b548fb3 100644 --- a/packages/jsx-macros/src/core/helper/use-model.ts +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -1,10 +1,5 @@ -// Modified from: https://github.com/vuejs/core/blob/main/packages/runtime-core/src/helpers/useModel.ts - import { customRef, watchSyncEffect, type ModelRef } from 'vue' -const hasChanged = (value: any, oldValue: any): boolean => - !Object.is(value, oldValue) - type DefineModelOptions> = { default?: any get?: (v: T) => any @@ -20,17 +15,13 @@ export function useModel( name: string, options: DefineModelOptions = {}, ): any { - const modifiers = - name === 'modelValue' ? props.modelModifiers : props[`${name}Modifiers`] - const res = customRef((track, trigger) => { let localValue: any = options?.default - let prevSetValue: any let prevEmittedValue: any watchSyncEffect(() => { const propValue = props[name] - if (hasChanged(localValue, propValue)) { + if (!Object.is(prevEmittedValue, propValue)) { localValue = propValue trigger() } @@ -43,44 +34,21 @@ export function useModel( }, set(value) { - const emittedValue = options.set ? options.set(value) : value - if ( - !hasChanged(emittedValue, localValue) && - !(prevSetValue !== undefined && hasChanged(value, prevSetValue)) - ) { - return - } - if ( - !( - props && - // check if parent has passed v-model - props[name] !== undefined && - props[`onUpdate:${name}`] !== undefined - ) - ) { - // no v-model, local update - localValue = value - trigger() - } - - props[`onUpdate:${name}`]?.(emittedValue) - // #10279: if the local value is converted via a setter but the value - // emitted to parent was the same, the parent will not trigger any - // updates and there will be no prop sync. However the local input state - // may be out of sync, so we need to force an update here. - if ( - hasChanged(value, emittedValue) && - hasChanged(value, prevSetValue) && - !hasChanged(emittedValue, prevEmittedValue) - ) { - trigger() + if (Object.is(value, localValue)) return + localValue = value + trigger() + const emittedValue = (prevEmittedValue = options.set + ? options.set(value) + : value) + for (const emit of [props[`onUpdate:${name}`]].flat()) { + if (typeof emit === 'function') emit(emittedValue) } - prevSetValue = value - prevEmittedValue = emittedValue }, } }) + const modifiers = + name === 'modelValue' ? props.modelModifiers : props[`${name}Modifiers`] // @ts-expect-error res[Symbol.iterator] = () => { let i = 0 From bfcad5e559d09e3c4aad2f885852c3c9826a9a29 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 30 Oct 2024 11:24:03 +0800 Subject: [PATCH 060/156] fix(define-component): All propNames will be wrapped by quotation marks --- .../jsx-macros/tests/__snapshots__/fixtures.test.ts.snap | 6 +++--- packages/jsx-macros/tests/fixtures/define-component.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 54e612b66..757722b5c 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -20,15 +20,15 @@ const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, }) return () =>
{[foo.value, __MACROS_default_props.bar, attrs.baz]}
}, - {props: { bar: { required: true }, 'foo': { validator: (value) => { + {props: { 'bar': { required: true }, 'foo': { validator: (value) => { return value === 'foo' }, required: false, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, ) const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { const foo = __MACROS_useModel(props, 'foo') - return () =>
{[foo.value, props['bar']]}
-}, { props: { bar: null, 'foo': null, 'onUpdate:foo': null } }) + return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
+}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null } }) const Comp2 = __MACROS_defineComponent(async (__MACROS_props) => { let __temp, __restore diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 9c67b4a9c..527a37cd8 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -14,9 +14,9 @@ const Comp = defineComponent( { name: 'Comp' }, ) -const Comp1 = defineComponent((props: { bar: 'bar' }) => { +const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { const foo = defineModel('foo') - return () =>
{[foo.value, props['bar']]}
+ return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
}) const Comp2 = defineComponent(async () => { From 513e2e2e24b24d61a774b82afc940b232e66b890 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 30 Oct 2024 19:38:26 +0800 Subject: [PATCH 061/156] feat(defineStyle): support css modules --- packages/jsx-macros/src/core/define-style.ts | 40 ++- packages/jsx-macros/src/core/index.ts | 28 +- .../tests/__snapshots__/fixtures.test.ts.snap | 14 +- .../tests/fixtures/define-style.tsx | 12 +- packages/volar/src/common.ts | 2 +- packages/volar/src/jsx-macros.ts | 335 +----------------- packages/volar/src/jsx-macros/define-style.ts | 45 +++ packages/volar/src/jsx-macros/global-types.ts | 10 + packages/volar/src/jsx-macros/index.ts | 229 ++++++++++++ packages/volar/src/jsx-macros/transform.ts | 111 ++++++ 10 files changed, 448 insertions(+), 378 deletions(-) create mode 100644 packages/volar/src/jsx-macros/define-style.ts create mode 100644 packages/volar/src/jsx-macros/global-types.ts create mode 100644 packages/volar/src/jsx-macros/index.ts create mode 100644 packages/volar/src/jsx-macros/transform.ts diff --git a/packages/jsx-macros/src/core/define-style.ts b/packages/jsx-macros/src/core/define-style.ts index f1cb8a5c5..44bfb1193 100644 --- a/packages/jsx-macros/src/core/define-style.ts +++ b/packages/jsx-macros/src/core/define-style.ts @@ -1,26 +1,26 @@ import { walkAST, type MagicStringAST } from '@vue-macros/common' import hash from 'hash-sum' import { helperPrefix } from './helper' -import { isFunctionalNode, type FunctionalNode } from '.' -import type { CallExpression, Node } from '@babel/types' +import { isFunctionalNode, type DefineStyle, type FunctionalNode } from '.' +import type { Node } from '@babel/types' export function transformDefineStyle( - node: CallExpression, - lang: string, + defineStyle: DefineStyle, + index: number, root: FunctionalNode | undefined, - defineStyleIndex: number, s: MagicStringAST, importMap: Map, ): void { - if (node.arguments[0]?.type !== 'TemplateLiteral') return + const { expression, lang, isDeclaration } = defineStyle + if (expression.arguments[0]?.type !== 'TemplateLiteral') return - let css = s.sliceNode(node.arguments[0]).slice(1, -1) + let css = s.sliceNode(expression.arguments[0]).slice(1, -1) const scopeId = hash(css) const vars = new Map() - node.arguments[0].expressions.forEach((expression) => { - const cssVar = s.sliceNode(expression) + expression.arguments[0].expressions.forEach((exp) => { + const cssVar = s.sliceNode(exp) const cssVarId = toCssVarId(cssVar, `--${scopeId}-`) - s.overwrite(expression.start! - 2, expression.end! + 1, `var(${cssVarId})`) + s.overwrite(exp.start! - 2, exp.end! + 1, `var(${cssVarId})`) vars.set(cssVarId, cssVar) }) @@ -48,9 +48,9 @@ export function transformDefineStyle( } } - let scoped = !!root - if (node.arguments[1]?.type === 'ObjectExpression') { - for (const prop of node.arguments[1].properties) { + let scoped = isDeclaration ? false : !!root + if (expression.arguments[1]?.type === 'ObjectExpression') { + for (const prop of expression.arguments[1].properties) { if ( prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && @@ -75,11 +75,17 @@ export function transformDefineStyle( }) } - css = s.sliceNode(node.arguments[0]).slice(1, -1) - const importId = `${helperPrefix}/define-style?index=${defineStyleIndex}&scopeId=${scopeId}&scoped=${scoped}&lang.${lang}` + css = s.sliceNode(expression.arguments[0]).slice(1, -1) + const module = isDeclaration ? 'module.' : '' + const importId = `${helperPrefix}/define-style?index=${index}&scopeId=${scopeId}&scoped=${scoped}&lang.${module}${lang}` importMap.set(importId, css) - s.appendLeft(0, `import "${importId}";`) - s.removeNode(node) + s.appendLeft( + 0, + isDeclaration + ? `import style${index} from "${importId}"` + : `import "${importId}";`, + ) + s.overwriteNode(expression, isDeclaration ? `style${index}` : '') } function getReturnStatement(root: FunctionalNode) { diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 8c9e25bce..8e873a815 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -26,6 +26,12 @@ export type FunctionalNode = | FunctionExpression | ArrowFunctionExpression +export type DefineStyle = { + expression: CallExpression + isDeclaration: boolean + lang: string +} + export type RootMapValue = { defineComponent?: CallExpression defineModel?: { @@ -34,10 +40,7 @@ export type RootMapValue = { }[] defineSlots?: CallExpression defineExpose?: CallExpression - defineStyle?: { - expression: CallExpression - lang: string - }[] + defineStyle?: DefineStyle[] } export function transformJsxMacros( @@ -48,21 +51,11 @@ export function transformJsxMacros( ): CodeTransform | undefined { const s = new MagicStringAST(code) const rootMap = getRootMap(s, id) - let defineStyleIndex = 0 for (const [root, map] of rootMap) { - if (map.defineStyle?.length) { - map.defineStyle.forEach(({ expression, lang }) => { - transformDefineStyle( - expression, - lang, - root, - defineStyleIndex++, - s, - importMap, - ) - }) - } + map.defineStyle?.forEach((defineStyle, index) => { + transformDefineStyle(defineStyle, index, root, s, importMap) + }) if (root === undefined) continue @@ -148,6 +141,7 @@ function getRootMap(s: MagicStringAST, id: string) { const [, lang = 'css'] = macroName.split('.') ;(rootMap.get(root)!.defineStyle ??= []).push({ expression: macroExpression, + isDeclaration: node.type === 'VariableDeclaration', lang, }) } else if ( diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 757722b5c..6e2e620e8 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -25,7 +25,7 @@ const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, }, required: false, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, ) -const Comp1 = __MACROS_defineComponent((props: { bar: 'bar' }) => { +const Comp1 = __MACROS_defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null } }) @@ -100,8 +100,8 @@ export default function (__MACROS_props) { `; exports[`fixtures > ./fixtures/define-style.tsx 1`] = ` -"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=true&lang.css";import "/vue-macros/jsx-macros/define-style?index=1&scopeId=102189c6&scoped=true&lang.scss"; -import { defineComponent as __MACROS_defineComponent } from "vue";import "/vue-macros/jsx-macros/define-style?index=2&scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' +"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=true&lang.css";import style0 from "/vue-macros/jsx-macros/define-style?index=0&scopeId=426a859d&scoped=false&lang.module.scss" +import { defineComponent as __MACROS_defineComponent } from "vue";import "/vue-macros/jsx-macros/define-style?index=0&scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' export const Comp = (__MACROS_props) => { const color = ref('red') @@ -111,12 +111,12 @@ export const Comp = (__MACROS_props) => { export default __MACROS_defineComponent((__MACROS_props) => { const color = ref('red') - + const styles = style0 return () => ( <> -
foo
-
- bar +
foo
+
+ bar
) diff --git a/packages/jsx-macros/tests/fixtures/define-style.tsx b/packages/jsx-macros/tests/fixtures/define-style.tsx index b1568161f..a585a0756 100644 --- a/packages/jsx-macros/tests/fixtures/define-style.tsx +++ b/packages/jsx-macros/tests/fixtures/define-style.tsx @@ -12,17 +12,17 @@ export const Comp = () => { export default defineComponent(() => { const color = ref('red') - defineStyle.scss( - ` + const styles = defineStyle.scss(` .bar { color: ${color.value}; + .barBaz { + background: red; + } } - `, - { scoped: true }, - ) + `) return () => ( <> -
foo
+
foo
bar
diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index c3f94fb2c..f7480f3e7 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -107,7 +107,7 @@ export interface VolarContext { export function getStart( node: | import('typescript').Node - | import('typescript').SignatureDeclarationBase['parameters'], + | import('typescript').NodeArray, { ts, sfc, source = 'scriptSetup' }: VolarContext, ): number { return (ts as any).getTokenPosOfNode(node, sfc[source]!.ast) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 152b07ecd..2d6d77304 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -1,320 +1,6 @@ -import { createFilter, HELPER_PREFIX } from '@vue-macros/common' -import { toValidAssetId } from '@vue/compiler-dom' -import { replaceSourceRange } from 'muggle-string' -import { getStart, getText, type VueMacrosPlugin } from './common' -import type { TransformOptions } from './jsx-directive/index' -import type { VueCompilerOptions } from '@vue/language-core' - -type RootMap = Map< - | import('typescript').ArrowFunction - | import('typescript').FunctionExpression - | import('typescript').FunctionDeclaration, - { - defineModel?: string[] - defineSlots?: string - defineExpose?: string - defineComponent?: true - } -> - -function getMacro( - node: import('typescript').Node | undefined, - ts: typeof import('typescript'), - vueCompilerOptions: VueCompilerOptions, -): - | { - expression: import('typescript').CallExpression - initializer: import('typescript').Node - isRequired: boolean - } - | undefined { - if (!node) return - - if (ts.isVariableStatement(node)) { - return ts.forEachChild(node.declarationList, (decl) => getExpression(decl)) - } else { - return getExpression(node) - } - - function getExpression(decl: import('typescript').Node) { - if (ts.isVariableDeclaration(decl) && decl.initializer) { - const initializer = - ts.isCallExpression(decl.initializer) && - ts.isIdentifier(decl.initializer.expression) && - decl.initializer.expression.escapedText === '$' && - decl.initializer.arguments[0] - ? decl.initializer.arguments[0] - : decl.initializer - const expression = getMacroExpression(initializer) - if (expression) { - return { - expression, - initializer: decl.initializer, - isRequired: ts.isNonNullExpression(initializer), - } - } - } else if (ts.isExpressionStatement(decl)) { - const expression = getMacroExpression(decl.expression) - if (expression) - return { - expression, - initializer: decl.expression, - isRequired: ts.isNonNullExpression(decl.expression), - } - } - } - - function getMacroExpression(node: import('typescript').Node) { - if (ts.isNonNullExpression(node)) { - node = node.expression - } - return ( - ts.isCallExpression(node) && - ts.isIdentifier(node.expression) && - [ - ...vueCompilerOptions.macros.defineModel, - ...vueCompilerOptions.macros.defineExpose, - ...vueCompilerOptions.macros.defineSlots, - 'defineStyle', - ].includes(node.expression.escapedText!) && - node - ) - } -} - -function getRootMap( - options: TransformOptions, - vueCompilerOptions: VueCompilerOptions, -): RootMap { - const { ts, sfc, source, codes } = options - const rootMap: RootMap = new Map() - - function walk( - node: import('typescript').Node, - parents: import('typescript').Node[], - ) { - ts.forEachChild(node, (child) => { - parents.unshift(node) - walk(child, parents) - parents.shift() - }) - - const root = - parents[1] && - (ts.isArrowFunction(parents[1]) || - ts.isFunctionExpression(parents[1]) || - ts.isFunctionDeclaration(parents[1])) - ? parents[1] - : undefined - if (!root) return - - if ( - parents[2] && - ts.isCallExpression(parents[2]) && - !parents[2].typeArguments && - getText(parents[2].expression, options) === 'defineComponent' - ) { - if (!rootMap.has(root)) rootMap.set(root, {}) - if (!rootMap.get(root)!.defineComponent) { - rootMap.get(root)!.defineComponent = true - replaceSourceRange( - codes, - source, - getStart(parents[2], options), - getStart(parents[2], options), - HELPER_PREFIX, - ) - } - } - - const macro = getMacro(node, ts, vueCompilerOptions) - if (!macro) return - - const { expression, initializer } = macro - let isRequired = macro.isRequired - if (!rootMap.has(root)) rootMap.set(root, {}) - const macroName = getText(expression.expression, options) - if (vueCompilerOptions.macros.defineModel.includes(macroName)) { - const modelName = - expression.arguments[0] && - ts.isStringLiteralLike(expression.arguments[0]) - ? expression.arguments[0].text - : 'modelValue' - const modelOptions = - expression.arguments[0] && - ts.isStringLiteralLike(expression.arguments[0]) - ? expression.arguments[1] - : expression.arguments[0] - if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { - let hasRequired = false - for (const prop of modelOptions.properties) { - if ( - ts.isPropertyAssignment(prop) && - getText(prop.name, options) === 'required' - ) { - hasRequired = true - isRequired = prop.initializer.kind === ts.SyntaxKind.TrueKeyword - } - } - - if (!hasRequired && isRequired) { - replaceSourceRange( - codes, - source, - modelOptions.end - 1, - modelOptions.end - 1, - `${expression.arguments.hasTrailingComma ? '' : ','} required: true`, - ) - } - } else if (isRequired) { - replaceSourceRange( - codes, - source, - expression.arguments.end, - expression.arguments.end, - `${!expression.arguments.hasTrailingComma && expression.arguments.length ? ',' : ''} { required: true }`, - ) - } - - const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) - const typeString = `import("vue").UnwrapRef` - ;(rootMap.get(root)!.defineModel ??= [])!.push( - `'${modelName}'${isRequired ? ':' : '?:'} ${typeString}`, - `'onUpdate:${modelName}'?: ($event: ${typeString}) => any`, - ) - replaceSourceRange( - codes, - source, - getStart(initializer, options), - getStart(initializer, options), - `// @ts-ignore\n${id};\nlet ${id} =`, - ) - } else if (vueCompilerOptions.macros.defineSlots.includes(macroName)) { - replaceSourceRange( - codes, - source, - getStart(expression, options), - getStart(expression, options), - `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, - ) - rootMap.get(root)!.defineSlots = - `{ vSlots?: typeof ${HELPER_PREFIX}slots }` - } else if (vueCompilerOptions.macros.defineExpose.includes(macroName)) { - replaceSourceRange( - codes, - source, - getStart(expression, options), - getStart(expression, options), - `// @ts-ignore\n${HELPER_PREFIX}expose;\nconst ${HELPER_PREFIX}expose =`, - ) - rootMap.get(root)!.defineExpose = - `(exposed: typeof ${HELPER_PREFIX}expose) => {}` - } - } - - ts.forEachChild(sfc[source]!.ast, (node) => walk(node, [])) - return rootMap -} - -function transformJsxMacros(rootMap: RootMap, options: TransformOptions): void { - const { ts, source, codes } = options - - for (const [root, map] of rootMap) { - if (!root.body) continue - const asyncModifier = root.modifiers?.find( - (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, - ) - if (asyncModifier && map.defineComponent) - replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as Awaited>['render'] & { __ctx: Awaited> }` - - const propsType = root.parameters[0]?.type - ? String(getText(root.parameters[0].type, options)) - : '{}' - replaceSourceRange( - codes, - source, - getStart(root.parameters, options), - getStart(root.parameters, options), - `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType},`, - `${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, - ) - if (ts.isArrowFunction(root)) { - replaceSourceRange(codes, source, root.end, root.end, `)) => `, result) - } else { - replaceSourceRange( - codes, - source, - getStart(root.body, options), - getStart(root.body, options), - '=>', - ) - replaceSourceRange( - codes, - source, - root.end, - root.end, - `)){ return `, - result, - '}', - ) - } - - ts.forEachChild(root.body, (node) => { - if (ts.isReturnStatement(node) && node.expression) { - const defaultProps = [] - const elements = - root.parameters[0] && - !root.parameters[0].type && - ts.isObjectBindingPattern(root.parameters[0].name) - ? root.parameters[0].name.elements - : [] - for (const element of elements) { - if (ts.isIdentifier(element.name)) - defaultProps.push( - `${element.name.escapedText}${ - element.initializer && - ts.isNonNullExpression(element.initializer) - ? ':' - : '?:' - } typeof ${element.name.escapedText}`, - ) - } - - const shouldWrapByCall = - (ts.isArrowFunction(node.expression) || - ts.isFunctionExpression(node.expression)) && - map.defineComponent - replaceSourceRange( - codes, - source, - getStart(node, options), - getStart(node.expression, options), - `return {\nprops: {} as `, - options.vueVersion ? `import('vue').PublicProps & ` : '', - `{${defaultProps.join(', ')}} & `, - map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', - map.defineSlots ? ` & ${map.defineSlots}` : '', - map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', - `,\nrender: `, - shouldWrapByCall ? '(' : '', - ) - replaceSourceRange( - codes, - source, - node.expression.end, - node.expression.end, - shouldWrapByCall ? ')()' : '', - `\n}`, - ) - } - }) - } -} +import { createFilter } from '@vue-macros/common' +import { getRootMap, globalTypes, transformJsxMacros } from './jsx-macros/index' +import type { VueMacrosPlugin } from './common' const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { if (!options) return [] @@ -342,20 +28,9 @@ const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { if ( (fileName.endsWith('.tsx') || rootMap.size) && - !embeddedFile.content - .toString() - .includes(`declare function defineSlots`) + !embeddedFile.content.toString().includes(globalTypes) ) { - embeddedFile.content.push( - ` -const { defineModel } = await import('vue') -declare function defineSlots>(slots?: Partial): T; -declare function defineExpose = Record>(exposed?: Exposed): Exposed; -type __VLS_DefineStyle = (style: string, options?: { scoped?: boolean }) => void; -declare const defineStyle: { (style: string, options?: { scoped?: boolean }): void; scss: __VLS_DefineStyle; sass: __VLS_DefineStyle; stylus: __VLS_DefineStyle; less: __VLS_DefineStyle; postcss: __VLS_DefineStyle }; -declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; - `, - ) + embeddedFile.content.push(globalTypes) } } }, diff --git a/packages/volar/src/jsx-macros/define-style.ts b/packages/volar/src/jsx-macros/define-style.ts new file mode 100644 index 000000000..934575d6b --- /dev/null +++ b/packages/volar/src/jsx-macros/define-style.ts @@ -0,0 +1,45 @@ +import { generateCssClassProperty } from '@vue/language-core/lib/codegen/script/template' +import { parseCssClassNames } from '@vue/language-core/lib/utils/parseCssClassNames' +import { replaceSourceRange } from 'muggle-string' +import { getStart, getText } from '../common' +import type { TransformOptions } from '../jsx-directive/index' + +export function transformDefineStyle( + defineStyle: import('typescript').CallExpression[] | undefined, + options: TransformOptions, +): void { + const { ts, source, codes } = options + defineStyle?.forEach((expression, index) => { + if ( + expression?.arguments[0] && + !expression.typeArguments && + ts.isTemplateExpression(expression.arguments[0]) + ) { + replaceSourceRange( + codes, + source, + expression.arguments.pos - 1, + expression.arguments.pos - 1, + '<{}', + ...getCssClassesType( + getText(expression.arguments[0], options).slice(1, -1), + getStart(expression.arguments[0], options) + 1, + index, + ), + '>', + ) + } + }) +} + +function* getCssClassesType(css: string, offset: number, index: number) { + for (const className of [...parseCssClassNames(css)]) { + yield* generateCssClassProperty( + index, + className.text, + className.offset + offset, + 'string', + false, + ) + } +} diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts new file mode 100644 index 000000000..e6591778f --- /dev/null +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -0,0 +1,10 @@ +import { HELPER_PREFIX } from '@vue-macros/common' + +export const globalTypes: string = ` +const { defineModel } = await import('vue') +declare function defineSlots>(slots?: Partial): T; +declare function defineExpose = Record>(exposed?: Exposed): Exposed; +type __VLS_StyleArgs = [style: string, options?: { scoped?: boolean }] +declare const defineStyle: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T } +declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; +` diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts new file mode 100644 index 000000000..3259706be --- /dev/null +++ b/packages/volar/src/jsx-macros/index.ts @@ -0,0 +1,229 @@ +import { HELPER_PREFIX } from '@vue-macros/common' +import { toValidAssetId } from '@vue/compiler-dom' +import { replaceSourceRange } from 'muggle-string' +import { getStart, getText } from '../common' +import type { TransformOptions } from '../jsx-directive/index' +import type { VueCompilerOptions } from '@vue/language-core' + +export { transformJsxMacros } from './transform' +export { globalTypes } from './global-types' + +export type RootMap = Map< + | import('typescript').ArrowFunction + | import('typescript').FunctionExpression + | import('typescript').FunctionDeclaration, + { + defineModel?: string[] + defineSlots?: string + defineExpose?: string + defineStyle?: import('typescript').CallExpression[] + defineComponent?: true + } +> + +function getMacro( + node: import('typescript').Node | undefined, + ts: typeof import('typescript'), + vueCompilerOptions: VueCompilerOptions, +): + | { + expression: import('typescript').CallExpression + initializer: import('typescript').Node + isRequired: boolean + } + | undefined { + if (!node) return + + if (ts.isVariableStatement(node)) { + return ts.forEachChild(node.declarationList, (decl) => getExpression(decl)) + } else { + return getExpression(node) + } + + function getExpression(decl: import('typescript').Node) { + if (ts.isVariableDeclaration(decl) && decl.initializer) { + const initializer = + ts.isCallExpression(decl.initializer) && + ts.isIdentifier(decl.initializer.expression) && + decl.initializer.expression.escapedText === '$' && + decl.initializer.arguments[0] + ? decl.initializer.arguments[0] + : decl.initializer + const expression = getMacroExpression(initializer) + if (expression) { + return { + expression, + initializer: decl.initializer, + isRequired: ts.isNonNullExpression(initializer), + } + } + } else if (ts.isExpressionStatement(decl)) { + const expression = getMacroExpression(decl.expression) + if (expression) + return { + expression, + initializer: decl.expression, + isRequired: ts.isNonNullExpression(decl.expression), + } + } + } + + function getMacroExpression(node: import('typescript').Node) { + if (ts.isNonNullExpression(node)) { + node = node.expression + } + if (!ts.isCallExpression(node)) return + const expression = ts.isPropertyAccessExpression(node.expression) + ? node.expression + : node + return ( + ts.isIdentifier(expression.expression) && + [ + ...vueCompilerOptions.macros.defineModel, + ...vueCompilerOptions.macros.defineExpose, + ...vueCompilerOptions.macros.defineSlots, + 'defineStyle', + ].includes(expression.expression.escapedText!) && + node + ) + } +} + +export function getRootMap( + options: TransformOptions, + vueCompilerOptions: VueCompilerOptions, +): RootMap { + const { ts, sfc, source, codes } = options + const rootMap: RootMap = new Map() + + function walk( + node: import('typescript').Node, + parents: import('typescript').Node[], + ) { + ts.forEachChild(node, (child) => { + parents.unshift(node) + walk(child, parents) + parents.shift() + }) + + const root = + parents[1] && + (ts.isArrowFunction(parents[1]) || + ts.isFunctionExpression(parents[1]) || + ts.isFunctionDeclaration(parents[1])) + ? parents[1] + : undefined + if (!root) return + + if ( + parents[2] && + ts.isCallExpression(parents[2]) && + !parents[2].typeArguments && + getText(parents[2].expression, options) === 'defineComponent' + ) { + if (!rootMap.has(root)) rootMap.set(root, {}) + if (!rootMap.get(root)!.defineComponent) { + rootMap.get(root)!.defineComponent = true + replaceSourceRange( + codes, + source, + getStart(parents[2], options), + getStart(parents[2], options), + HELPER_PREFIX, + ) + } + } + + const macro = getMacro(node, ts, vueCompilerOptions) + if (!macro) return + + const { expression, initializer } = macro + let isRequired = macro.isRequired + if (!rootMap.has(root)) rootMap.set(root, {}) + const macroName = getText(expression.expression, options) + if (vueCompilerOptions.macros.defineModel.includes(macroName)) { + const modelName = + expression.arguments[0] && + ts.isStringLiteralLike(expression.arguments[0]) + ? expression.arguments[0].text + : 'modelValue' + const modelOptions = + expression.arguments[0] && + ts.isStringLiteralLike(expression.arguments[0]) + ? expression.arguments[1] + : expression.arguments[0] + if (modelOptions && ts.isObjectLiteralExpression(modelOptions)) { + let hasRequired = false + for (const prop of modelOptions.properties) { + if ( + ts.isPropertyAssignment(prop) && + getText(prop.name, options) === 'required' + ) { + hasRequired = true + isRequired = prop.initializer.kind === ts.SyntaxKind.TrueKeyword + } + } + + if (!hasRequired && isRequired) { + replaceSourceRange( + codes, + source, + modelOptions.end - 1, + modelOptions.end - 1, + `${expression.arguments.hasTrailingComma ? '' : ','} required: true`, + ) + } + } else if (isRequired) { + replaceSourceRange( + codes, + source, + expression.arguments.end, + expression.arguments.end, + `${!expression.arguments.hasTrailingComma && expression.arguments.length ? ',' : ''} { required: true }`, + ) + } + + const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) + const typeString = `import("vue").UnwrapRef` + ;(rootMap.get(root)!.defineModel ??= [])!.push( + `'${modelName}'${isRequired ? ':' : '?:'} ${typeString}`, + `'onUpdate:${modelName}'?: ($event: ${typeString}) => any`, + ) + replaceSourceRange( + codes, + source, + getStart(initializer, options), + getStart(initializer, options), + `// @ts-ignore\n${id};\nlet ${id} =`, + ) + } else if (vueCompilerOptions.macros.defineSlots.includes(macroName)) { + replaceSourceRange( + codes, + source, + getStart(expression, options), + getStart(expression, options), + `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, + ) + rootMap.get(root)!.defineSlots = + `{ vSlots?: typeof ${HELPER_PREFIX}slots }` + } else if (vueCompilerOptions.macros.defineExpose.includes(macroName)) { + replaceSourceRange( + codes, + source, + getStart(expression, options), + getStart(expression, options), + `// @ts-ignore\n${HELPER_PREFIX}expose;\nconst ${HELPER_PREFIX}expose =`, + ) + rootMap.get(root)!.defineExpose = + `(exposed: typeof ${HELPER_PREFIX}expose) => {}` + } else if ( + macroName.startsWith('defineStyle') && + ts.isVariableStatement(node) + ) { + ;(rootMap.get(root)!.defineStyle ??= [])!.push(expression) + } + } + + ts.forEachChild(sfc[source]!.ast, (node) => walk(node, [])) + return rootMap +} diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts new file mode 100644 index 000000000..86534736e --- /dev/null +++ b/packages/volar/src/jsx-macros/transform.ts @@ -0,0 +1,111 @@ +import { HELPER_PREFIX } from '@vue-macros/common' +import { replaceSourceRange } from 'muggle-string' +import { getStart, getText } from '../common' +import type { TransformOptions } from '../jsx-directive/index' +import { transformDefineStyle } from './define-style' +import type { RootMap } from '.' + +export function transformJsxMacros( + rootMap: RootMap, + options: TransformOptions, +): void { + const { ts, source, codes } = options + + for (const [root, map] of rootMap) { + if (!root.body) continue + const asyncModifier = root.modifiers?.find( + (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, + ) + if (asyncModifier && map.defineComponent) + replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) + const result = `({}) as Awaited>['render'] & { __ctx: Awaited> }` + + const propsType = root.parameters[0]?.type + ? String(getText(root.parameters[0].type, options)) + : '{}' + replaceSourceRange( + codes, + source, + getStart(root.parameters, options), + getStart(root.parameters, options), + `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType},`, + `${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, + ) + if (ts.isArrowFunction(root)) { + replaceSourceRange(codes, source, root.end, root.end, `)) => `, result) + } else { + replaceSourceRange( + codes, + source, + getStart(root.body, options), + getStart(root.body, options), + '=>', + ) + replaceSourceRange( + codes, + source, + root.end, + root.end, + `)){ return `, + result, + '}', + ) + } + + transformDefineStyle(map.defineStyle, options) + + ts.forEachChild(root.body, (node) => { + if (ts.isReturnStatement(node) && node.expression) { + const defaultProps = [] + const elements = + root.parameters[0] && + !root.parameters[0].type && + ts.isObjectBindingPattern(root.parameters[0].name) + ? root.parameters[0].name.elements + : [] + for (const element of elements) { + if (ts.isIdentifier(element.name)) + defaultProps.push( + `${element.name.escapedText}${ + element.initializer && + ts.isNonNullExpression(element.initializer) + ? ':' + : '?:' + } typeof ${element.name.escapedText}`, + ) + } + + const shouldWrapByCall = + (ts.isArrowFunction(node.expression) || + ts.isFunctionExpression(node.expression)) && + map.defineComponent + replaceSourceRange( + codes, + source, + getStart(node, options), + getStart(node.expression, options), + `return {\nprops: {} as `, + options.vueVersion ? `import('vue').PublicProps & ` : '', + `{${defaultProps.join(', ')}} & `, + map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', + map.defineSlots ? ` & ${map.defineSlots}` : '', + map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', + `,\nrender: `, + shouldWrapByCall ? '(' : '', + ) + replaceSourceRange( + codes, + source, + node.expression.end, + node.expression.end, + shouldWrapByCall ? ')()' : '', + `\n}`, + ) + } + }) + } +} From cbecfa6a7e26f5d24cdd345f03f79e091af4ec65 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 2 Nov 2024 14:27:21 +0800 Subject: [PATCH 062/156] feat(volar): compatible with ts-macro --- .changeset/mighty-bags-divide.md | 6 ++++++ packages/volar/src/common.ts | 18 ++++++++++++++---- packages/volar/src/jsx-directive.ts | 7 ++++--- packages/volar/src/jsx-directive/index.ts | 10 +++++----- packages/volar/src/jsx-directive/v-for.ts | 12 +++++------- packages/volar/src/jsx-directive/v-model.ts | 10 ++-------- packages/volar/src/jsx-directive/v-slot.ts | 6 +++--- packages/volar/src/jsx-ref.ts | 9 +++++---- 8 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 .changeset/mighty-bags-divide.md diff --git a/.changeset/mighty-bags-divide.md b/.changeset/mighty-bags-divide.md new file mode 100644 index 000000000..ffb042b3b --- /dev/null +++ b/.changeset/mighty-bags-divide.md @@ -0,0 +1,6 @@ +--- +"@vue-macros/volar": patch +--- + +compatible with ts-macro + \ No newline at end of file diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index 0aded8b72..b9b587924 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -99,24 +99,34 @@ export function getVolarOptions( } export interface VolarContext { - sfc: Sfc ts: typeof import('typescript') + ast?: import('typescript').SourceFile + sfc?: Sfc source?: 'script' | 'scriptSetup' } export function getStart( +<<<<<<< Updated upstream node: import('typescript').Node, { ts, sfc, source = 'scriptSetup' }: VolarContext, +======= + node: + | import('typescript').Node + | import('typescript').NodeArray, + { ts, ast, sfc, source = 'scriptSetup' }: VolarContext, +>>>>>>> Stashed changes ): number { - return (ts as any).getTokenPosOfNode(node, sfc[source]!.ast) + ast = ast || sfc?.[source]?.ast + return (ts as any).getTokenPosOfNode(node, ast) } export function getText( node: import('typescript').Node, context: VolarContext, ): string { - const { sfc, source = 'scriptSetup' } = context - return sfc[source]!.content.slice(getStart(node, context), node.end) + let { sfc, ast, source = 'scriptSetup' } = context + ast = ast || sfc?.[source]?.ast + return ast!.text.slice(getStart(node, context), node.end) } export function isJsxExpression( diff --git a/packages/volar/src/jsx-directive.ts b/packages/volar/src/jsx-directive.ts index 2f07ee693..d91b235db 100644 --- a/packages/volar/src/jsx-directive.ts +++ b/packages/volar/src/jsx-directive.ts @@ -14,12 +14,13 @@ const plugin: VueMacrosPlugin<'jsxDirective'> = (ctx, options = {}) => { if (!filter(fileName) || !['jsx', 'tsx'].includes(embeddedFile.lang)) return - for (const source of ['script', 'scriptSetup'] as const) { - if (!sfc[source]?.ast) continue + for (const source of ['script', 'scriptSetup', undefined] as const) { + const ast = sfc[source as 'script']?.ast + if (!ast) continue transformJsxDirective({ codes: embeddedFile.content, - sfc, + ast, ts: ctx.modules.typescript, source, vueVersion: ctx.vueCompilerOptions.target, diff --git a/packages/volar/src/jsx-directive/index.ts b/packages/volar/src/jsx-directive/index.ts index a71ef50cb..cc1beef21 100644 --- a/packages/volar/src/jsx-directive/index.ts +++ b/packages/volar/src/jsx-directive/index.ts @@ -7,7 +7,7 @@ import { transformVIf } from './v-if' import { transformVModel } from './v-model' import { transformVOn, transformVOnWithModifiers } from './v-on' import { transformVSlot, transformVSlots, type VSlotMap } from './v-slot' -import type { Code, Sfc } from '@vue/language-core' +import type { Code } from '@vue/language-core' import type { JsxOpeningElement, JsxSelfClosingElement } from 'typescript' export type JsxDirective = { @@ -18,14 +18,14 @@ export type JsxDirective = { export type TransformOptions = { codes: Code[] - sfc: Sfc + ast: import('typescript').SourceFile ts: typeof import('typescript') - source: 'script' | 'scriptSetup' + source: 'script' | 'scriptSetup' | undefined vueVersion?: number } export function transformJsxDirective(options: TransformOptions): void { - const { sfc, ts, source } = options + const { ast, ts } = options const vIfMap = new Map< JsxDirective['node'] | null | undefined, @@ -194,7 +194,7 @@ export function transformJsxDirective(options: TransformOptions): void { parents.shift() }) } - ts.forEachChild(sfc[source]!.ast, walkJsxDirective) + ts.forEachChild(ast, walkJsxDirective) const ctxMap = new Map( Array.from(ctxNodeMap).map(([node, root], index) => [ diff --git a/packages/volar/src/jsx-directive/v-for.ts b/packages/volar/src/jsx-directive/v-for.ts index 195933f89..2ccb12ebe 100644 --- a/packages/volar/src/jsx-directive/v-for.ts +++ b/packages/volar/src/jsx-directive/v-for.ts @@ -7,7 +7,7 @@ export function resolveVFor( attribute: JsxDirective['attribute'], options: TransformOptions, ): Code[] { - const { ts, sfc, source } = options + const { ts, ast, source } = options const result: Code[] = [] if ( @@ -38,14 +38,14 @@ export function resolveVFor( result.push( '__VLS_getVForSourceType(', [ - sfc[source]!.content.slice(getStart(list, options), list.end), + ast.text.slice(getStart(list, options), list.end), source, getStart(list, options), allCodeFeatures, ], ').map(([', [ - String(sfc[source]?.content.slice(getStart(item, options), item.end)), + String(ast.text.slice(getStart(item, options), item.end)), source, getStart(item, options), allCodeFeatures, @@ -53,9 +53,7 @@ export function resolveVFor( ', ', index ? [ - String( - sfc[source]?.content.slice(getStart(index, options), index.end), - ), + String(ast.text.slice(getStart(index, options), index.end)), source, getStart(index, options), allCodeFeatures, @@ -68,7 +66,7 @@ export function resolveVFor( ', ', [ String( - sfc[source]?.content.slice( + ast?.text.slice( getStart(objectIndex, options), objectIndex.end, ), diff --git a/packages/volar/src/jsx-directive/v-model.ts b/packages/volar/src/jsx-directive/v-model.ts index f82767b9e..7a02e435b 100644 --- a/packages/volar/src/jsx-directive/v-model.ts +++ b/packages/volar/src/jsx-directive/v-model.ts @@ -8,7 +8,7 @@ export function transformVModel( ctxMap: Map, options: TransformOptions, ): void { - const { codes, ts, source, sfc } = options + const { codes, ts, source, ast } = options let firstNamespacedNode: | { attribute: JsxDirective['attribute'] @@ -144,13 +144,7 @@ export function transformVModel( `}}`, ) // Fix `v-model:` without type hints - replaceSourceRange( - codes, - source, - end, - end + 1, - sfc[source]!.content.slice(end, end + 1), - ) + replaceSourceRange(codes, source, end, end + 1, ast.text.slice(end, end + 1)) } function getModelsType(codes: Code[]) { diff --git a/packages/volar/src/jsx-directive/v-slot.ts b/packages/volar/src/jsx-directive/v-slot.ts index 9c7897bc7..dad28c2ce 100644 --- a/packages/volar/src/jsx-directive/v-slot.ts +++ b/packages/volar/src/jsx-directive/v-slot.ts @@ -25,7 +25,7 @@ export function transformVSlot( options: TransformOptions, ): void { if (nodeMap.size === 0) return - const { codes, ts, sfc, source } = options + const { codes, ts, ast, source } = options nodeMap.forEach(({ attributeMap, vSlotAttribute }, node) => { const result: Code[] = [' vSlots={{'] @@ -113,7 +113,7 @@ export function transformVSlot( return isSlotTemplate && ts.isJsxSelfClosingElement(child) ? '' : ([ - sfc[source]!.content.slice(node.pos, node.end), + ast!.text.slice(node.pos, node.end), source, node.pos, allCodeFeatures, @@ -165,7 +165,7 @@ export function transformVSlot( source, vSlotAttribute.end, vSlotAttribute.end + 1, - sfc[source]!.content.slice(vSlotAttribute.end, vSlotAttribute.end + 1), + ast.text.slice(vSlotAttribute.end, vSlotAttribute.end + 1), ) } else if (ts.isJsxElement(node)) { replaceSourceRange( diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index b2660a367..a5f03c08d 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -17,7 +17,7 @@ function transformRef({ nodes: RefNode[] codes: Code[] ts: typeof import('typescript') - source: 'script' | 'scriptSetup' + source: 'script' | 'scriptSetup' | undefined }) { for (const { name, initializer } of nodes) { if (ts.isCallExpression(initializer)) { @@ -87,9 +87,10 @@ const plugin: VueMacrosPlugin<'jsxRef'> = (ctx, options = {}) => { const ts = ctx.modules.typescript const alias = options.alias || ['useRef'] - for (const source of ['script', 'scriptSetup'] as const) { - if (!sfc[source]) continue - const nodes = getRefNodes(ts, sfc[source].ast, alias) + for (const source of ['script', 'scriptSetup', undefined] as const) { + const ast = sfc[source as 'script']?.ast + if (!ast) continue + const nodes = getRefNodes(ts, ast, alias) if (nodes.length) { transformRef({ nodes, From 07dc7f6eeb77a685151f489549f79a98d95a2951 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 2 Nov 2024 14:32:35 +0800 Subject: [PATCH 063/156] fix: typo --- packages/volar/src/common.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index b9b587924..8823f8fd6 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -106,15 +106,10 @@ export interface VolarContext { } export function getStart( -<<<<<<< Updated upstream - node: import('typescript').Node, - { ts, sfc, source = 'scriptSetup' }: VolarContext, -======= node: | import('typescript').Node | import('typescript').NodeArray, { ts, ast, sfc, source = 'scriptSetup' }: VolarContext, ->>>>>>> Stashed changes ): number { ast = ast || sfc?.[source]?.ast return (ts as any).getTokenPosOfNode(node, ast) From bd54421189e56788ff15776343cfd2230c92a393 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 4 Nov 2024 17:49:31 +0800 Subject: [PATCH 064/156] feat: support ts-macro --- packages/volar/package.json | 3 +- packages/volar/src/common.ts | 1 + packages/volar/src/index.ts | 3 +- packages/volar/src/jsx-directive.ts | 40 ++-- packages/volar/src/jsx-directive/index.ts | 3 +- packages/volar/src/jsx-ref.ts | 44 ++-- pnpm-lock.yaml | 264 ++++++++++++++++++++++ 7 files changed, 307 insertions(+), 51 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index f19566077..767b86e77 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -280,7 +280,8 @@ "@vue-macros/short-bind": "workspace:*", "@vue-macros/short-vmodel": "workspace:*", "@vue/language-core": "catalog:", - "muggle-string": "^0.4.1" + "muggle-string": "^0.4.1", + "ts-macro": "^0.0.2" }, "devDependencies": { "@vue/compiler-dom": "catalog:", diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index 8823f8fd6..3f9a2f2fe 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -9,6 +9,7 @@ import { replace, replaceAll } from 'muggle-string' import type { SFCScriptBlock } from '@vue-macros/common' import type { Code, Sfc, VueLanguagePlugin } from '@vue/language-core' +export const REGEX_JSX: RegExp = /\.[jt]sx$/ export const REGEX_DEFINE_COMPONENT: RegExp = /(?<=(?:__VLS_|\(await import\(\S+\)\)\.)defineComponent\(\{\n)/g diff --git a/packages/volar/src/index.ts b/packages/volar/src/index.ts index 7031ead94..cd8c5aec7 100644 --- a/packages/volar/src/index.ts +++ b/packages/volar/src/index.ts @@ -48,7 +48,8 @@ const plugin: VueLanguagePlugin = (ctx) => Object.entries(plugins).flatMap(([name, plugin]) => { const options = getVolarOptions(ctx, name as keyof typeof plugins) if (!options) return [] - return plugin(ctx, options) + // @ts-expect-error compatible with ts-macro + return plugin({ ...ctx, options }, options) as any }) export default plugin diff --git a/packages/volar/src/jsx-directive.ts b/packages/volar/src/jsx-directive.ts index d91b235db..7a7d527bd 100644 --- a/packages/volar/src/jsx-directive.ts +++ b/packages/volar/src/jsx-directive.ts @@ -1,32 +1,26 @@ import { createFilter } from '@vue-macros/common' +import { createPlugin, type PluginReturn } from 'ts-macro' +import { REGEX_JSX } from './common' import { transformJsxDirective } from './jsx-directive/index' -import type { VueMacrosPlugin } from './common' +import type { OptionsResolved } from '@vue-macros/config' -const plugin: VueMacrosPlugin<'jsxDirective'> = (ctx, options = {}) => { +export default createPlugin(({ options = {}, ts }) => { if (!options) return [] - - const filter = createFilter(options) + const filter = createFilter({ + ...options, + include: options.include || REGEX_JSX, + }) return { name: 'vue-macros-jsx-directive', - version: 2.1, - resolveEmbeddedCode(fileName, sfc, embeddedFile) { - if (!filter(fileName) || !['jsx', 'tsx'].includes(embeddedFile.lang)) - return - - for (const source of ['script', 'scriptSetup', undefined] as const) { - const ast = sfc[source as 'script']?.ast - if (!ast) continue - - transformJsxDirective({ - codes: embeddedFile.content, - ast, - ts: ctx.modules.typescript, - source, - vueVersion: ctx.vueCompilerOptions.target, - }) - } + resolveVirtualCode({ ast, codes, fileName, source, languageId }) { + if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return + transformJsxDirective({ + codes, + ast, + ts, + source, + }) }, } -} -export default plugin +}) as PluginReturn diff --git a/packages/volar/src/jsx-directive/index.ts b/packages/volar/src/jsx-directive/index.ts index cc1beef21..3cccfb5e2 100644 --- a/packages/volar/src/jsx-directive/index.ts +++ b/packages/volar/src/jsx-directive/index.ts @@ -20,8 +20,7 @@ export type TransformOptions = { codes: Code[] ast: import('typescript').SourceFile ts: typeof import('typescript') - source: 'script' | 'scriptSetup' | undefined - vueVersion?: number + source?: 'script' | 'scriptSetup' } export function transformJsxDirective(options: TransformOptions): void { diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index a5f03c08d..d8b8b8ec2 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -1,6 +1,8 @@ import { createFilter } from '@vue-macros/common' import { replaceSourceRange } from 'muggle-string' -import type { VueMacrosPlugin } from './common' +import { createPlugin, type PluginReturn } from 'ts-macro' +import { REGEX_JSX } from './common' +import type { OptionsResolved } from '@vue-macros/config' import type { Code } from '@vue/language-core' type RefNode = { @@ -74,33 +76,27 @@ function getRefNodes( return result } -const plugin: VueMacrosPlugin<'jsxRef'> = (ctx, options = {}) => { +export default createPlugin(({ options = {}, ts }) => { if (!options) return [] - - const filter = createFilter(options) + const filter = createFilter({ + ...options, + include: options.include || REGEX_JSX, + }) + const alias = options.alias || ['useRef'] return { name: 'vue-macros-jsx-ref', - version: 2.1, - resolveEmbeddedCode(fileName, sfc, embeddedFile) { - if (!filter(fileName)) return - const ts = ctx.modules.typescript - const alias = options.alias || ['useRef'] - - for (const source of ['script', 'scriptSetup', undefined] as const) { - const ast = sfc[source as 'script']?.ast - if (!ast) continue - const nodes = getRefNodes(ts, ast, alias) - if (nodes.length) { - transformRef({ - nodes, - codes: embeddedFile.content, - ts, - source, - }) - } + resolveVirtualCode({ ast, codes, fileName, source, languageId }) { + if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return + const nodes = getRefNodes(ts, ast, alias) + if (nodes.length) { + transformRef({ + nodes, + codes, + ts, + source, + }) } }, } -} -export default plugin +}) as PluginReturn diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d11bed037..a8877760f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -955,6 +955,9 @@ importers: muggle-string: specifier: ^0.4.1 version: 0.4.1 + ts-macro: + specifier: ^0.0.2 + version: 0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3) devDependencies: '@vue/compiler-dom': specifier: 'catalog:' @@ -1670,6 +1673,27 @@ packages: search-insights: optional: true + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.0': + resolution: {integrity: sha512-z7wkxRSZgrQHXVzObGkXG+Vmj3uRlpM11oCZ9pbaz0nFejvCDmAiNDpY75+wgXOcffKpj4rzGtwGaZxfJKsJxw==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/core@1.3.1': resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} @@ -2633,6 +2657,10 @@ packages: peerDependencies: vue: ^2.7.0 || ^3.0.0 + '@ts-macro/language-server@0.0.2': + resolution: {integrity: sha512-GMSsLyIwPz6uWlUX1PwcrbyiHBGecz3owbzjGOURYp/asXiZlHM8/yzaTrKDXhxEr8NM9aszyIiWvjJ7CY6rCA==} + hasBin: true + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -2920,12 +2948,24 @@ packages: '@volar/language-core@2.4.8': resolution: {integrity: sha512-K/GxMOXGq997bO00cdFhTNuR85xPxj0BEEAy+BaqqayTmy9Tmhfgmq2wpJcVspRhcwfgPoE2/mEJa26emUhG/g==} + '@volar/language-server@2.4.8': + resolution: {integrity: sha512-3Jd9Y+0Zhwi/zfdRxqoNrm7AxP6lgTsw4Ni9r6eCyWYGVsTnpVwGmlcbiZyDja6anoKZxnaeDatX1jkaHHWaRQ==} + + '@volar/language-service@2.4.8': + resolution: {integrity: sha512-9y8X4cdUxXmy4s5HoB8jmOpDIZG7XVFu4iEFvouhZlJX2leCq0pbq5h7dhA+O8My0fne3vtE6cJ4t9nc+8UBZw==} + '@volar/source-map@2.4.8': resolution: {integrity: sha512-jeWJBkC/WivdelMwxKkpFL811uH/jJ1kVxa+c7OvG48DXc3VrP7pplSWPP2W1dLMqBxD+awRlg55FQQfiup4cA==} '@volar/typescript@2.4.8': resolution: {integrity: sha512-6xkIYJ5xxghVBhVywMoPMidDDAFT1OoQeXwa27HSgJ6AiIKRe61RXLoik+14Z7r0JvnblXVsjsRLmCr42SGzqg==} + '@vscode/emmet-helper@2.9.3': + resolution: {integrity: sha512-rB39LHWWPQYYlYfpv9qCoZOVioPCftKXXqrsyqN1mTWZM6dTnONT63Db+03vgrBbHzJN45IrgS/AGxw9iiqfEw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + '@vue/babel-helper-vue-jsx-merge-props@1.4.0': resolution: {integrity: sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==} @@ -3029,6 +3069,14 @@ packages: '@vue/devtools-shared@7.5.4': resolution: {integrity: sha512-dwuq4YmwTyLc7eBOqX63s3JB8il7qnKsNgENglSMkUPwiItHkVAYYfPESN1rxSdYkl1RCux1l5TBidYqfUDNAA==} + '@vue/language-core@2.1.10': + resolution: {integrity: sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@vue/language-core@2.1.8': resolution: {integrity: sha512-DtPUKrIRqqzY1joGfVHxHWZoxXZbCQLmVtW+QTifuPInfcs1R/3UAdlJXDp+lpSpP9lI5m+jMYYlwDXXu3KSTg==} peerDependencies: @@ -3717,6 +3765,9 @@ packages: electron-to-chromium@1.5.47: resolution: {integrity: sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==} + emmet@2.4.11: + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -4600,6 +4651,9 @@ packages: resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -5454,6 +5508,9 @@ packages: resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} engines: {node: '>=0.10'} + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -5885,6 +5942,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-macro@0.0.2: + resolution: {integrity: sha512-M1LWmpRJu5CvpS21qBbcrx75wWpppOXGYOirRg2zWqfVlxf5D1oDXHrrkAqRF35bCYEhKkJ/o7fzWzZ8IGXeVw==} + tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} engines: {node: ^18 || >=20} @@ -5955,6 +6015,9 @@ packages: resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} engines: {node: '>=16'} + typescript-auto-import-cache@0.3.5: + resolution: {integrity: sha512-fAIveQKsoYj55CozUiBoj4b/7WpN0i4o74wiGY5JVUEoD0XiqDk1tJqTEjgzL2/AizKQrXxyRosSebyDzBZKjw==} + typescript-eslint@8.11.0: resolution: {integrity: sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6273,9 +6336,56 @@ packages: jsdom: optional: true + volar-service-css@0.0.62: + resolution: {integrity: sha512-JwNyKsH3F8PuzZYuqPf+2e+4CTU8YoyUHEHVnoXNlrLe7wy9U3biomZ56llN69Ris7TTy/+DEX41yVxQpM4qvg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.62: + resolution: {integrity: sha512-U4dxWDBWz7Pi4plpbXf4J4Z/ss6kBO3TYrACxWNsE29abu75QzVS0paxDDhI6bhqpbDFXlpsDhZ9aXVFpnfGRQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.62: + resolution: {integrity: sha512-p7MPi71q7KOsH0eAbZwPBiKPp9B2+qrdHAd6VY5oTo9BUXatsOAdakTm9Yf0DUj6uWBAaOT01BSeVOPwucMV1g==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.1: + resolution: {integrity: sha512-1BzTBuJfwMc3A0uX4JBdJgoxp74cjj4q2mDJdp49yD/GuAq4X0k5WtK6fNcMYr+FfJ9nqgR6lpfCSZDkARJ5qQ==} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + vscode-languageserver-textdocument@1.0.12: resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-uri@2.1.2: + resolution: {integrity: sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==} + vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} @@ -7243,6 +7353,29 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.0': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + '@emnapi/core@1.3.1': dependencies: '@emnapi/wasi-threads': 1.0.1 @@ -8366,6 +8499,17 @@ snapshots: '@tanstack/virtual-core': 3.10.8 vue: 3.5.12(typescript@5.6.3) + '@ts-macro/language-server@0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3)': + dependencies: + '@volar/language-server': 2.4.8 + ts-macro: 0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3) + volar-service-css: 0.0.62(@volar/language-service@2.4.8) + volar-service-emmet: 0.0.62(@volar/language-service@2.4.8) + volar-service-typescript: 0.0.62(@volar/language-service@2.4.8) + transitivePeerDependencies: + - '@volar/language-service' + - typescript + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.0 @@ -8803,6 +8947,25 @@ snapshots: dependencies: '@volar/source-map': 2.4.8 + '@volar/language-server@2.4.8': + dependencies: + '@volar/language-core': 2.4.8 + '@volar/language-service': 2.4.8 + '@volar/typescript': 2.4.8 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + '@volar/language-service@2.4.8': + dependencies: + '@volar/language-core': 2.4.8 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + '@volar/source-map@2.4.8': {} '@volar/typescript@2.4.8': @@ -8811,6 +8974,16 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.0.8 + '@vscode/emmet-helper@2.9.3': + dependencies: + emmet: 2.4.11 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 2.1.2 + + '@vscode/l10n@0.0.18': {} + '@vue/babel-helper-vue-jsx-merge-props@1.4.0': {} '@vue/babel-helper-vue-transform-on@1.2.5': {} @@ -9007,6 +9180,19 @@ snapshots: dependencies: rfdc: 1.4.1 + '@vue/language-core@2.1.10(typescript@5.6.3)': + dependencies: + '@volar/language-core': 2.4.8 + '@vue/compiler-dom': 3.5.12 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.12 + alien-signals: 0.2.0 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.6.3 + '@vue/language-core@2.1.8(typescript@5.6.3)': dependencies: '@volar/language-core': 2.4.8 @@ -9803,6 +9989,11 @@ snapshots: electron-to-chromium@1.5.47: {} + emmet@2.4.11: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -10797,6 +10988,8 @@ snapshots: espree: 9.6.1 semver: 7.6.3 + jsonc-parser@2.3.1: {} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -11871,6 +12064,8 @@ snapshots: repeat-string@1.6.1: {} + request-light@0.7.0: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -12346,6 +12541,19 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-macro@0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3): + dependencies: + '@ts-macro/language-server': 0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3) + '@volar/language-core': 2.4.8 + '@volar/typescript': 2.4.8 + '@vue/language-core': 2.1.10(typescript@5.6.3) + jiti: 2.3.3 + muggle-string: 0.4.1 + vscode-uri: 3.0.8 + transitivePeerDependencies: + - '@volar/language-service' + - typescript + tsconfck@3.1.4(typescript@5.6.3): optionalDependencies: typescript: 5.6.3 @@ -12417,6 +12625,10 @@ snapshots: type-fest@4.26.1: {} + typescript-auto-import-cache@0.3.5: + dependencies: + semver: 7.6.3 + typescript-eslint@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3): dependencies: '@typescript-eslint/eslint-plugin': 8.11.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3) @@ -12926,8 +13138,60 @@ snapshots: - supports-color - terser + volar-service-css@0.0.62(@volar/language-service@2.4.8): + dependencies: + vscode-css-languageservice: 6.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.8 + + volar-service-emmet@0.0.62(@volar/language-service@2.4.8): + dependencies: + '@emmetio/css-parser': 0.4.0 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.9.3 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.8 + + volar-service-typescript@0.0.62(@volar/language-service@2.4.8): + dependencies: + path-browserify: 1.0.1 + semver: 7.6.3 + typescript-auto-import-cache: 0.3.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-nls: 5.2.0 + vscode-uri: 3.0.8 + optionalDependencies: + '@volar/language-service': 2.4.8 + + vscode-css-languageservice@6.3.1: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.0.8 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + vscode-languageserver-textdocument@1.0.12: {} + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + + vscode-uri@2.1.2: {} + vscode-uri@3.0.8: {} vue-demi@0.14.10(vue@2.7.16): From f818736e3173cac05ed5897b124ca0303755ab6a Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 5 Nov 2024 00:38:39 +0800 Subject: [PATCH 065/156] feat: add type --- packages/volar/src/jsx-directive.ts | 39 +-- packages/volar/src/jsx-directive/context.ts | 58 ++++- packages/volar/src/jsx-directive/index.ts | 16 +- packages/volar/src/jsx-directive/v-for.ts | 25 ++ packages/volar/src/jsx-directive/v-model.ts | 251 ++++++++++---------- packages/volar/src/jsx-directive/v-on.ts | 27 ++- packages/volar/src/jsx-ref.ts | 47 ++-- 7 files changed, 276 insertions(+), 187 deletions(-) diff --git a/packages/volar/src/jsx-directive.ts b/packages/volar/src/jsx-directive.ts index 7a7d527bd..941486754 100644 --- a/packages/volar/src/jsx-directive.ts +++ b/packages/volar/src/jsx-directive.ts @@ -4,23 +4,26 @@ import { REGEX_JSX } from './common' import { transformJsxDirective } from './jsx-directive/index' import type { OptionsResolved } from '@vue-macros/config' -export default createPlugin(({ options = {}, ts }) => { - if (!options) return [] - const filter = createFilter({ - ...options, - include: options.include || REGEX_JSX, +const plugin: PluginReturn = + createPlugin(({ options = {}, ts }) => { + if (!options) return [] + const filter = createFilter({ + ...options, + include: options.include || REGEX_JSX, + }) + + return { + name: 'vue-macros-jsx-directive', + resolveVirtualCode({ ast, codes, fileName, source, languageId }) { + if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return + transformJsxDirective({ + codes, + ast, + ts, + source, + }) + }, + } }) - return { - name: 'vue-macros-jsx-directive', - resolveVirtualCode({ ast, codes, fileName, source, languageId }) { - if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return - transformJsxDirective({ - codes, - ast, - ts, - source, - }) - }, - } -}) as PluginReturn +export default plugin diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 2be3d8bd3..9d6e05ed2 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -7,19 +7,34 @@ import { type TransformOptions, } from './index' -export function transformCtx( - node: JsxDirective['node'], - root: import('typescript').Block | undefined, - index: number, - options: TransformOptions, -): string { - const { ts, codes } = options - - const openingElement = getOpeningElement(node, options) - if (!openingElement) return '' +export type CtxMap = Map< + JsxDirective['node'], + import('typescript').Block | undefined +> - if (!codes.toString().includes('function __VLS_getFunctionalComponentCtx')) { - codes.push(` +export function resolveCtxMap( + ctxNodeMap: CtxMap, + options: TransformOptions, +): Map { + if (ctxNodeMap.size) { + options.codes.push(` +type __VLS_IsAny = 0 extends 1 & T ? true : false; +type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; +type __VLS_Element = __VLS_PickNotAny; +function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): + T extends new (...args: any) => any + ? (props: (K extends { $props: infer Props } ? Props : any) & Record, ctx?: any) => __VLS_Element & { __ctx?: { + attrs?: any, + slots?: K extends { $slots: infer Slots } ? Slots : any, + emit?: K extends { $emit: infer Emit } ? Emit : any + } & { props?: (K extends { $props: infer Props } ? Props : any) & Record; expose?(exposed: K): void; } } + : T extends () => any ? (props: {}, ctx?: any) => ReturnType + : T extends (...args: any) => any ? T + : (_: {} & Record, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {} & Record } }; +const __VLS_nativeElements = { + ...{} as SVGElementTagNameMap, + ...{} as HTMLElementTagNameMap, +}; function __VLS_getFunctionalComponentCtx( comp: T, compInstance: K, @@ -35,6 +50,25 @@ function __VLS_getFunctionalComponentCtx( : {};\n`) } + return new Map( + Array.from(ctxNodeMap).map(([node, root], index) => [ + node, + transformCtx(node, root, index, options), + ]), + ) +} + +export function transformCtx( + node: JsxDirective['node'], + root: import('typescript').Block | undefined, + index: number, + options: TransformOptions, +): string { + const { ts, codes } = options + + const openingElement = getOpeningElement(node, options) + if (!openingElement) return '' + let props = '' let refValue for (const prop of openingElement.attributes.properties) { diff --git a/packages/volar/src/jsx-directive/index.ts b/packages/volar/src/jsx-directive/index.ts index 3cccfb5e2..f72b85b0f 100644 --- a/packages/volar/src/jsx-directive/index.ts +++ b/packages/volar/src/jsx-directive/index.ts @@ -1,5 +1,5 @@ import { getText, isJsxExpression } from '../common' -import { transformCtx } from './context' +import { resolveCtxMap, type CtxMap } from './context' import { transformRef } from './ref' import { transformVBind } from './v-bind' import { transformVFor } from './v-for' @@ -39,10 +39,7 @@ export function transformJsxDirective(options: TransformOptions): void { const refNodes: JsxDirective[] = [] const vSlots: JsxDirective[] = [] - const ctxNodeMap = new Map< - JsxDirective['node'], - import('typescript').Block | undefined - >() + const ctxNodeMap: CtxMap = new Map() function walkJsxDirective( node: import('typescript').Node, @@ -195,17 +192,12 @@ export function transformJsxDirective(options: TransformOptions): void { } ts.forEachChild(ast, walkJsxDirective) - const ctxMap = new Map( - Array.from(ctxNodeMap).map(([node, root], index) => [ - node, - transformCtx(node, root, index, options), - ]), - ) + const ctxMap = resolveCtxMap(ctxNodeMap, options) transformVSlot(vSlotMap, ctxMap, options) transformVFor(vForNodes, options) vIfMap.forEach((nodes) => transformVIf(nodes, options)) - vModelMap.forEach((nodes) => transformVModel(nodes, ctxMap, options)) + transformVModel(vModelMap, ctxMap, options) transformVOn(vOnNodes, ctxMap, options) transformVOnWithModifiers(vOnWithModifiers, options) transformVBind(vBindNodes, options) diff --git a/packages/volar/src/jsx-directive/v-for.ts b/packages/volar/src/jsx-directive/v-for.ts index 2ccb12ebe..2bcb29911 100644 --- a/packages/volar/src/jsx-directive/v-for.ts +++ b/packages/volar/src/jsx-directive/v-for.ts @@ -89,6 +89,7 @@ export function transformVFor( nodes: JsxDirective[], options: TransformOptions, ): void { + if (!nodes.length) return const { codes, source } = options nodes.forEach(({ attribute, node, parent }) => { @@ -114,4 +115,28 @@ export function transformVFor( attribute.end, ) }) + + codes.push(` +function __VLS_getVForSourceType(source: number): [number, number, number][]; +function __VLS_getVForSourceType(source: string): [string, number, number][]; +function __VLS_getVForSourceType(source: T): [ + item: T[number], + key: number, + index: number, +][]; +function __VLS_getVForSourceType }>(source: T): [ + item: T extends { [Symbol.iterator](): Iterator } ? T1 : never, + key: number, + index: undefined, +][]; +function __VLS_getVForSourceType }>(source: T): [ + item: number | (Exclude extends { [Symbol.iterator](): Iterator } ? T1 : never), + key: number, + index: undefined, +][]; +function __VLS_getVForSourceType(source: T): [ + item: T[keyof T], + key: keyof T, + index: number, +][];\n`) } diff --git a/packages/volar/src/jsx-directive/v-model.ts b/packages/volar/src/jsx-directive/v-model.ts index 7a02e435b..d357231da 100644 --- a/packages/volar/src/jsx-directive/v-model.ts +++ b/packages/volar/src/jsx-directive/v-model.ts @@ -4,152 +4,159 @@ import { getStart, getText, isJsxExpression } from '../common' import { getTagName, type JsxDirective, type TransformOptions } from './index' export function transformVModel( - nodes: JsxDirective[], + nodeMap: Map, ctxMap: Map, options: TransformOptions, ): void { + if (!nodeMap.size) return const { codes, ts, source, ast } = options - let firstNamespacedNode: - | { - attribute: JsxDirective['attribute'] - node: JsxDirective['node'] - attributeName: string - } - | undefined + for (const [, nodes] of nodeMap) { + let firstNamespacedNode: + | { + attribute: JsxDirective['attribute'] + node: JsxDirective['node'] + attributeName: string + } + | undefined - const result: Code[] = [] - const emits: string[] = [] - for (const { attribute, node } of nodes) { - const modelValue = ['input', 'select', 'textarea'].includes( - getTagName(node, options), - ) - ? 'value' - : 'modelValue' - const isArrayExpression = - isJsxExpression(attribute.initializer) && - attribute.initializer.expression && - ts.isArrayLiteralExpression(attribute.initializer.expression) + const result: Code[] = [] + const emits: string[] = [] + for (const { attribute, node } of nodes) { + const modelValue = ['input', 'select', 'textarea'].includes( + getTagName(node, options), + ) + ? 'value' + : 'modelValue' + const isArrayExpression = + isJsxExpression(attribute.initializer) && + attribute.initializer.expression && + ts.isArrayLiteralExpression(attribute.initializer.expression) - const name = getText(attribute.name, options) - const start = getStart(attribute.name, options) - if (name.startsWith('v-model:') || isArrayExpression) { - let isDynamic = false - const attributeName = name - .slice(8) - .split(/\s/)[0] - .split('_')[0] - .replace(/^\$(.*)\$/, (_, $1) => { - isDynamic = true - return $1 - }) - firstNamespacedNode ??= { - attribute, - attributeName, - node, - } - if (firstNamespacedNode.attribute !== attribute) { - replaceSourceRange( - codes, - source, - getStart(attribute, options), - attribute.end, - ) - result.push(',') - } + const name = getText(attribute.name, options) + const start = getStart(attribute.name, options) + if (name.startsWith('v-model:') || isArrayExpression) { + let isDynamic = false + const attributeName = name + .slice(8) + .split(/\s/)[0] + .split('_')[0] + .replace(/^\$(.*)\$/, (_, $1) => { + isDynamic = true + return $1 + }) + firstNamespacedNode ??= { + attribute, + attributeName, + node, + } + if (firstNamespacedNode.attribute !== attribute) { + replaceSourceRange( + codes, + source, + getStart(attribute, options), + attribute.end, + ) + result.push(',') + } - if (isArrayExpression) { - const { elements } = attribute.initializer.expression - if (elements[1] && !ts.isArrayLiteralExpression(elements[1])) { - isDynamic = !ts.isStringLiteral(elements[1]) - result.push( - isDynamic ? '[`${' : '', - [ - getText(elements[1], options), + if (isArrayExpression) { + const { elements } = attribute.initializer.expression + if (elements[1] && !ts.isArrayLiteralExpression(elements[1])) { + isDynamic = !ts.isStringLiteral(elements[1]) + result.push( + isDynamic ? '[`${' : '', + [ + getText(elements[1], options), + source, + getStart(elements[1], options), + allCodeFeatures, + ], + isDynamic ? '}`]' : '', + ) + } else { + result.push(modelValue) + } + + if (elements[0]) + result.push(':', [ + getText(elements[0], options), source, - getStart(elements[1], options), + getStart(elements[0], options), allCodeFeatures, - ], + ]) + } else { + result.push( + isDynamic ? '[`${' : '', + ...(attributeName + .split('-') + .map((code, index, codes) => [ + index ? code.at(0)?.toUpperCase() + code.slice(1) : code, + source, + start + + (isDynamic ? 9 : 8) + + (index && codes[index - 1].length + 1), + allCodeFeatures, + ]) as Code[]), isDynamic ? '}`]' : '', ) - } else { - result.push(modelValue) - } - if (elements[0]) - result.push(':', [ - getText(elements[0], options), - source, - getStart(elements[0], options), - allCodeFeatures, - ]) - } else { - result.push( - isDynamic ? '[`${' : '', - ...(attributeName - .split('-') - .map((code, index, codes) => [ - index ? code.at(0)?.toUpperCase() + code.slice(1) : code, + if ( + attribute.initializer && + isJsxExpression(attribute.initializer) && + attribute.initializer.expression && + attributeName + ) + result.push(':', [ + getText(attribute.initializer.expression, options), source, - start + - (isDynamic ? 9 : 8) + - (index && codes[index - 1].length + 1), + getStart(attribute.initializer.expression, options), allCodeFeatures, - ]) as Code[]), - isDynamic ? '}`]' : '', - ) + ]) + } - if ( - attribute.initializer && - isJsxExpression(attribute.initializer) && - attribute.initializer.expression && - attributeName + emits.push(`'onUpdate:${attributeName}': () => {}, `) + } else { + replaceSourceRange( + codes, + source, + start, + attribute.name.end, + `{...{'onUpdate:${modelValue}': () => {} }} `, + modelValue.slice(0, 3), + [modelValue.slice(3), source, start, allCodeFeatures], ) - result.push(':', [ - getText(attribute.initializer.expression, options), - source, - getStart(attribute.initializer.expression, options), - allCodeFeatures, - ]) } - - emits.push(`'onUpdate:${attributeName}': () => {}, `) - } else { - replaceSourceRange( - codes, - source, - start, - attribute.name.end, - `{...{'onUpdate:${modelValue}': () => {} }} `, - modelValue.slice(0, 3), - [modelValue.slice(3), source, start, allCodeFeatures], - ) } + + if (!firstNamespacedNode) return + const { attribute, attributeName, node } = firstNamespacedNode + const end = attributeName ? attribute.end : getStart(attribute, options) + 8 + replaceSourceRange( + codes, + source, + getStart(attribute, options), + end, + `{...{`, + ...result, + `} satisfies __VLS_GetModels<__VLS_NormalizeProps>}`, + ` {...{`, + ...emits, + `}}`, + ) + // Fix `v-model:` without type hints + replaceSourceRange( + codes, + source, + end, + end + 1, + ast.text.slice(end, end + 1), + ) } - if (!firstNamespacedNode) return - const { attribute, attributeName, node } = firstNamespacedNode getModelsType(codes) - - const end = attributeName ? attribute.end : getStart(attribute, options) + 8 - replaceSourceRange( - codes, - source, - getStart(attribute, options), - end, - `{...{`, - ...result, - `} satisfies __VLS_GetModels<__VLS_NormalizeProps>}`, - ` {...{`, - ...emits, - `}}`, - ) - // Fix `v-model:` without type hints - replaceSourceRange(codes, source, end, end + 1, ast.text.slice(end, end + 1)) } function getModelsType(codes: Code[]) { - if (codes.toString().includes('type __VLS_GetModels')) return - codes.push(` type __VLS_NormalizeProps = T extends object ? { diff --git a/packages/volar/src/jsx-directive/v-on.ts b/packages/volar/src/jsx-directive/v-on.ts index 8660417f5..c64a68b60 100644 --- a/packages/volar/src/jsx-directive/v-on.ts +++ b/packages/volar/src/jsx-directive/v-on.ts @@ -8,7 +8,7 @@ export function transformVOn( ctxMap: Map, { codes, source }: TransformOptions, ): void { - if (nodes.length === 0) return + if (!nodes.length) return for (const { node, attribute } of nodes) { replaceSourceRange( @@ -19,6 +19,31 @@ export function transformVOn( ` satisfies __VLS_NormalizeEmits`, ) } + + codes.push(` +type __VLS_UnionToIntersection = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never; +type __VLS_OverloadUnionInner = U & T extends (...args: infer A) => infer R + ? U extends T + ? never + : __VLS_OverloadUnionInner & U & ((...args: A) => R)> | ((...args: A) => R) + : never; +type __VLS_OverloadUnion = Exclude< + __VLS_OverloadUnionInner<(() => never) & T>, + T extends () => never ? never : () => never +>; +type __VLS_ConstructorOverloads = __VLS_OverloadUnion extends infer F + ? F extends (event: infer E, ...args: infer A) => any + ? { [K in E & string]: (...args: A) => void; } + : never + : never; +type __VLS_NormalizeEmits = __VLS_PrettifyGlobal< + __VLS_UnionToIntersection< + __VLS_ConstructorOverloads & { + [K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never + } + > +>; +type __VLS_PrettifyGlobal = { [K in keyof T]: T[K]; } & {};\n`) } export function transformVOnWithModifiers( diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index d8b8b8ec2..34fa43cd8 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -76,27 +76,30 @@ function getRefNodes( return result } -export default createPlugin(({ options = {}, ts }) => { - if (!options) return [] - const filter = createFilter({ - ...options, - include: options.include || REGEX_JSX, +const plugin: PluginReturn = + createPlugin(({ options = {}, ts }) => { + if (!options) return [] + const filter = createFilter({ + ...options, + include: options.include || REGEX_JSX, + }) + const alias = options.alias || ['useRef'] + + return { + name: 'vue-macros-jsx-ref', + resolveVirtualCode({ ast, codes, fileName, source, languageId }) { + if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return + const nodes = getRefNodes(ts, ast, alias) + if (nodes.length) { + transformRef({ + nodes, + codes, + ts, + source, + }) + } + }, + } }) - const alias = options.alias || ['useRef'] - return { - name: 'vue-macros-jsx-ref', - resolveVirtualCode({ ast, codes, fileName, source, languageId }) { - if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return - const nodes = getRefNodes(ts, ast, alias) - if (nodes.length) { - transformRef({ - nodes, - codes, - ts, - source, - }) - } - }, - } -}) as PluginReturn +export default plugin From 140675b975fbf65ba62bd745396f4678f0faf77c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 5 Nov 2024 00:40:27 +0800 Subject: [PATCH 066/156] fix: typo --- packages/volar/src/jsx-directive/v-slot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-directive/v-slot.ts b/packages/volar/src/jsx-directive/v-slot.ts index dad28c2ce..3daba536f 100644 --- a/packages/volar/src/jsx-directive/v-slot.ts +++ b/packages/volar/src/jsx-directive/v-slot.ts @@ -113,7 +113,7 @@ export function transformVSlot( return isSlotTemplate && ts.isJsxSelfClosingElement(child) ? '' : ([ - ast!.text.slice(node.pos, node.end), + ast.text.slice(node.pos, node.end), source, node.pos, allCodeFeatures, From e55dac6c5783db9a6fcf2d3922b960af5f7033a4 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 5 Nov 2024 18:32:43 +0800 Subject: [PATCH 067/156] fix: filter --- packages/volar/package.json | 2 +- packages/volar/src/common.ts | 1 - packages/volar/src/jsx-directive.ts | 8 +--- packages/volar/src/jsx-directive/context.ts | 20 ++++----- packages/volar/src/jsx-directive/v-model.ts | 8 +++- packages/volar/src/jsx-ref.ts | 8 +--- pnpm-lock.yaml | 49 ++++++--------------- pnpm-workspace.yaml | 4 +- 8 files changed, 38 insertions(+), 62 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index 767b86e77..bfa50be0c 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -281,7 +281,7 @@ "@vue-macros/short-vmodel": "workspace:*", "@vue/language-core": "catalog:", "muggle-string": "^0.4.1", - "ts-macro": "^0.0.2" + "ts-macro": "^0.0.3" }, "devDependencies": { "@vue/compiler-dom": "catalog:", diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts index 3f9a2f2fe..8823f8fd6 100644 --- a/packages/volar/src/common.ts +++ b/packages/volar/src/common.ts @@ -9,7 +9,6 @@ import { replace, replaceAll } from 'muggle-string' import type { SFCScriptBlock } from '@vue-macros/common' import type { Code, Sfc, VueLanguagePlugin } from '@vue/language-core' -export const REGEX_JSX: RegExp = /\.[jt]sx$/ export const REGEX_DEFINE_COMPONENT: RegExp = /(?<=(?:__VLS_|\(await import\(\S+\)\)\.)defineComponent\(\{\n)/g diff --git a/packages/volar/src/jsx-directive.ts b/packages/volar/src/jsx-directive.ts index 941486754..2ba2a8493 100644 --- a/packages/volar/src/jsx-directive.ts +++ b/packages/volar/src/jsx-directive.ts @@ -1,21 +1,17 @@ import { createFilter } from '@vue-macros/common' import { createPlugin, type PluginReturn } from 'ts-macro' -import { REGEX_JSX } from './common' import { transformJsxDirective } from './jsx-directive/index' import type { OptionsResolved } from '@vue-macros/config' const plugin: PluginReturn = createPlugin(({ options = {}, ts }) => { if (!options) return [] - const filter = createFilter({ - ...options, - include: options.include || REGEX_JSX, - }) + const filter = createFilter(options) return { name: 'vue-macros-jsx-directive', resolveVirtualCode({ ast, codes, fileName, source, languageId }) { - if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return + if (!filter(fileName) || !['jsx', 'tsx'].includes(languageId)) return transformJsxDirective({ codes, ast, diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 9d6e05ed2..78353042a 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -20,17 +20,17 @@ export function resolveCtxMap( options.codes.push(` type __VLS_IsAny = 0 extends 1 & T ? true : false; type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; -type __VLS_Element = __VLS_PickNotAny; +type __VLS_Element = globalThis.JSX.Element; function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): - T extends new (...args: any) => any - ? (props: (K extends { $props: infer Props } ? Props : any) & Record, ctx?: any) => __VLS_Element & { __ctx?: { - attrs?: any, - slots?: K extends { $slots: infer Slots } ? Slots : any, - emit?: K extends { $emit: infer Emit } ? Emit : any - } & { props?: (K extends { $props: infer Props } ? Props : any) & Record; expose?(exposed: K): void; } } - : T extends () => any ? (props: {}, ctx?: any) => ReturnType - : T extends (...args: any) => any ? T - : (_: {} & Record, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {} & Record } }; + T extends new (...args: any) => any + ? (props: (K extends { $props: infer Props } ? Props : any) & Record, ctx?: any) => __VLS_Element & { __ctx?: { + attrs?: any, + slots?: K extends { $scopedSlots: infer Slots } ? Slots : K extends { $slots: infer Slots } ? Slots : any, + emit?: K extends { $emit: infer Emit } ? Emit : any + } & { props?: (K extends { $props: infer Props } ? Props : any) & Record; expose?(exposed: K): void; } } + : T extends () => any ? (props: {}, ctx?: any) => ReturnType + : T extends (...args: any) => any ? T + : (_: {} & Record, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {} & Record } }; const __VLS_nativeElements = { ...{} as SVGElementTagNameMap, ...{} as HTMLElementTagNameMap, diff --git a/packages/volar/src/jsx-directive/v-model.ts b/packages/volar/src/jsx-directive/v-model.ts index d357231da..ee7800197 100644 --- a/packages/volar/src/jsx-directive/v-model.ts +++ b/packages/volar/src/jsx-directive/v-model.ts @@ -121,10 +121,16 @@ export function transformVModel( source, start, attribute.name.end, - `{...{'onUpdate:${modelValue}': () => {} }} `, modelValue.slice(0, 3), [modelValue.slice(3), source, start, allCodeFeatures], ) + replaceSourceRange( + codes, + source, + attribute.end, + attribute.end, + ` {...{'onUpdate:${modelValue}': () => {} }}`, + ) } } diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index 34fa43cd8..61931c539 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -1,7 +1,6 @@ import { createFilter } from '@vue-macros/common' import { replaceSourceRange } from 'muggle-string' import { createPlugin, type PluginReturn } from 'ts-macro' -import { REGEX_JSX } from './common' import type { OptionsResolved } from '@vue-macros/config' import type { Code } from '@vue/language-core' @@ -79,16 +78,13 @@ function getRefNodes( const plugin: PluginReturn = createPlugin(({ options = {}, ts }) => { if (!options) return [] - const filter = createFilter({ - ...options, - include: options.include || REGEX_JSX, - }) + const filter = createFilter(options) const alias = options.alias || ['useRef'] return { name: 'vue-macros-jsx-ref', resolveVirtualCode({ ast, codes, fileName, source, languageId }) { - if (!filter(fileName) && !['jsx', 'tsx'].includes(languageId)) return + if (!filter(fileName) || !['jsx', 'tsx'].includes(languageId)) return const nodes = getRefNodes(ts, ast, alias) if (nodes.length) { transformRef({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 93a1f5552..c00d0c098 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,8 +19,8 @@ catalogs: specifier: ^3.5.12 version: 3.5.12 '@vue/language-core': - specifier: 2.1.8 - version: 2.1.8 + specifier: 2.1.10 + version: 2.1.10 '@vue/shared': specifier: ^3.5.12 version: 3.5.12 @@ -40,8 +40,8 @@ catalogs: specifier: ^3.5.12 version: 3.5.12 vue-tsc: - specifier: 2.1.8 - version: 2.1.8 + specifier: 2.1.10 + version: 2.1.10 overrides: esbuild: ^0.24.0 @@ -177,7 +177,7 @@ importers: version: 3.5.12(typescript@5.6.3) vue-tsc: specifier: 'catalog:' - version: 2.1.8(typescript@5.6.3) + version: 2.1.10(typescript@5.6.3) vue2: specifier: npm:vue@^2.7.16 version: vue@2.7.16 @@ -789,7 +789,7 @@ importers: version: 3.13.2(rollup@4.24.4)(webpack-sources@3.2.3) '@vue/language-core': specifier: 'catalog:' - version: 2.1.8(typescript@5.6.3) + version: 2.1.10(typescript@5.6.3) packages/reactivity-transform: dependencies: @@ -951,7 +951,7 @@ importers: version: link:../short-vmodel '@vue/language-core': specifier: 'catalog:' - version: 2.1.8(typescript@5.6.3) + version: 2.1.10(typescript@5.6.3) muggle-string: specifier: ^0.4.1 version: 0.4.1 @@ -967,7 +967,7 @@ importers: version: 5.6.3 vue-tsc: specifier: 'catalog:' - version: 2.1.8(typescript@5.6.3) + version: 2.1.10(typescript@5.6.3) playground/astro: dependencies: @@ -1055,7 +1055,7 @@ importers: version: 0.12.0(@stylexjs/stylex@0.9.3)(vite@5.4.10(@types/node@22.8.7)(less@4.2.0)(terser@5.36.0)) vue-tsc: specifier: 'catalog:' - version: 2.1.8(typescript@5.6.3) + version: 2.1.10(typescript@5.6.3) playground/vue3: dependencies: @@ -1125,7 +1125,7 @@ importers: version: 0.12.0(@stylexjs/stylex@0.9.3)(vite@5.4.10(@types/node@22.8.7)(less@4.2.0)(terser@5.36.0)) vue-tsc: specifier: 'catalog:' - version: 2.1.8(typescript@5.6.3) + version: 2.1.10(typescript@5.6.3) packages: @@ -3101,14 +3101,6 @@ packages: typescript: optional: true - '@vue/language-core@2.1.8': - resolution: {integrity: sha512-DtPUKrIRqqzY1joGfVHxHWZoxXZbCQLmVtW+QTifuPInfcs1R/3UAdlJXDp+lpSpP9lI5m+jMYYlwDXXu3KSTg==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@vue/reactivity@3.5.12': resolution: {integrity: sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==} @@ -6451,8 +6443,8 @@ packages: peerDependencies: vue: ^3.0.0 - vue-tsc@2.1.8: - resolution: {integrity: sha512-6+vjb7JLxKIzeD/1ktoUBZGAr+148FQoEFl8Lv5EpDJLO2PrUalhp7atMEuzEkLnoooM5bg3pJqjZI+oobxIaQ==} + vue-tsc@2.1.10: + resolution: {integrity: sha512-RBNSfaaRHcN5uqVqJSZh++Gy/YUzryuv9u1aFWhsammDJXNtUiJMNoJ747lZcQ68wUQFx6E73y4FY3D8E7FGMA==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -9259,19 +9251,6 @@ snapshots: optionalDependencies: typescript: 5.6.3 - '@vue/language-core@2.1.8(typescript@5.6.3)': - dependencies: - '@volar/language-core': 2.4.8 - '@vue/compiler-dom': 3.5.12 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.12 - alien-signals: 0.2.0 - minimatch: 9.0.5 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - optionalDependencies: - typescript: 5.6.3 - '@vue/reactivity@3.5.12': dependencies: '@vue/shared': 3.5.12 @@ -13315,10 +13294,10 @@ snapshots: dependencies: vue: 3.5.12(typescript@5.6.3) - vue-tsc@2.1.8(typescript@5.6.3): + vue-tsc@2.1.10(typescript@5.6.3): dependencies: '@volar/typescript': 2.4.8 - '@vue/language-core': 2.1.8(typescript@5.6.3) + '@vue/language-core': 2.1.10(typescript@5.6.3) semver: 7.6.3 typescript: 5.6.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f5c473040..e180a4c7c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,7 +5,7 @@ catalog: '@vue/compiler-core': ^3.5.12 '@vue/compiler-dom': ^3.5.12 '@vue/compiler-sfc': ^3.5.12 - '@vue/language-core': 2.1.8 + '@vue/language-core': 2.1.10 '@vue/reactivity': ^3.5.12 '@vue/runtime-core': ^3.5.12 '@vue/runtime-dom': ^3.5.12 @@ -15,7 +15,7 @@ catalog: vite: ^5.4.10 vite-plugin-stylex: ^0.12.0 vue: ^3.5.12 - vue-tsc: 2.1.8 + vue-tsc: 2.1.10 packages: - packages/* - playground/* From bdbd04c5a9f3ad5f0c12b371acc67c1de8e16499 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 5 Nov 2024 18:34:06 +0800 Subject: [PATCH 068/156] fix: pnpm-lock --- pnpm-lock.yaml | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c00d0c098..89740c4a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -956,8 +956,8 @@ importers: specifier: ^0.4.1 version: 0.4.1 ts-macro: - specifier: ^0.0.2 - version: 0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3) + specifier: ^0.0.3 + version: 0.0.3(@volar/language-service@2.4.8) devDependencies: '@vue/compiler-dom': specifier: 'catalog:' @@ -2675,8 +2675,8 @@ packages: peerDependencies: vue: ^2.7.0 || ^3.0.0 - '@ts-macro/language-server@0.0.2': - resolution: {integrity: sha512-GMSsLyIwPz6uWlUX1PwcrbyiHBGecz3owbzjGOURYp/asXiZlHM8/yzaTrKDXhxEr8NM9aszyIiWvjJ7CY6rCA==} + '@ts-macro/language-server@0.0.3': + resolution: {integrity: sha512-F5tPW7fHnYMDDze8Km7T7LDSl1J0fd+TDGU0FLIfYYBpbgyoGs1vmreAoPPa0JBAy7NxQ391Ny9Rx4zv+noKYQ==} hasBin: true '@tybys/wasm-util@0.9.0': @@ -5962,8 +5962,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-macro@0.0.2: - resolution: {integrity: sha512-M1LWmpRJu5CvpS21qBbcrx75wWpppOXGYOirRg2zWqfVlxf5D1oDXHrrkAqRF35bCYEhKkJ/o7fzWzZ8IGXeVw==} + ts-macro@0.0.3: + resolution: {integrity: sha512-cBVqNDfaix04u1c72HjK32j1LfTPvO2axNCNthhYhTlrr+ImYBk/qb2hzfm8nSffulMkhxy20/8NRJ0vaL91Lg==} tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} @@ -8547,16 +8547,15 @@ snapshots: '@tanstack/virtual-core': 3.10.8 vue: 3.5.12(typescript@5.6.3) - '@ts-macro/language-server@0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3)': + '@ts-macro/language-server@0.0.3(@volar/language-service@2.4.8)': dependencies: '@volar/language-server': 2.4.8 - ts-macro: 0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3) + ts-macro: 0.0.3(@volar/language-service@2.4.8) volar-service-css: 0.0.62(@volar/language-service@2.4.8) volar-service-emmet: 0.0.62(@volar/language-service@2.4.8) volar-service-typescript: 0.0.62(@volar/language-service@2.4.8) transitivePeerDependencies: - '@volar/language-service' - - typescript '@tybys/wasm-util@0.9.0': dependencies: @@ -12602,18 +12601,16 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-macro@0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3): + ts-macro@0.0.3(@volar/language-service@2.4.8): dependencies: - '@ts-macro/language-server': 0.0.2(@volar/language-service@2.4.8)(typescript@5.6.3) + '@ts-macro/language-server': 0.0.3(@volar/language-service@2.4.8) '@volar/language-core': 2.4.8 '@volar/typescript': 2.4.8 - '@vue/language-core': 2.1.10(typescript@5.6.3) jiti: 2.3.3 muggle-string: 0.4.1 vscode-uri: 3.0.8 transitivePeerDependencies: - '@volar/language-service' - - typescript tsconfck@3.1.4(typescript@5.6.3): optionalDependencies: From f8f0135a3545ea9aaf0bad25a36ae94db46307d6 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 6 Nov 2024 00:29:31 +0800 Subject: [PATCH 069/156] chore: update ts-macros --- packages/volar/package.json | 2 +- packages/volar/src/jsx-directive.ts | 2 +- packages/volar/src/jsx-ref.ts | 4 ++-- pnpm-lock.yaml | 23 +++++++++++++---------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index bfa50be0c..b09b9ae7a 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -281,7 +281,7 @@ "@vue-macros/short-vmodel": "workspace:*", "@vue/language-core": "catalog:", "muggle-string": "^0.4.1", - "ts-macro": "^0.0.3" + "ts-macro": "^0.0.4" }, "devDependencies": { "@vue/compiler-dom": "catalog:", diff --git a/packages/volar/src/jsx-directive.ts b/packages/volar/src/jsx-directive.ts index 2ba2a8493..58b8849b0 100644 --- a/packages/volar/src/jsx-directive.ts +++ b/packages/volar/src/jsx-directive.ts @@ -4,7 +4,7 @@ import { transformJsxDirective } from './jsx-directive/index' import type { OptionsResolved } from '@vue-macros/config' const plugin: PluginReturn = - createPlugin(({ options = {}, ts }) => { + createPlugin(({ ts }, options = {}) => { if (!options) return [] const filter = createFilter(options) diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index 61931c539..57cfc7767 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -52,7 +52,7 @@ function getRefNodes( const result: RefNode[] = [] function walk(node: import('typescript').Node) { if (ts.isVariableStatement(node)) { - return ts.forEachChild(node.declarationList, (decl) => { + ts.forEachChild(node.declarationList, (decl) => { if ( ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name) && @@ -76,7 +76,7 @@ function getRefNodes( } const plugin: PluginReturn = - createPlugin(({ options = {}, ts }) => { + createPlugin(({ ts }, options = {}) => { if (!options) return [] const filter = createFilter(options) const alias = options.alias || ['useRef'] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89740c4a2..575745b6f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -956,8 +956,8 @@ importers: specifier: ^0.4.1 version: 0.4.1 ts-macro: - specifier: ^0.0.3 - version: 0.0.3(@volar/language-service@2.4.8) + specifier: ^0.0.4 + version: 0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3) devDependencies: '@vue/compiler-dom': specifier: 'catalog:' @@ -2675,8 +2675,8 @@ packages: peerDependencies: vue: ^2.7.0 || ^3.0.0 - '@ts-macro/language-server@0.0.3': - resolution: {integrity: sha512-F5tPW7fHnYMDDze8Km7T7LDSl1J0fd+TDGU0FLIfYYBpbgyoGs1vmreAoPPa0JBAy7NxQ391Ny9Rx4zv+noKYQ==} + '@ts-macro/language-server@0.0.4': + resolution: {integrity: sha512-Y7aJFE/p/XyWViPxU0zIsiwLhExkOr6zEujimLeqPqY+b32vEttOQkEfiNYxCY6cUC8U5/wQmq/wePgrWO5/Vw==} hasBin: true '@tybys/wasm-util@0.9.0': @@ -5962,8 +5962,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-macro@0.0.3: - resolution: {integrity: sha512-cBVqNDfaix04u1c72HjK32j1LfTPvO2axNCNthhYhTlrr+ImYBk/qb2hzfm8nSffulMkhxy20/8NRJ0vaL91Lg==} + ts-macro@0.0.4: + resolution: {integrity: sha512-1A26REuo5iybl8ChEEcmahLo0rrzx5iXWz4hMGxaGYn0gimYRW2Wjz0wqJVAwjBoencg56WhOR/uRcdE752/+A==} tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} @@ -8547,15 +8547,16 @@ snapshots: '@tanstack/virtual-core': 3.10.8 vue: 3.5.12(typescript@5.6.3) - '@ts-macro/language-server@0.0.3(@volar/language-service@2.4.8)': + '@ts-macro/language-server@0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3)': dependencies: '@volar/language-server': 2.4.8 - ts-macro: 0.0.3(@volar/language-service@2.4.8) + ts-macro: 0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3) volar-service-css: 0.0.62(@volar/language-service@2.4.8) volar-service-emmet: 0.0.62(@volar/language-service@2.4.8) volar-service-typescript: 0.0.62(@volar/language-service@2.4.8) transitivePeerDependencies: - '@volar/language-service' + - typescript '@tybys/wasm-util@0.9.0': dependencies: @@ -12601,16 +12602,18 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-macro@0.0.3(@volar/language-service@2.4.8): + ts-macro@0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3): dependencies: - '@ts-macro/language-server': 0.0.3(@volar/language-service@2.4.8) + '@ts-macro/language-server': 0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3) '@volar/language-core': 2.4.8 '@volar/typescript': 2.4.8 + '@vue/language-core': 2.1.10(typescript@5.6.3) jiti: 2.3.3 muggle-string: 0.4.1 vscode-uri: 3.0.8 transitivePeerDependencies: - '@volar/language-service' + - typescript tsconfck@3.1.4(typescript@5.6.3): optionalDependencies: From 5595191fbe910e526808ae9265106eac650d12ba Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 8 Nov 2024 08:39:22 +0800 Subject: [PATCH 070/156] fix: v-model --- packages/volar/src/jsx-directive/v-model.ts | 269 ++++++++++---------- 1 file changed, 136 insertions(+), 133 deletions(-) diff --git a/packages/volar/src/jsx-directive/v-model.ts b/packages/volar/src/jsx-directive/v-model.ts index ee7800197..3208a3f95 100644 --- a/packages/volar/src/jsx-directive/v-model.ts +++ b/packages/volar/src/jsx-directive/v-model.ts @@ -9,157 +9,160 @@ export function transformVModel( options: TransformOptions, ): void { if (!nodeMap.size) return - const { codes, ts, source, ast } = options + for (const [, nodes] of nodeMap) { - let firstNamespacedNode: - | { - attribute: JsxDirective['attribute'] - node: JsxDirective['node'] - attributeName: string - } - | undefined + transform(nodes, ctxMap, options) + } - const result: Code[] = [] - const emits: string[] = [] - for (const { attribute, node } of nodes) { - const modelValue = ['input', 'select', 'textarea'].includes( - getTagName(node, options), - ) - ? 'value' - : 'modelValue' - const isArrayExpression = - isJsxExpression(attribute.initializer) && - attribute.initializer.expression && - ts.isArrayLiteralExpression(attribute.initializer.expression) + getModelsType(options.codes) +} - const name = getText(attribute.name, options) - const start = getStart(attribute.name, options) - if (name.startsWith('v-model:') || isArrayExpression) { - let isDynamic = false - const attributeName = name - .slice(8) - .split(/\s/)[0] - .split('_')[0] - .replace(/^\$(.*)\$/, (_, $1) => { - isDynamic = true - return $1 - }) - firstNamespacedNode ??= { - attribute, - attributeName, - node, - } - if (firstNamespacedNode.attribute !== attribute) { - replaceSourceRange( - codes, - source, - getStart(attribute, options), - attribute.end, - ) - result.push(',') - } +function transform( + nodes: JsxDirective[], + ctxMap: Map, + options: TransformOptions, +) { + const { codes, ts, source, ast } = options + let firstNamespacedNode: + | { + attribute: JsxDirective['attribute'] + node: JsxDirective['node'] + attributeName: string + } + | undefined - if (isArrayExpression) { - const { elements } = attribute.initializer.expression - if (elements[1] && !ts.isArrayLiteralExpression(elements[1])) { - isDynamic = !ts.isStringLiteral(elements[1]) - result.push( - isDynamic ? '[`${' : '', - [ - getText(elements[1], options), - source, - getStart(elements[1], options), - allCodeFeatures, - ], - isDynamic ? '}`]' : '', - ) - } else { - result.push(modelValue) - } + const result: Code[] = [] + const emits: string[] = [] + for (const { attribute, node } of nodes) { + const modelValue = ['input', 'select', 'textarea'].includes( + getTagName(node, options), + ) + ? 'value' + : 'modelValue' + const isArrayExpression = + isJsxExpression(attribute.initializer) && + attribute.initializer.expression && + ts.isArrayLiteralExpression(attribute.initializer.expression) - if (elements[0]) - result.push(':', [ - getText(elements[0], options), - source, - getStart(elements[0], options), - allCodeFeatures, - ]) - } else { + const name = getText(attribute.name, options) + const start = getStart(attribute.name, options) + if (name.startsWith('v-model:') || isArrayExpression) { + let isDynamic = false + const attributeName = name + .slice(8) + .split(/\s/)[0] + .split('_')[0] + .replace(/^\$(.*)\$/, (_, $1) => { + isDynamic = true + return $1 + }) + firstNamespacedNode ??= { + attribute, + attributeName, + node, + } + if (firstNamespacedNode.attribute !== attribute) { + replaceSourceRange( + codes, + source, + getStart(attribute, options), + attribute.end, + ) + result.push(',') + } + + if (isArrayExpression) { + const { elements } = attribute.initializer.expression + if (elements[1] && !ts.isArrayLiteralExpression(elements[1])) { + isDynamic = !ts.isStringLiteral(elements[1]) result.push( isDynamic ? '[`${' : '', - ...(attributeName - .split('-') - .map((code, index, codes) => [ - index ? code.at(0)?.toUpperCase() + code.slice(1) : code, - source, - start + - (isDynamic ? 9 : 8) + - (index && codes[index - 1].length + 1), - allCodeFeatures, - ]) as Code[]), - isDynamic ? '}`]' : '', - ) - - if ( - attribute.initializer && - isJsxExpression(attribute.initializer) && - attribute.initializer.expression && - attributeName - ) - result.push(':', [ - getText(attribute.initializer.expression, options), + [ + getText(elements[1], options), source, - getStart(attribute.initializer.expression, options), + getStart(elements[1], options), allCodeFeatures, - ]) + ], + isDynamic ? '}`]' : '', + ) + } else { + result.push(modelValue) } - emits.push(`'onUpdate:${attributeName}': () => {}, `) + if (elements[0]) + result.push(':', [ + getText(elements[0], options), + source, + getStart(elements[0], options), + allCodeFeatures, + ]) } else { - replaceSourceRange( - codes, - source, - start, - attribute.name.end, - modelValue.slice(0, 3), - [modelValue.slice(3), source, start, allCodeFeatures], + result.push( + isDynamic ? '[`${' : '', + ...(attributeName + .split('-') + .map((code, index, codes) => [ + index ? code.at(0)?.toUpperCase() + code.slice(1) : code, + source, + start + + (isDynamic ? 9 : 8) + + (index && codes[index - 1].length + 1), + allCodeFeatures, + ]) as Code[]), + isDynamic ? '}`]' : '', ) - replaceSourceRange( - codes, - source, - attribute.end, - attribute.end, - ` {...{'onUpdate:${modelValue}': () => {} }}`, + + if ( + attribute.initializer && + isJsxExpression(attribute.initializer) && + attribute.initializer.expression && + attributeName ) + result.push(':', [ + getText(attribute.initializer.expression, options), + source, + getStart(attribute.initializer.expression, options), + allCodeFeatures, + ]) } - } - if (!firstNamespacedNode) return - const { attribute, attributeName, node } = firstNamespacedNode - const end = attributeName ? attribute.end : getStart(attribute, options) + 8 - replaceSourceRange( - codes, - source, - getStart(attribute, options), - end, - `{...{`, - ...result, - `} satisfies __VLS_GetModels<__VLS_NormalizeProps>}`, - ` {...{`, - ...emits, - `}}`, - ) - // Fix `v-model:` without type hints - replaceSourceRange( - codes, - source, - end, - end + 1, - ast.text.slice(end, end + 1), - ) + emits.push(`'onUpdate:${attributeName}': () => {}, `) + } else { + replaceSourceRange( + codes, + source, + start, + attribute.name.end, + modelValue.slice(0, 3), + [modelValue.slice(3), source, start, allCodeFeatures], + ) + replaceSourceRange( + codes, + source, + attribute.end, + attribute.end, + ` {...{'onUpdate:${modelValue}': () => {} }}`, + ) + } } - getModelsType(codes) + if (!firstNamespacedNode) return + const { attribute, attributeName, node } = firstNamespacedNode + const end = attributeName ? attribute.end : getStart(attribute, options) + 8 + replaceSourceRange( + codes, + source, + getStart(attribute, options), + end, + `{...{`, + ...result, + `} satisfies __VLS_GetModels<__VLS_NormalizeProps>}`, + ` {...{`, + ...emits, + `}}`, + ) + // Fix `v-model:` without type hints + replaceSourceRange(codes, source, end, end + 1, ast.text.slice(end, end + 1)) } function getModelsType(codes: Code[]) { From da6062e466ff5300edf00c3d6fc287ed30dec43f Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 8 Nov 2024 11:04:30 +0800 Subject: [PATCH 071/156] feat: use ts-macro --- packages/jsx-macros/src/core/index.ts | 17 ++-- packages/jsx-macros/src/index.ts | 14 +++- packages/volar/src/jsx-macros.ts | 52 ++++++------ packages/volar/src/jsx-macros/define-style.ts | 52 +++++++++++- packages/volar/src/jsx-macros/index.ts | 80 ++++++++++++------- packages/volar/src/jsx-macros/transform.ts | 8 +- 6 files changed, 150 insertions(+), 73 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 8e873a815..51e536ab1 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -50,7 +50,7 @@ export function transformJsxMacros( options: OptionsResolved, ): CodeTransform | undefined { const s = new MagicStringAST(code) - const rootMap = getRootMap(s, id) + const rootMap = getRootMap(s, id, options) for (const [root, map] of rootMap) { map.defineStyle?.forEach((defineStyle, index) => { @@ -102,7 +102,7 @@ export function transformJsxMacros( return generateTransform(s, id) } -function getRootMap(s: MagicStringAST, id: string) { +function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { const parents: (Node | undefined | null)[] = [] const rootMap = new Map() walkAST(babelParse(s.original, getLang(id)), { @@ -132,23 +132,22 @@ function getRootMap(s: MagicStringAST, id: string) { if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = s.sliceNode(macroExpression.callee) if (macroName) { - if (macroName === 'defineModel') { + if (options.macros.defineModel?.includes(macroName)) { ;(rootMap.get(root)!.defineModel ??= []).push({ expression: macroExpression, isRequired: expression?.type === 'TSNonNullExpression', }) - } else if (macroName.startsWith('defineStyle')) { + } else if (options.macros.defineStyle?.includes(macroName)) { const [, lang = 'css'] = macroName.split('.') ;(rootMap.get(root)!.defineStyle ??= []).push({ expression: macroExpression, isDeclaration: node.type === 'VariableDeclaration', lang, }) - } else if ( - macroName === 'defineSlots' || - macroName === 'defineExpose' - ) { - rootMap.get(root)![macroName] = macroExpression + } else if (options.macros.defineSlots?.includes(macroName)) { + rootMap.get(root)!.defineSlots = macroExpression + } else if (options.macros.defineExpose?.includes(macroName)) { + rootMap.get(root)!.defineExpose = macroExpression } } }, diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 6159f7a17..f40691ee3 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -28,10 +28,16 @@ import { transformStyle } from './core/style' export type Options = BaseOptions & { lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + macros?: { + defineModel?: string[] + defineExpose?: string[] + defineSlots?: string[] + defineStyle?: string[] + } } export type OptionsResolved = MarkRequired< Options, - 'include' | 'version' | 'lib' + 'include' | 'version' | 'lib' | 'macros' > function resolveOptions( @@ -47,6 +53,12 @@ function resolveOptions( ...options, version, lib, + macros: { + defineModel: options.macros?.defineModel ?? ['defineModel'], + defineSlots: options.macros?.defineSlots ?? ['defineSlots'], + defineExpose: options.macros?.defineExpose ?? ['defineExpose'], + defineStyle: options.macros?.defineStyle ?? ['defineStyle'], + }, } } diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 2d6d77304..3d76c452f 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -1,39 +1,43 @@ import { createFilter } from '@vue-macros/common' +import { createPlugin, type PluginReturn } from 'ts-macro' import { getRootMap, globalTypes, transformJsxMacros } from './jsx-macros/index' -import type { VueMacrosPlugin } from './common' +import type { OptionsResolved } from '@vue-macros/config' -const plugin: VueMacrosPlugin<'jsxMacros'> = (ctx, options = {}) => { - if (!options) return [] +const plugin: PluginReturn = + createPlugin(({ ts }, userOptions = {}) => { + if (!userOptions) return [] - const filter = createFilter(options) - const { version: vueVersion } = options + const filter = createFilter(userOptions) + const lib = userOptions.lib ?? 'vue' + const macros = { + defineModel: userOptions.macros?.defineModel ?? ['defineModel'], + defineExpose: userOptions.macros?.defineExpose ?? ['defineExpose'], + defineSlots: userOptions.macros?.defineSlots ?? ['defineSlots'], + defineStyle: userOptions.macros?.defineStyle ?? ['defineStyle'], + } - return { - name: 'vue-macros-jsx-macros', - version: 2.1, - resolveEmbeddedCode(fileName, sfc, embeddedFile) { - if (!filter(fileName) || embeddedFile.lang !== 'tsx') return + return { + name: 'vue-macros-jsx-macros', + resolveVirtualCode(virtualCode) { + const { fileName, languageId, codes } = virtualCode + if (!filter(fileName) || !['jsx', 'tsx'].includes(languageId)) return - for (const source of ['script', 'scriptSetup'] as const) { - if (!sfc[source]) continue const options = { - sfc, - source, - ts: ctx.modules.typescript, - codes: embeddedFile.content, - vueVersion, + ...virtualCode, + ts, + lib, + macros, } - const rootMap = getRootMap(options, ctx.vueCompilerOptions) + const rootMap = getRootMap(options) if (rootMap.size) transformJsxMacros(rootMap, options) if ( (fileName.endsWith('.tsx') || rootMap.size) && - !embeddedFile.content.toString().includes(globalTypes) + !codes.toString().includes(globalTypes) ) { - embeddedFile.content.push(globalTypes) + codes.push(globalTypes) } - } - }, - } -} + }, + } + }) export default plugin diff --git a/packages/volar/src/jsx-macros/define-style.ts b/packages/volar/src/jsx-macros/define-style.ts index 934575d6b..0569fecec 100644 --- a/packages/volar/src/jsx-macros/define-style.ts +++ b/packages/volar/src/jsx-macros/define-style.ts @@ -2,15 +2,17 @@ import { generateCssClassProperty } from '@vue/language-core/lib/codegen/script/ import { parseCssClassNames } from '@vue/language-core/lib/utils/parseCssClassNames' import { replaceSourceRange } from 'muggle-string' import { getStart, getText } from '../common' -import type { TransformOptions } from '../jsx-directive/index' +import type { JsxMacros, TransformOptions } from '.' export function transformDefineStyle( - defineStyle: import('typescript').CallExpression[] | undefined, + defineStyles: JsxMacros['defineStyle'], options: TransformOptions, ): void { + if (!defineStyles?.length) return const { ts, source, codes } = options - defineStyle?.forEach((expression, index) => { + defineStyles.forEach(({ expression, isCssModules }, index) => { if ( + isCssModules && expression?.arguments[0] && !expression.typeArguments && ts.isTemplateExpression(expression.arguments[0]) @@ -29,6 +31,8 @@ export function transformDefineStyle( '>', ) } + + addEmbeddedCode(expression, index, options) }) } @@ -43,3 +47,45 @@ function* getCssClassesType(css: string, offset: number, index: number) { ) } } + +function addEmbeddedCode( + expression: import('typescript').CallExpression, + index: number, + options: TransformOptions, +) { + const { ts } = options + const languageId = + ts.isPropertyAccessExpression(expression.expression) && + ts.isIdentifier(expression.expression.name) + ? expression.expression.name.text + : 'css' + const style = expression.arguments[0] + const styleText = getText(style, options) + .slice(1, -1) + .replaceAll(/\$\{.*\}/g, (str) => '_'.repeat(str.length)) + options.embeddedCodes.push({ + id: `style_${index}`, + languageId, + snapshot: { + getText: (start, end) => styleText.slice(start, end), + getLength: () => styleText.length, + getChangeRange: () => undefined, + }, + mappings: [ + { + sourceOffsets: [getStart(style, options)! + 1], + generatedOffsets: [0], + lengths: [styleText.length], + data: { + completion: true, + format: true, + navigation: true, + semantic: true, + structure: true, + verification: true, + }, + }, + ], + embeddedCodes: [], + }) +} diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 3259706be..e6a2ab830 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -1,30 +1,51 @@ -import { HELPER_PREFIX } from '@vue-macros/common' +import { + HELPER_PREFIX, + type MarkRequired, + type Overwrite, +} from '@vue-macros/common' import { toValidAssetId } from '@vue/compiler-dom' import { replaceSourceRange } from 'muggle-string' import { getStart, getText } from '../common' -import type { TransformOptions } from '../jsx-directive/index' -import type { VueCompilerOptions } from '@vue/language-core' +import type { OptionsResolved } from '@vue-macros/config' +import type { TsmVirtualCode } from 'ts-macro' export { transformJsxMacros } from './transform' export { globalTypes } from './global-types' +type UserOptions = MarkRequired< + Exclude, + 'lib' | 'macros' +> +export type TransformOptions = Overwrite< + TsmVirtualCode, + { + ts: typeof import('typescript') + lib: UserOptions['lib'] + macros: UserOptions['macros'] + } +> + +export type JsxMacros = { + defineModel?: string[] + defineSlots?: string + defineExpose?: string + defineStyle?: { + expression: import('typescript').CallExpression + isCssModules: boolean + }[] + defineComponent?: true +} export type RootMap = Map< | import('typescript').ArrowFunction | import('typescript').FunctionExpression | import('typescript').FunctionDeclaration, - { - defineModel?: string[] - defineSlots?: string - defineExpose?: string - defineStyle?: import('typescript').CallExpression[] - defineComponent?: true - } + JsxMacros > function getMacro( node: import('typescript').Node | undefined, ts: typeof import('typescript'), - vueCompilerOptions: VueCompilerOptions, + options: TransformOptions, ): | { expression: import('typescript').CallExpression @@ -79,21 +100,18 @@ function getMacro( return ( ts.isIdentifier(expression.expression) && [ - ...vueCompilerOptions.macros.defineModel, - ...vueCompilerOptions.macros.defineExpose, - ...vueCompilerOptions.macros.defineSlots, - 'defineStyle', + ...(options.macros.defineModel ?? []), + ...(options.macros.defineExpose ?? []), + ...(options.macros.defineSlots ?? []), + ...(options.macros.defineStyle ?? []), ].includes(expression.expression.escapedText!) && node ) } } -export function getRootMap( - options: TransformOptions, - vueCompilerOptions: VueCompilerOptions, -): RootMap { - const { ts, sfc, source, codes } = options +export function getRootMap(options: TransformOptions): RootMap { + const { ts, ast, source, codes } = options const rootMap: RootMap = new Map() function walk( @@ -134,14 +152,14 @@ export function getRootMap( } } - const macro = getMacro(node, ts, vueCompilerOptions) + const macro = getMacro(node, ts, options) if (!macro) return const { expression, initializer } = macro let isRequired = macro.isRequired if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = getText(expression.expression, options) - if (vueCompilerOptions.macros.defineModel.includes(macroName)) { + if (options.macros.defineModel?.includes(macroName)) { const modelName = expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) @@ -184,7 +202,7 @@ export function getRootMap( } const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) - const typeString = `import("vue").UnwrapRef` + const typeString = `import('vue').UnwrapRef` ;(rootMap.get(root)!.defineModel ??= [])!.push( `'${modelName}'${isRequired ? ':' : '?:'} ${typeString}`, `'onUpdate:${modelName}'?: ($event: ${typeString}) => any`, @@ -196,7 +214,7 @@ export function getRootMap( getStart(initializer, options), `// @ts-ignore\n${id};\nlet ${id} =`, ) - } else if (vueCompilerOptions.macros.defineSlots.includes(macroName)) { + } else if (options.macros.defineSlots?.includes(macroName)) { replaceSourceRange( codes, source, @@ -206,7 +224,7 @@ export function getRootMap( ) rootMap.get(root)!.defineSlots = `{ vSlots?: typeof ${HELPER_PREFIX}slots }` - } else if (vueCompilerOptions.macros.defineExpose.includes(macroName)) { + } else if (options.macros.defineExpose?.includes(macroName)) { replaceSourceRange( codes, source, @@ -216,14 +234,14 @@ export function getRootMap( ) rootMap.get(root)!.defineExpose = `(exposed: typeof ${HELPER_PREFIX}expose) => {}` - } else if ( - macroName.startsWith('defineStyle') && - ts.isVariableStatement(node) - ) { - ;(rootMap.get(root)!.defineStyle ??= [])!.push(expression) + } else if (macroName.startsWith('defineStyle')) { + ;(rootMap.get(root)!.defineStyle ??= [])!.push({ + expression, + isCssModules: !!ts.isVariableStatement(node), + }) } } - ts.forEachChild(sfc[source]!.ast, (node) => walk(node, [])) + ts.forEachChild(ast, (node) => walk(node, [])) return rootMap } diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts index 86534736e..bc7b83511 100644 --- a/packages/volar/src/jsx-macros/transform.ts +++ b/packages/volar/src/jsx-macros/transform.ts @@ -1,9 +1,8 @@ import { HELPER_PREFIX } from '@vue-macros/common' import { replaceSourceRange } from 'muggle-string' import { getStart, getText } from '../common' -import type { TransformOptions } from '../jsx-directive/index' import { transformDefineStyle } from './define-style' -import type { RootMap } from '.' +import type { RootMap, TransformOptions } from '.' export function transformJsxMacros( rootMap: RootMap, @@ -89,9 +88,8 @@ export function transformJsxMacros( getStart(node, options), getStart(node.expression, options), `return {\nprops: {} as `, - options.vueVersion ? `import('vue').PublicProps & ` : '', - `{${defaultProps.join(', ')}} & `, - map.defineModel?.length ? `{ ${map.defineModel?.join(', ')} }` : '{}', + `{ ${defaultProps.join(', ')} } & `, + `{ ${map.defineModel?.join(', ') ?? ''} }`, map.defineSlots ? ` & ${map.defineSlots}` : '', map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', `,\nrender: `, From dc0f9327cf1af67c893eae1ad1dc9c93ed0fb63f Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 8 Nov 2024 11:41:32 +0800 Subject: [PATCH 072/156] fix: test --- packages/jsx-macros/src/core/index.ts | 12 ++++++++++-- packages/jsx-macros/tests/fixtures.test.ts | 12 ++++++++++++ packages/volar/src/jsx-macros/define-style.ts | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 51e536ab1..889bc643a 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -130,7 +130,11 @@ function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { const macroExpression = getMacroExpression(expression) if (!macroExpression) return if (!rootMap.has(root)) rootMap.set(root, {}) - const macroName = s.sliceNode(macroExpression.callee) + const macroName = s.sliceNode( + macroExpression.callee.type === 'MemberExpression' + ? macroExpression.callee.object + : macroExpression.callee, + ) if (macroName) { if (options.macros.defineModel?.includes(macroName)) { ;(rootMap.get(root)!.defineModel ??= []).push({ @@ -138,7 +142,11 @@ function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { isRequired: expression?.type === 'TSNonNullExpression', }) } else if (options.macros.defineStyle?.includes(macroName)) { - const [, lang = 'css'] = macroName.split('.') + const lang = + macroExpression.callee.type === 'MemberExpression' && + macroExpression.callee.property.type === 'Identifier' + ? macroExpression.callee.property.name + : 'css' ;(rootMap.get(root)!.defineStyle ??= []).push({ expression: macroExpression, isDeclaration: node.type === 'VariableDeclaration', diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index e54c6da78..d63d209bd 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -13,6 +13,12 @@ describe('fixtures', async () => { lib: 'vue', include: ['*.tsx'], version: 3.5, + macros: { + defineModel: ['defineModel'], + defineSlots: ['defineSlots'], + defineExpose: ['defineExpose'], + defineStyle: ['defineStyle'], + }, })?.code, ) }) @@ -28,6 +34,12 @@ describe('react fixtures', async () => { lib: 'react', include: ['*.tsx'], version: 18, + macros: { + defineModel: ['defineModel'], + defineSlots: ['defineSlots'], + defineExpose: ['defineExpose'], + defineStyle: ['defineStyle'], + }, })?.code, ) }) diff --git a/packages/volar/src/jsx-macros/define-style.ts b/packages/volar/src/jsx-macros/define-style.ts index 0569fecec..9cf68107a 100644 --- a/packages/volar/src/jsx-macros/define-style.ts +++ b/packages/volar/src/jsx-macros/define-style.ts @@ -15,7 +15,7 @@ export function transformDefineStyle( isCssModules && expression?.arguments[0] && !expression.typeArguments && - ts.isTemplateExpression(expression.arguments[0]) + ts.isTemplateLiteral(expression.arguments[0]) ) { replaceSourceRange( codes, From 004d62f6cfceb7561acbe868f659d343f2dfac76 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 10 Nov 2024 18:21:50 +0800 Subject: [PATCH 073/156] feat: partial vSlots --- packages/volar/src/jsx-macros/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index e6a2ab830..a037c72a0 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -223,7 +223,7 @@ export function getRootMap(options: TransformOptions): RootMap { `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, ) rootMap.get(root)!.defineSlots = - `{ vSlots?: typeof ${HELPER_PREFIX}slots }` + `{ vSlots?: Partial }` } else if (options.macros.defineExpose?.includes(macroName)) { replaceSourceRange( codes, From 8ed8b91c4b91d0a6281ecf64d13b24c725ac2ae9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 13 Nov 2024 00:56:35 +0800 Subject: [PATCH 074/156] chore: update ts-macro --- packages/volar/package.json | 2 +- packages/volar/src/jsx-directive.ts | 4 +- packages/volar/src/jsx-ref.ts | 4 +- pnpm-lock.yaml | 241 +--------------------------- 4 files changed, 12 insertions(+), 239 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index b09b9ae7a..7f1c92065 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -281,7 +281,7 @@ "@vue-macros/short-vmodel": "workspace:*", "@vue/language-core": "catalog:", "muggle-string": "^0.4.1", - "ts-macro": "^0.0.4" + "ts-macro": "^0.1.3" }, "devDependencies": { "@vue/compiler-dom": "catalog:", diff --git a/packages/volar/src/jsx-directive.ts b/packages/volar/src/jsx-directive.ts index 58b8849b0..3b938428f 100644 --- a/packages/volar/src/jsx-directive.ts +++ b/packages/volar/src/jsx-directive.ts @@ -10,8 +10,8 @@ const plugin: PluginReturn = return { name: 'vue-macros-jsx-directive', - resolveVirtualCode({ ast, codes, fileName, source, languageId }) { - if (!filter(fileName) || !['jsx', 'tsx'].includes(languageId)) return + resolveVirtualCode({ filePath, ast, codes, source, languageId }) { + if (!filter(filePath) || !['jsx', 'tsx'].includes(languageId)) return transformJsxDirective({ codes, ast, diff --git a/packages/volar/src/jsx-ref.ts b/packages/volar/src/jsx-ref.ts index 57cfc7767..dfead2afc 100644 --- a/packages/volar/src/jsx-ref.ts +++ b/packages/volar/src/jsx-ref.ts @@ -83,8 +83,8 @@ const plugin: PluginReturn = return { name: 'vue-macros-jsx-ref', - resolveVirtualCode({ ast, codes, fileName, source, languageId }) { - if (!filter(fileName) || !['jsx', 'tsx'].includes(languageId)) return + resolveVirtualCode({ filePath, ast, codes, source, languageId }) { + if (!filter(filePath) || !['jsx', 'tsx'].includes(languageId)) return const nodes = getRefNodes(ts, ast, alias) if (nodes.length) { transformRef({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 575745b6f..572df8b39 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -956,8 +956,8 @@ importers: specifier: ^0.4.1 version: 0.4.1 ts-macro: - specifier: ^0.0.4 - version: 0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3) + specifier: ^0.1.3 + version: 0.1.3(rollup@4.24.4)(typescript@5.6.3) devDependencies: '@vue/compiler-dom': specifier: 'catalog:' @@ -1684,27 +1684,6 @@ packages: search-insights: optional: true - '@emmetio/abbreviation@2.3.3': - resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} - - '@emmetio/css-abbreviation@2.1.8': - resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} - - '@emmetio/css-parser@0.4.0': - resolution: {integrity: sha512-z7wkxRSZgrQHXVzObGkXG+Vmj3uRlpM11oCZ9pbaz0nFejvCDmAiNDpY75+wgXOcffKpj4rzGtwGaZxfJKsJxw==} - - '@emmetio/html-matcher@1.3.0': - resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} - - '@emmetio/scanner@1.0.4': - resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} - - '@emmetio/stream-reader-utils@0.1.0': - resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} - - '@emmetio/stream-reader@2.2.0': - resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} - '@emnapi/core@1.3.1': resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} @@ -2675,10 +2654,6 @@ packages: peerDependencies: vue: ^2.7.0 || ^3.0.0 - '@ts-macro/language-server@0.0.4': - resolution: {integrity: sha512-Y7aJFE/p/XyWViPxU0zIsiwLhExkOr6zEujimLeqPqY+b32vEttOQkEfiNYxCY6cUC8U5/wQmq/wePgrWO5/Vw==} - hasBin: true - '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -2972,24 +2947,12 @@ packages: '@volar/language-core@2.4.8': resolution: {integrity: sha512-K/GxMOXGq997bO00cdFhTNuR85xPxj0BEEAy+BaqqayTmy9Tmhfgmq2wpJcVspRhcwfgPoE2/mEJa26emUhG/g==} - '@volar/language-server@2.4.8': - resolution: {integrity: sha512-3Jd9Y+0Zhwi/zfdRxqoNrm7AxP6lgTsw4Ni9r6eCyWYGVsTnpVwGmlcbiZyDja6anoKZxnaeDatX1jkaHHWaRQ==} - - '@volar/language-service@2.4.8': - resolution: {integrity: sha512-9y8X4cdUxXmy4s5HoB8jmOpDIZG7XVFu4iEFvouhZlJX2leCq0pbq5h7dhA+O8My0fne3vtE6cJ4t9nc+8UBZw==} - '@volar/source-map@2.4.8': resolution: {integrity: sha512-jeWJBkC/WivdelMwxKkpFL811uH/jJ1kVxa+c7OvG48DXc3VrP7pplSWPP2W1dLMqBxD+awRlg55FQQfiup4cA==} '@volar/typescript@2.4.8': resolution: {integrity: sha512-6xkIYJ5xxghVBhVywMoPMidDDAFT1OoQeXwa27HSgJ6AiIKRe61RXLoik+14Z7r0JvnblXVsjsRLmCr42SGzqg==} - '@vscode/emmet-helper@2.9.3': - resolution: {integrity: sha512-rB39LHWWPQYYlYfpv9qCoZOVioPCftKXXqrsyqN1mTWZM6dTnONT63Db+03vgrBbHzJN45IrgS/AGxw9iiqfEw==} - - '@vscode/l10n@0.0.18': - resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} - '@vue/babel-helper-vue-jsx-merge-props@1.4.0': resolution: {integrity: sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==} @@ -3785,9 +3748,6 @@ packages: electron-to-chromium@1.5.47: resolution: {integrity: sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==} - emmet@2.4.11: - resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} - emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -4671,9 +4631,6 @@ packages: resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - jsonc-parser@2.3.1: - resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} - jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -5528,9 +5485,6 @@ packages: resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} engines: {node: '>=0.10'} - request-light@0.7.0: - resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -5962,8 +5916,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-macro@0.0.4: - resolution: {integrity: sha512-1A26REuo5iybl8ChEEcmahLo0rrzx5iXWz4hMGxaGYn0gimYRW2Wjz0wqJVAwjBoencg56WhOR/uRcdE752/+A==} + ts-macro@0.1.3: + resolution: {integrity: sha512-25mBVn21XasXPQRvEW4f3wtG+Dkjb//1eGjZnAdIe1E7ARdzOoQGayaWOwy/GarKH8dtpCPZKpJqapMuKt9LTA==} tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} @@ -6035,9 +5989,6 @@ packages: resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} engines: {node: '>=16'} - typescript-auto-import-cache@0.3.5: - resolution: {integrity: sha512-fAIveQKsoYj55CozUiBoj4b/7WpN0i4o74wiGY5JVUEoD0XiqDk1tJqTEjgzL2/AizKQrXxyRosSebyDzBZKjw==} - typescript-eslint@8.11.0: resolution: {integrity: sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6365,56 +6316,9 @@ packages: jsdom: optional: true - volar-service-css@0.0.62: - resolution: {integrity: sha512-JwNyKsH3F8PuzZYuqPf+2e+4CTU8YoyUHEHVnoXNlrLe7wy9U3biomZ56llN69Ris7TTy/+DEX41yVxQpM4qvg==} - peerDependencies: - '@volar/language-service': ~2.4.0 - peerDependenciesMeta: - '@volar/language-service': - optional: true - - volar-service-emmet@0.0.62: - resolution: {integrity: sha512-U4dxWDBWz7Pi4plpbXf4J4Z/ss6kBO3TYrACxWNsE29abu75QzVS0paxDDhI6bhqpbDFXlpsDhZ9aXVFpnfGRQ==} - peerDependencies: - '@volar/language-service': ~2.4.0 - peerDependenciesMeta: - '@volar/language-service': - optional: true - - volar-service-typescript@0.0.62: - resolution: {integrity: sha512-p7MPi71q7KOsH0eAbZwPBiKPp9B2+qrdHAd6VY5oTo9BUXatsOAdakTm9Yf0DUj6uWBAaOT01BSeVOPwucMV1g==} - peerDependencies: - '@volar/language-service': ~2.4.0 - peerDependenciesMeta: - '@volar/language-service': - optional: true - - vscode-css-languageservice@6.3.1: - resolution: {integrity: sha512-1BzTBuJfwMc3A0uX4JBdJgoxp74cjj4q2mDJdp49yD/GuAq4X0k5WtK6fNcMYr+FfJ9nqgR6lpfCSZDkARJ5qQ==} - - vscode-jsonrpc@8.2.0: - resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} - engines: {node: '>=14.0.0'} - - vscode-languageserver-protocol@3.17.5: - resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} - vscode-languageserver-textdocument@1.0.12: resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} - vscode-languageserver-types@3.17.5: - resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} - - vscode-languageserver@9.0.1: - resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} - hasBin: true - - vscode-nls@5.2.0: - resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} - - vscode-uri@2.1.2: - resolution: {integrity: sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==} - vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} @@ -7393,29 +7297,6 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' - '@emmetio/abbreviation@2.3.3': - dependencies: - '@emmetio/scanner': 1.0.4 - - '@emmetio/css-abbreviation@2.1.8': - dependencies: - '@emmetio/scanner': 1.0.4 - - '@emmetio/css-parser@0.4.0': - dependencies: - '@emmetio/stream-reader': 2.2.0 - '@emmetio/stream-reader-utils': 0.1.0 - - '@emmetio/html-matcher@1.3.0': - dependencies: - '@emmetio/scanner': 1.0.4 - - '@emmetio/scanner@1.0.4': {} - - '@emmetio/stream-reader-utils@0.1.0': {} - - '@emmetio/stream-reader@2.2.0': {} - '@emnapi/core@1.3.1': dependencies: '@emnapi/wasi-threads': 1.0.1 @@ -8547,17 +8428,6 @@ snapshots: '@tanstack/virtual-core': 3.10.8 vue: 3.5.12(typescript@5.6.3) - '@ts-macro/language-server@0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3)': - dependencies: - '@volar/language-server': 2.4.8 - ts-macro: 0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3) - volar-service-css: 0.0.62(@volar/language-service@2.4.8) - volar-service-emmet: 0.0.62(@volar/language-service@2.4.8) - volar-service-typescript: 0.0.62(@volar/language-service@2.4.8) - transitivePeerDependencies: - - '@volar/language-service' - - typescript - '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.0 @@ -9005,25 +8875,6 @@ snapshots: dependencies: '@volar/source-map': 2.4.8 - '@volar/language-server@2.4.8': - dependencies: - '@volar/language-core': 2.4.8 - '@volar/language-service': 2.4.8 - '@volar/typescript': 2.4.8 - path-browserify: 1.0.1 - request-light: 0.7.0 - vscode-languageserver: 9.0.1 - vscode-languageserver-protocol: 3.17.5 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.0.8 - - '@volar/language-service@2.4.8': - dependencies: - '@volar/language-core': 2.4.8 - vscode-languageserver-protocol: 3.17.5 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.0.8 - '@volar/source-map@2.4.8': {} '@volar/typescript@2.4.8': @@ -9032,16 +8883,6 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.0.8 - '@vscode/emmet-helper@2.9.3': - dependencies: - emmet: 2.4.11 - jsonc-parser: 2.3.1 - vscode-languageserver-textdocument: 1.0.12 - vscode-languageserver-types: 3.17.5 - vscode-uri: 2.1.2 - - '@vscode/l10n@0.0.18': {} - '@vue/babel-helper-vue-jsx-merge-props@1.4.0': {} '@vue/babel-helper-vue-transform-on@1.2.5': {} @@ -10049,11 +9890,6 @@ snapshots: electron-to-chromium@1.5.47: {} - emmet@2.4.11: - dependencies: - '@emmetio/abbreviation': 2.3.3 - '@emmetio/css-abbreviation': 2.1.8 - emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -11049,8 +10885,6 @@ snapshots: espree: 9.6.1 semver: 7.6.3 - jsonc-parser@2.3.1: {} - jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -12125,8 +11959,6 @@ snapshots: repeat-string@1.6.1: {} - request-light@0.7.0: {} - resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -12602,17 +12434,14 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-macro@0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3): + ts-macro@0.1.3(rollup@4.24.4)(typescript@5.6.3): dependencies: - '@ts-macro/language-server': 0.0.4(@volar/language-service@2.4.8)(typescript@5.6.3) + '@rollup/pluginutils': 5.1.3(rollup@4.24.4) '@volar/language-core': 2.4.8 - '@volar/typescript': 2.4.8 '@vue/language-core': 2.1.10(typescript@5.6.3) - jiti: 2.3.3 muggle-string: 0.4.1 - vscode-uri: 3.0.8 transitivePeerDependencies: - - '@volar/language-service' + - rollup - typescript tsconfck@3.1.4(typescript@5.6.3): @@ -12686,10 +12515,6 @@ snapshots: type-fest@4.26.1: {} - typescript-auto-import-cache@0.3.5: - dependencies: - semver: 7.6.3 - typescript-eslint@8.11.0(eslint@9.14.0(jiti@2.3.3))(typescript@5.6.3): dependencies: '@typescript-eslint/eslint-plugin': 8.11.0(@typescript-eslint/parser@8.11.0(eslint@9.14.0(jiti@2.3.3))(typescript@5.6.3))(eslint@9.14.0(jiti@2.3.3))(typescript@5.6.3) @@ -13207,60 +13032,8 @@ snapshots: - supports-color - terser - volar-service-css@0.0.62(@volar/language-service@2.4.8): - dependencies: - vscode-css-languageservice: 6.3.1 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.0.8 - optionalDependencies: - '@volar/language-service': 2.4.8 - - volar-service-emmet@0.0.62(@volar/language-service@2.4.8): - dependencies: - '@emmetio/css-parser': 0.4.0 - '@emmetio/html-matcher': 1.3.0 - '@vscode/emmet-helper': 2.9.3 - vscode-uri: 3.0.8 - optionalDependencies: - '@volar/language-service': 2.4.8 - - volar-service-typescript@0.0.62(@volar/language-service@2.4.8): - dependencies: - path-browserify: 1.0.1 - semver: 7.6.3 - typescript-auto-import-cache: 0.3.5 - vscode-languageserver-textdocument: 1.0.12 - vscode-nls: 5.2.0 - vscode-uri: 3.0.8 - optionalDependencies: - '@volar/language-service': 2.4.8 - - vscode-css-languageservice@6.3.1: - dependencies: - '@vscode/l10n': 0.0.18 - vscode-languageserver-textdocument: 1.0.12 - vscode-languageserver-types: 3.17.5 - vscode-uri: 3.0.8 - - vscode-jsonrpc@8.2.0: {} - - vscode-languageserver-protocol@3.17.5: - dependencies: - vscode-jsonrpc: 8.2.0 - vscode-languageserver-types: 3.17.5 - vscode-languageserver-textdocument@1.0.12: {} - vscode-languageserver-types@3.17.5: {} - - vscode-languageserver@9.0.1: - dependencies: - vscode-languageserver-protocol: 3.17.5 - - vscode-nls@5.2.0: {} - - vscode-uri@2.1.2: {} - vscode-uri@3.0.8: {} vue-demi@0.14.10(vue@2.7.16): From 1f6b971cab3a6d02a25f96e088a39cabe620b841 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 13 Nov 2024 01:32:44 +0800 Subject: [PATCH 075/156] chore: update ts-macro to 0.1.4 --- packages/volar/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index 7f1c92065..04aae4005 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -281,7 +281,7 @@ "@vue-macros/short-vmodel": "workspace:*", "@vue/language-core": "catalog:", "muggle-string": "^0.4.1", - "ts-macro": "^0.1.3" + "ts-macro": "^0.1.4" }, "devDependencies": { "@vue/compiler-dom": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 572df8b39..9bb9fb9c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -956,8 +956,8 @@ importers: specifier: ^0.4.1 version: 0.4.1 ts-macro: - specifier: ^0.1.3 - version: 0.1.3(rollup@4.24.4)(typescript@5.6.3) + specifier: ^0.1.4 + version: 0.1.4(rollup@4.24.4)(typescript@5.6.3) devDependencies: '@vue/compiler-dom': specifier: 'catalog:' @@ -5916,8 +5916,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-macro@0.1.3: - resolution: {integrity: sha512-25mBVn21XasXPQRvEW4f3wtG+Dkjb//1eGjZnAdIe1E7ARdzOoQGayaWOwy/GarKH8dtpCPZKpJqapMuKt9LTA==} + ts-macro@0.1.4: + resolution: {integrity: sha512-UKSQw9C+HTpFBtiweU8BNgSFDS/YAsjDX1u6S3r80f97KTqT0HOHSZ8FI8suuFagPTGU37IEjA89h9FaRoV1hw==} tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} @@ -12434,7 +12434,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-macro@0.1.3(rollup@4.24.4)(typescript@5.6.3): + ts-macro@0.1.4(rollup@4.24.4)(typescript@5.6.3): dependencies: '@rollup/pluginutils': 5.1.3(rollup@4.24.4) '@volar/language-core': 2.4.8 From 8787ec1320ac3419aa999ebe4cb217fd6ee37145 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 14 Nov 2024 16:32:52 +0800 Subject: [PATCH 076/156] fix: use ShallowUnwrapRef for exposed --- packages/volar/src/jsx-macros/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index a037c72a0..1d068c5e2 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -233,7 +233,9 @@ export function getRootMap(options: TransformOptions): RootMap { `// @ts-ignore\n${HELPER_PREFIX}expose;\nconst ${HELPER_PREFIX}expose =`, ) rootMap.get(root)!.defineExpose = - `(exposed: typeof ${HELPER_PREFIX}expose) => {}` + options.lib === 'vue' + ? `(exposed: import('vue').ShallowUnwrapRef) => {}` + : `(exposed: typeof ${HELPER_PREFIX}expose) => {}` } else if (macroName.startsWith('defineStyle')) { ;(rootMap.get(root)!.defineStyle ??= [])!.push({ expression, From 1ed78bace5b92d0b5691e609c3d4ce40f9461b90 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 14 Nov 2024 16:56:52 +0800 Subject: [PATCH 077/156] fix: better type --- packages/volar/src/jsx-macros/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 1d068c5e2..ba3841086 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -204,7 +204,7 @@ export function getRootMap(options: TransformOptions): RootMap { const id = toValidAssetId(modelName, `${HELPER_PREFIX}model` as any) const typeString = `import('vue').UnwrapRef` ;(rootMap.get(root)!.defineModel ??= [])!.push( - `'${modelName}'${isRequired ? ':' : '?:'} ${typeString}`, + `${modelName.includes('-') ? `'${modelName}'` : modelName}${isRequired ? ':' : '?:'} ${typeString}`, `'onUpdate:${modelName}'?: ($event: ${typeString}) => any`, ) replaceSourceRange( From 54169acec39d6297c3a7e551fe55bfdaf5f23a50 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 15 Nov 2024 20:21:24 +0800 Subject: [PATCH 078/156] feat: convert `//` comments to `/* */` --- packages/jsx-macros/src/core/define-style.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/jsx-macros/src/core/define-style.ts b/packages/jsx-macros/src/core/define-style.ts index 44bfb1193..37f863664 100644 --- a/packages/jsx-macros/src/core/define-style.ts +++ b/packages/jsx-macros/src/core/define-style.ts @@ -75,7 +75,10 @@ export function transformDefineStyle( }) } - css = s.sliceNode(expression.arguments[0]).slice(1, -1) + css = s + .sliceNode(expression.arguments[0]) + .slice(1, -1) + .replaceAll(/\/\/(.*)(?=\n)/g, '/*$1*/') const module = isDeclaration ? 'module.' : '' const importId = `${helperPrefix}/define-style?index=${index}&scopeId=${scopeId}&scoped=${scoped}&lang.${module}${lang}` importMap.set(importId, css) From 794f16ce8d1de2d0722a5c9267f750084c27824d Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 20 Nov 2024 17:23:01 +0800 Subject: [PATCH 079/156] fix: docs build error --- packages/volar/src/jsx-macros/define-style.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/volar/src/jsx-macros/define-style.ts b/packages/volar/src/jsx-macros/define-style.ts index 9cf68107a..e0cfdeed0 100644 --- a/packages/volar/src/jsx-macros/define-style.ts +++ b/packages/volar/src/jsx-macros/define-style.ts @@ -1,5 +1,5 @@ -import { generateCssClassProperty } from '@vue/language-core/lib/codegen/script/template' -import { parseCssClassNames } from '@vue/language-core/lib/utils/parseCssClassNames' +import { generateCssClassProperty } from '@vue/language-core/lib/codegen/script/template.js' +import { parseCssClassNames } from '@vue/language-core/lib/utils/parseCssClassNames.js' import { replaceSourceRange } from 'muggle-string' import { getStart, getText } from '../common' import type { JsxMacros, TransformOptions } from '.' From 4537c412230de79fae30c9da591f05b9dbc61dc2 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 20 Nov 2024 18:45:53 +0800 Subject: [PATCH 080/156] fix: typecheck --- packages/volar/src/jsx-directive/context.ts | 2 +- packages/volar/src/jsx-directive/ref.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 36e8bcf2e..faef806b1 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -43,7 +43,7 @@ function __VLS_getFunctionalComponentCtx( ? { expose: (exposed: (typeof __VLS_nativeElements)[S]) => any } : '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } - ? Ctx['props']['vSlots'] } & Ctx + ? { slots: Ctx['props']['vSlots'] } & Ctx : never : T extends (props: infer P, ctx: infer Ctx) => any ? { props: P; slots: P['vSlots']; } & Ctx diff --git a/packages/volar/src/jsx-directive/ref.ts b/packages/volar/src/jsx-directive/ref.ts index 4cb124421..b871899a5 100644 --- a/packages/volar/src/jsx-directive/ref.ts +++ b/packages/volar/src/jsx-directive/ref.ts @@ -32,7 +32,7 @@ export function transformRef( getStart(attribute.initializer.expression, options), allCodeFeatures, ], - `} satisfies { ref: (e: Parameters[0]) => any }) as {}}`, + `} satisfies { ref: (e: Parameters[0]) => any }) as {}}`, ) } } From 5f8ed02d71e90ffb674b41b5d81031d125ee83d9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 12:41:37 +0800 Subject: [PATCH 081/156] types: use {} instead of any --- packages/volar/src/jsx-directive/context.ts | 4 ++-- packages/volar/src/jsx-macros/global-types.ts | 7 ++++--- packages/volar/src/jsx-macros/index.ts | 8 ++------ packages/volar/src/jsx-macros/transform.ts | 11 +++++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index faef806b1..1f11e4f95 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -21,7 +21,7 @@ export function resolveCtxMap( type __VLS_IsAny = 0 extends 1 & T ? true : false; type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; type __VLS_Element = globalThis.JSX.Element; -function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): +declare function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): T extends new (...args: any) => any ? (props: (K extends { $props: infer Props } ? Props : any) & Record, ctx?: any) => __VLS_Element & { __ctx?: { attrs?: any, @@ -35,7 +35,7 @@ const __VLS_nativeElements = { ...{} as SVGElementTagNameMap, ...{} as HTMLElementTagNameMap, }; -function __VLS_getFunctionalComponentCtx( +declare function __VLS_getFunctionalComponentCtx( comp: T, compInstance: K, s: S, diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index e6591778f..6a7cae57c 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -2,9 +2,10 @@ import { HELPER_PREFIX } from '@vue-macros/common' export const globalTypes: string = ` const { defineModel } = await import('vue') -declare function defineSlots>(slots?: Partial): T; +declare function defineSlots>(): Partial; +declare function defineSlots>(slots: T): T; declare function defineExpose = Record>(exposed?: Exposed): Exposed; -type __VLS_StyleArgs = [style: string, options?: { scoped?: boolean }] -declare const defineStyle: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T } +type __VLS_StyleArgs = [style: string, options?: { scoped?: boolean }]; +declare const defineStyle: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T }; declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; ` diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index ba3841086..4c5b42f78 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -222,8 +222,7 @@ export function getRootMap(options: TransformOptions): RootMap { getStart(expression, options), `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, ) - rootMap.get(root)!.defineSlots = - `{ vSlots?: Partial }` + rootMap.get(root)!.defineSlots = `Partial` } else if (options.macros.defineExpose?.includes(macroName)) { replaceSourceRange( codes, @@ -232,10 +231,7 @@ export function getRootMap(options: TransformOptions): RootMap { getStart(expression, options), `// @ts-ignore\n${HELPER_PREFIX}expose;\nconst ${HELPER_PREFIX}expose =`, ) - rootMap.get(root)!.defineExpose = - options.lib === 'vue' - ? `(exposed: import('vue').ShallowUnwrapRef) => {}` - : `(exposed: typeof ${HELPER_PREFIX}expose) => {}` + rootMap.get(root)!.defineExpose = `typeof ${HELPER_PREFIX}expose` } else if (macroName.startsWith('defineStyle')) { ;(rootMap.get(root)!.defineStyle ??= [])!.push({ expression, diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts index bc7b83511..be49f20bf 100644 --- a/packages/volar/src/jsx-macros/transform.ts +++ b/packages/volar/src/jsx-macros/transform.ts @@ -88,10 +88,13 @@ export function transformJsxMacros( getStart(node, options), getStart(node.expression, options), `return {\nprops: {} as `, - `{ ${defaultProps.join(', ')} } & `, - `{ ${map.defineModel?.join(', ') ?? ''} }`, - map.defineSlots ? ` & ${map.defineSlots}` : '', - map.defineExpose ? `,\nexpose: ${map.defineExpose}` : '', + defaultProps.length ? `{ ${defaultProps.join(', ')} } & ` : '', + `{ vSlots?: ${map.defineSlots ?? '{}'}, ${map.defineModel?.join(', ') ?? ''} }`, + `,\nexpose: (exposed: ${ + options.lib === 'vue' + ? `import('vue').ShallowUnwrapRef` + : 'NonNullable' + }<${map.defineExpose ?? '{}'}>) => {}`, `,\nrender: `, shouldWrapByCall ? '(' : '', ) From 1bec4fc5e10774af839af4460342d6bd381aad47 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 14:31:42 +0800 Subject: [PATCH 082/156] fix: typecheck --- packages/jsx-macros/tests/fixtures/define-slots.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/tests/fixtures/define-slots.tsx b/packages/jsx-macros/tests/fixtures/define-slots.tsx index d9ed24ff4..0d3fcb541 100644 --- a/packages/jsx-macros/tests/fixtures/define-slots.tsx +++ b/packages/jsx-macros/tests/fixtures/define-slots.tsx @@ -2,12 +2,12 @@ export const Comp = () => { const slots = defineSlots<{ default: () => any }>() - return
{slots.default()}
+ return
{slots.default?.()}
} export default function () { const slots = defineSlots({ default: () =>
default
, }) - return
{slots.default()}
+ return
{slots.default?.()}
} From a4959751c09dd62ad935ce79cacb7d2965812a64 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 18:23:00 +0800 Subject: [PATCH 083/156] feat: support alias --- packages/common/src/ast.ts | 7 +- .../src/core/define-component/index.ts | 11 ++- packages/jsx-macros/src/core/define-model.ts | 11 ++- packages/jsx-macros/src/core/index.ts | 27 +++--- packages/jsx-macros/src/index.ts | 43 ++++++---- packages/volar/src/index.ts | 2 + packages/volar/src/jsx-macros.ts | 86 +++++++++++-------- packages/volar/src/jsx-macros/global-types.ts | 17 ++-- packages/volar/src/jsx-macros/index.ts | 34 +++++--- 9 files changed, 152 insertions(+), 86 deletions(-) diff --git a/packages/common/src/ast.ts b/packages/common/src/ast.ts index 5ada83265..7dfabb4ad 100644 --- a/packages/common/src/ast.ts +++ b/packages/common/src/ast.ts @@ -155,6 +155,7 @@ export function importHelperFn( local: string, from = 'vue', isDefault = false, + as: string = local, ) { const imported = isDefault ? 'default' : local const cacheKey = `${from}@${imported}` @@ -163,8 +164,8 @@ export function importHelperFn( offset, `\nimport ${ isDefault - ? HELPER_PREFIX + local - : `{ ${imported} as ${HELPER_PREFIX + local} }` + ? HELPER_PREFIX + as + : `{ ${imported} as ${HELPER_PREFIX + as} }` } from ${JSON.stringify(from)};`, ) if (!importedMap.has(s)) { @@ -174,5 +175,5 @@ export function importHelperFn( } } - return `${HELPER_PREFIX}${local}` + return `${HELPER_PREFIX}${as}` } diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 68c50bdc5..b405cc7ec 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,6 +1,7 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' import type { FunctionalNode, RootMapValue } from '..' +import type { OptionsResolved } from '../..' import { transformAwait } from './await' import { restructure } from './restructure' import type { ObjectExpression } from '@babel/types' @@ -10,11 +11,19 @@ export function transformDefineComponent( propsName: string, map: RootMapValue, s: MagicStringAST, + options: OptionsResolved, ): void { if (!map.defineComponent) return s.overwriteNode( map.defineComponent.callee, - importHelperFn(s, 0, 'defineComponent', 'vue'), + importHelperFn( + s, + 0, + `defineComponent`, + 'vue', + false, + options.defineComponent.alias[0], + ), ) let hasRestProp = false diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index cbf5ce577..3c5cef6e6 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -1,4 +1,5 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' +import type { OptionsResolved } from '..' import { useModelHelperId } from './helper' import type { CallExpression } from '@babel/types' @@ -6,10 +7,18 @@ export function transformDefineModel( node: CallExpression, propsName: string, s: MagicStringAST, + options: OptionsResolved, ): void { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useModel', useModelHelperId), + importHelperFn( + s, + 0, + 'useModel', + useModelHelperId, + false, + options.defineModel.alias[0], + ), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 889bc643a..e574a0b5d 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -84,11 +84,11 @@ export function transformJsxMacros( } if (map.defineComponent) { - transformDefineComponent(root, propsName, map, s) + transformDefineComponent(root, propsName, map, s, options) } if (map.defineModel?.length) { map.defineModel.forEach(({ expression }) => { - transformDefineModel(expression, propsName, s) + transformDefineModel(expression, propsName, s, options) }) } if (map.defineSlots) { @@ -113,7 +113,7 @@ function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { if ( parents[2]?.type === 'CallExpression' && - s.sliceNode(parents[2].callee) === 'defineComponent' + options.defineComponent.alias.includes(s.sliceNode(parents[2].callee)) ) { if (!rootMap.has(root)) rootMap.set(root, {}) if (!rootMap.get(root)!.defineComponent) { @@ -127,7 +127,7 @@ function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { : node.type === 'ExpressionStatement' ? node.expression : undefined - const macroExpression = getMacroExpression(expression) + const macroExpression = getMacroExpression(expression, options) if (!macroExpression) return if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = s.sliceNode( @@ -136,12 +136,12 @@ function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { : macroExpression.callee, ) if (macroName) { - if (options.macros.defineModel?.includes(macroName)) { + if (options.defineModel.alias.includes(macroName)) { ;(rootMap.get(root)!.defineModel ??= []).push({ expression: macroExpression, isRequired: expression?.type === 'TSNonNullExpression', }) - } else if (options.macros.defineStyle?.includes(macroName)) { + } else if (options.defineStyle.alias.includes(macroName)) { const lang = macroExpression.callee.type === 'MemberExpression' && macroExpression.callee.property.type === 'Identifier' @@ -152,9 +152,9 @@ function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { isDeclaration: node.type === 'VariableDeclaration', lang, }) - } else if (options.macros.defineSlots?.includes(macroName)) { + } else if (options.defineSlots.alias.includes(macroName)) { rootMap.get(root)!.defineSlots = macroExpression - } else if (options.macros.defineExpose?.includes(macroName)) { + } else if (options.defineExpose.alias.includes(macroName)) { rootMap.get(root)!.defineExpose = macroExpression } } @@ -177,6 +177,7 @@ export function isFunctionalNode(node?: Node | null): node is FunctionalNode { export function getMacroExpression( node: Node | null | undefined, + options: OptionsResolved, ): CallExpression | undefined { if (node?.type === 'TSNonNullExpression') { node = node.expression @@ -191,9 +192,13 @@ export function getMacroExpression( return node } else if ( node.callee.type === 'Identifier' && - ['defineSlots', 'defineModel', 'defineExpose', 'defineStyle'].includes( - node.callee.name!, - ) + [ + ...options.defineComponent.alias, + ...options.defineSlots.alias, + ...options.defineModel.alias, + ...options.defineExpose.alias, + ...options.defineStyle.alias, + ].includes(node.callee.name!) ) { return node } diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index f40691ee3..054ac5402 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -28,16 +28,22 @@ import { transformStyle } from './core/style' export type Options = BaseOptions & { lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' - macros?: { - defineModel?: string[] - defineExpose?: string[] - defineSlots?: string[] - defineStyle?: string[] - } + defineComponent?: { alias: string[] } + defineModel?: { alias: string[] } + defineExpose?: { alias: string[] } + defineSlots?: { alias: string[] } + defineStyle?: { alias: string[] } } export type OptionsResolved = MarkRequired< Options, - 'include' | 'version' | 'lib' | 'macros' + | 'include' + | 'version' + | 'lib' + | 'defineComponent' + | 'defineModel' + | 'defineExpose' + | 'defineSlots' + | 'defineStyle' > function resolveOptions( @@ -53,12 +59,13 @@ function resolveOptions( ...options, version, lib, - macros: { - defineModel: options.macros?.defineModel ?? ['defineModel'], - defineSlots: options.macros?.defineSlots ?? ['defineSlots'], - defineExpose: options.macros?.defineExpose ?? ['defineExpose'], - defineStyle: options.macros?.defineStyle ?? ['defineStyle'], + defineComponent: { + alias: options?.defineComponent?.alias ?? ['defineComponent'], }, + defineModel: { alias: options?.defineModel?.alias ?? ['defineModel'] }, + defineSlots: { alias: options?.defineSlots?.alias ?? ['defineSlots'] }, + defineExpose: { alias: options?.defineExpose?.alias ?? ['defineExpose'] }, + defineStyle: { alias: options?.defineStyle?.alias ?? ['defineStyle'] }, } } @@ -88,17 +95,16 @@ const plugin: UnpluginInstance = createUnplugin( else if (id === withDefaultsHelperId) return withDefaultsCode }, - transformInclude: filter, - transform(code, id) { + transformInclude(id) { if (importMap.get(id)) return + return filter(id) + }, + transform(code, id) { return transformJsxMacros(code, id, importMap, options) }, }, { name: 'unplugin-define-style', - transformInclude: createFilter({ - include: [new RegExp(`^${helperPrefix}/define-style`)], - }), loadInclude(id) { return normalizePath(id).startsWith(helperPrefix) }, @@ -106,8 +112,9 @@ const plugin: UnpluginInstance = createUnplugin( const id = normalizePath(_id) if (importMap.get(id)) return importMap.get(id) }, + transformInclude: (id) => importMap.get(id), transform(code: string, id: string) { - if (importMap.get(id)) return transformStyle(code, id, options) + return transformStyle(code, id, options) }, }, ] diff --git a/packages/volar/src/index.ts b/packages/volar/src/index.ts index 3a9721362..ba7a750cb 100644 --- a/packages/volar/src/index.ts +++ b/packages/volar/src/index.ts @@ -50,6 +50,8 @@ const plugin: VueLanguagePlugin = (ctx) => Object.entries(plugins).flatMap(([name, plugin]) => { const options = getVolarOptions(ctx, name as keyof typeof plugins) if (!options) return [] + ;(ctx.vueCompilerOptions.vueMacros ??= {})[name as keyof typeof plugins] ??= + options as any return plugin(ctx, options as any) as ReturnType }) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index b0d1d00fc..fec774dd0 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -1,43 +1,61 @@ import { createFilter } from '@vue-macros/common' import { createPlugin, type PluginReturn } from 'ts-macro' -import { getRootMap, globalTypes, transformJsxMacros } from './jsx-macros/index' +import { + getGlobalTypes, + getRootMap, + transformJsxMacros, +} from './jsx-macros/index' import type { OptionsResolved } from '@vue-macros/config' const plugin: PluginReturn = - createPlugin(({ ts }, userOptions = {}) => { - if (!userOptions) return [] + createPlugin( + ( + { ts, vueCompilerOptions }, + userOptions = vueCompilerOptions?.vueMacros?.jsxMacros === true + ? {} + : (vueCompilerOptions?.vueMacros?.jsxMacros ?? {}), + ) => { + if (!userOptions) return [] - const filter = createFilter(userOptions) - const lib = userOptions.lib ?? 'vue' - const macros = { - defineModel: userOptions.macros?.defineModel ?? ['defineModel'], - defineExpose: userOptions.macros?.defineExpose ?? ['defineExpose'], - defineSlots: userOptions.macros?.defineSlots ?? ['defineSlots'], - defineStyle: userOptions.macros?.defineStyle ?? ['defineStyle'], - } + const filter = createFilter(userOptions) + const lib = userOptions.lib ?? 'vue' + const macros = { + defineComponent: { + alias: userOptions.defineComponent?.alias ?? ['defineComponent'], + }, + defineModel: { + alias: userOptions.defineModel?.alias ?? ['defineModel'], + }, + defineExpose: { + alias: userOptions.defineExpose?.alias ?? ['defineExpose'], + }, + defineSlots: { + alias: userOptions.defineSlots?.alias ?? ['defineSlots'], + }, + defineStyle: { + alias: userOptions.defineStyle?.alias ?? ['defineStyle'], + }, + } - return { - name: 'vue-macros-jsx-macros', - resolveVirtualCode(virtualCode) { - const { filePath, languageId, codes } = virtualCode - if (!filter(filePath) || !['jsx', 'tsx'].includes(languageId)) return + return { + name: 'vue-macros-jsx-macros', + resolveVirtualCode(virtualCode) { + const { filePath, languageId, codes } = virtualCode + if (!filter(filePath) || !['jsx', 'tsx'].includes(languageId)) return - const options = { - ...virtualCode, - ts, - lib, - macros, - } - const rootMap = getRootMap(options) - if (rootMap.size) transformJsxMacros(rootMap, options) - - if ( - (filePath.endsWith('.tsx') || rootMap.size) && - !codes.toString().includes(globalTypes) - ) { - codes.push(globalTypes) - } - }, - } - }) + const options = { + ...virtualCode, + ts, + lib, + ...macros, + } + const rootMap = getRootMap(options) + if (rootMap.size) { + transformJsxMacros(rootMap, options) + codes.push(getGlobalTypes(options)) + } + }, + } + }, + ) export default plugin diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index 6a7cae57c..87415c36a 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -1,11 +1,14 @@ import { HELPER_PREFIX } from '@vue-macros/common' +import type { TransformOptions } from '.' -export const globalTypes: string = ` -const { defineModel } = await import('vue') -declare function defineSlots>(): Partial; -declare function defineSlots>(slots: T): T; -declare function defineExpose = Record>(exposed?: Exposed): Exposed; +export function getGlobalTypes(options: TransformOptions): string { + return ` +const { defineModel${options.defineModel.alias[0] !== 'defineModel' ? `: ${options.defineModel.alias[0]}` : ''} } = await import('vue') +declare function ${options.defineSlots.alias[0]}>(): Partial; +declare function ${options.defineSlots.alias[0]}>(slots: T): T; +declare function ${options.defineExpose.alias[0]} = Record>(exposed?: Exposed): Exposed; type __VLS_StyleArgs = [style: string, options?: { scoped?: boolean }]; -declare const defineStyle: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T }; -declare function ${HELPER_PREFIX}defineComponent any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; +declare const ${options.defineStyle.alias[0]}: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T }; +declare function ${HELPER_PREFIX}${options.defineComponent.alias[0]} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; ` +} diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 4c5b42f78..72d5e0b7b 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -10,18 +10,27 @@ import type { OptionsResolved } from '@vue-macros/config' import type { TsmVirtualCode } from 'ts-macro' export { transformJsxMacros } from './transform' -export { globalTypes } from './global-types' +export { getGlobalTypes } from './global-types' type UserOptions = MarkRequired< Exclude, - 'lib' | 'macros' + | 'lib' + | 'defineModel' + | 'defineSlots' + | 'defineStyle' + | 'defineExpose' + | 'defineComponent' > export type TransformOptions = Overwrite< TsmVirtualCode, { ts: typeof import('typescript') lib: UserOptions['lib'] - macros: UserOptions['macros'] + defineModel: UserOptions['defineModel'] + defineSlots: UserOptions['defineSlots'] + defineStyle: UserOptions['defineStyle'] + defineExpose: UserOptions['defineExpose'] + defineComponent: UserOptions['defineComponent'] } > @@ -100,10 +109,11 @@ function getMacro( return ( ts.isIdentifier(expression.expression) && [ - ...(options.macros.defineModel ?? []), - ...(options.macros.defineExpose ?? []), - ...(options.macros.defineSlots ?? []), - ...(options.macros.defineStyle ?? []), + ...(options.defineModel.alias ?? ['defineModel']), + ...(options.defineSlots.alias ?? ['defineSlots']), + ...(options.defineStyle.alias ?? ['defineStyle']), + ...(options.defineExpose.alias ?? ['defineExpose']), + ...(options.defineComponent.alias ?? ['defineComponent']), ].includes(expression.expression.escapedText!) && node ) @@ -137,7 +147,9 @@ export function getRootMap(options: TransformOptions): RootMap { parents[2] && ts.isCallExpression(parents[2]) && !parents[2].typeArguments && - getText(parents[2].expression, options) === 'defineComponent' + options.defineComponent.alias.includes( + getText(parents[2].expression, options), + ) ) { if (!rootMap.has(root)) rootMap.set(root, {}) if (!rootMap.get(root)!.defineComponent) { @@ -159,7 +171,7 @@ export function getRootMap(options: TransformOptions): RootMap { let isRequired = macro.isRequired if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = getText(expression.expression, options) - if (options.macros.defineModel?.includes(macroName)) { + if (options.defineModel.alias.includes(macroName)) { const modelName = expression.arguments[0] && ts.isStringLiteralLike(expression.arguments[0]) @@ -214,7 +226,7 @@ export function getRootMap(options: TransformOptions): RootMap { getStart(initializer, options), `// @ts-ignore\n${id};\nlet ${id} =`, ) - } else if (options.macros.defineSlots?.includes(macroName)) { + } else if (options.defineSlots.alias.includes(macroName)) { replaceSourceRange( codes, source, @@ -223,7 +235,7 @@ export function getRootMap(options: TransformOptions): RootMap { `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, ) rootMap.get(root)!.defineSlots = `Partial` - } else if (options.macros.defineExpose?.includes(macroName)) { + } else if (options.defineExpose.alias.includes(macroName)) { replaceSourceRange( codes, source, From 71224ea4c17800def2b15cec407776399d5cad45 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 18:42:17 +0800 Subject: [PATCH 084/156] fix: typecheck --- packages/jsx-macros/tests/fixtures.test.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index d63d209bd..dd93d84e6 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -13,12 +13,11 @@ describe('fixtures', async () => { lib: 'vue', include: ['*.tsx'], version: 3.5, - macros: { - defineModel: ['defineModel'], - defineSlots: ['defineSlots'], - defineExpose: ['defineExpose'], - defineStyle: ['defineStyle'], - }, + defineModel: { alias: ['defineModel'] }, + defineSlots: { alias: ['defineSlots'] }, + defineStyle: { alias: ['defineStyle'] }, + defineExpose: { alias: ['defineExpose'] }, + defineComponent: { alias: ['defineComponent'] }, })?.code, ) }) @@ -34,12 +33,11 @@ describe('react fixtures', async () => { lib: 'react', include: ['*.tsx'], version: 18, - macros: { - defineModel: ['defineModel'], - defineSlots: ['defineSlots'], - defineExpose: ['defineExpose'], - defineStyle: ['defineStyle'], - }, + defineModel: { alias: ['defineModel'] }, + defineSlots: { alias: ['defineSlots'] }, + defineStyle: { alias: ['defineStyle'] }, + defineExpose: { alias: ['defineExpose'] }, + defineComponent: { alias: ['defineComponent'] }, })?.code, ) }) From d5df6532501e54624d7e36d3bce7e003d9438a42 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 18:46:40 +0800 Subject: [PATCH 085/156] fix: test --- .../tests/__snapshots__/fixtures.test.ts.snap | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 6e2e620e8..926343be1 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -5,13 +5,13 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { useAttrs as __MACROS_useAttrs } from "vue"; -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; +import { useModel as __MACROS_defineModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' const Comp = __MACROS_defineComponent( (__MACROS_props) => { const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});const attrs = __MACROS_useAttrs(); - const foo = __MACROS_useModel(__MACROS_props, 'foo', { + const foo = __MACROS_defineModel(__MACROS_props, 'foo', { validator: (value) => { return value === 'foo' }, @@ -26,7 +26,7 @@ const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, ) const Comp1 = __MACROS_defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { - const foo = __MACROS_useModel(props, 'foo') + const foo = __MACROS_defineModel(props, 'foo') return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null } }) @@ -65,13 +65,13 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export d exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { - const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar })! +import { useModel as __MACROS_defineModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { + const foo = __MACROS_defineModel(__MACROS_props, 'foo', { default: bar })! return
{foo.value}
} export default function (__MACROS_props) { - const modelValue = __MACROS_useModel(__MACROS_props, 'modelValue',)! + const modelValue = __MACROS_defineModel(__MACROS_props, 'modelValue',)! return ( {modelValue.value} @@ -87,14 +87,14 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export c const slots = Object.assign<{ default: () => any }>({}, __MACROS_getCurrentInstance()?.slots) - return
{slots.default()}
+ return
{slots.default?.()}
} export default function (__MACROS_props) { const slots = Object.assign({ default: () =>
default
, },__MACROS_getCurrentInstance()?.slots) - return
{slots.default()}
+ return
{slots.default?.()}
} " `; From 77af2b58c8c38b4c665735b4a40deeddc941bf00 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 20:17:48 +0800 Subject: [PATCH 086/156] feat: introduce jsx --- packages/jsx/README.md | 3 + packages/jsx/package.json | 150 ++++++++++++++++++ packages/jsx/src/esbuild.ts | 3 + packages/jsx/src/index.ts | 33 ++++ packages/jsx/src/rolldown.ts | 3 + packages/jsx/src/rollup.ts | 3 + packages/jsx/src/rspack.ts | 3 + packages/jsx/src/runtime.ts | 1 + packages/jsx/src/vite.ts | 3 + packages/jsx/src/volar.ts | 2 + packages/jsx/src/webpack.ts | 3 + .../tests/__snapshots__/fixtures.test.ts.snap | 14 ++ packages/jsx/tests/fixtures.test.ts | 28 ++++ packages/jsx/tests/fixtures/index.tsx | 4 + packages/jsx/tsup.config.ts | 3 + packages/volar/package.json | 9 ++ packages/volar/src/jsx.ts | 28 ++++ pnpm-lock.yaml | 19 +++ 18 files changed, 312 insertions(+) create mode 100644 packages/jsx/README.md create mode 100644 packages/jsx/package.json create mode 100644 packages/jsx/src/esbuild.ts create mode 100644 packages/jsx/src/index.ts create mode 100644 packages/jsx/src/rolldown.ts create mode 100644 packages/jsx/src/rollup.ts create mode 100644 packages/jsx/src/rspack.ts create mode 100644 packages/jsx/src/runtime.ts create mode 100644 packages/jsx/src/vite.ts create mode 100644 packages/jsx/src/volar.ts create mode 100644 packages/jsx/src/webpack.ts create mode 100644 packages/jsx/tests/__snapshots__/fixtures.test.ts.snap create mode 100644 packages/jsx/tests/fixtures.test.ts create mode 100644 packages/jsx/tests/fixtures/index.tsx create mode 100644 packages/jsx/tsup.config.ts create mode 100644 packages/volar/src/jsx.ts diff --git a/packages/jsx/README.md b/packages/jsx/README.md new file mode 100644 index 000000000..fbad5293a --- /dev/null +++ b/packages/jsx/README.md @@ -0,0 +1,3 @@ +# @vue-macros/jsx [![npm](https://img.shields.io/npm/v/@vue-macros/jsx.svg)](https://npmjs.com/package/@vue-macros/jsx) + +Please refer to [README.md](https://github.com/vue-macros/vue-macros#readme) diff --git a/packages/jsx/package.json b/packages/jsx/package.json new file mode 100644 index 000000000..f629d597f --- /dev/null +++ b/packages/jsx/package.json @@ -0,0 +1,150 @@ +{ + "name": "@vue-macros/jsx", + "version": "0.0.1", + "packageManager": "pnpm@9.13.2", + "description": "jsx feature from Vue Macros.", + "type": "module", + "keywords": [ + "vue-macros", + "macros", + "vue", + "sfc", + "setup", + "script-setup", + "jsx" + ], + "license": "MIT", + "homepage": "https://vue-macros.dev", + "bugs": { + "url": "https://github.com/vue-macros/vue-macros/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vue-macros/vue-macros.git", + "directory": "packages/jsx" + }, + "author": "三咲智子 ", + "files": [ + "dist" + ], + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "dev": "./src/index.ts", + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./esbuild": { + "dev": "./src/esbuild.ts", + "require": "./dist/esbuild.cjs", + "import": "./dist/esbuild.js" + }, + "./rolldown": { + "dev": "./src/rolldown.ts", + "require": "./dist/rolldown.cjs", + "import": "./dist/rolldown.js" + }, + "./rollup": { + "dev": "./src/rollup.ts", + "require": "./dist/rollup.cjs", + "import": "./dist/rollup.js" + }, + "./rspack": { + "dev": "./src/rspack.ts", + "require": "./dist/rspack.cjs", + "import": "./dist/rspack.js" + }, + "./runtime": { + "dev": "./src/runtime.ts", + "require": "./dist/runtime.cjs", + "import": "./dist/runtime.js" + }, + "./vite": { + "dev": "./src/vite.ts", + "require": "./dist/vite.cjs", + "import": "./dist/vite.js" + }, + "./volar": { + "dev": "./src/volar.ts", + "require": "./dist/volar.cjs", + "import": "./dist/volar.js" + }, + "./webpack": { + "dev": "./src/webpack.ts", + "require": "./dist/webpack.cjs", + "import": "./dist/webpack.js" + }, + "./*": "./*" + }, + "typesVersions": { + "*": { + "*": [ + "./dist/*", + "./*" + ] + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./esbuild": { + "require": "./dist/esbuild.cjs", + "import": "./dist/esbuild.js" + }, + "./rolldown": { + "require": "./dist/rolldown.cjs", + "import": "./dist/rolldown.js" + }, + "./rollup": { + "require": "./dist/rollup.cjs", + "import": "./dist/rollup.js" + }, + "./rspack": { + "require": "./dist/rspack.cjs", + "import": "./dist/rspack.js" + }, + "./runtime": { + "require": "./dist/runtime.cjs", + "import": "./dist/runtime.js" + }, + "./vite": { + "require": "./dist/vite.cjs", + "import": "./dist/vite.js" + }, + "./volar": { + "require": "./dist/volar.cjs", + "import": "./dist/volar.js" + }, + "./webpack": { + "require": "./dist/webpack.cjs", + "import": "./dist/webpack.js" + }, + "./*": "./*" + } + }, + "scripts": { + "build": "tsup", + "dev": "DEV=true tsup" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "dependencies": { + "@vue-macros/config": "workspace:*", + "@vue-macros/jsx-directive": "workspace:*", + "@vue-macros/volar": "workspace:*", + "unplugin-combine": "^1.0.3" + }, + "devDependencies": { + "vue": "catalog:" + }, + "engines": { + "node": ">=16.14.0" + } +} diff --git a/packages/jsx/src/esbuild.ts b/packages/jsx/src/esbuild.ts new file mode 100644 index 000000000..e8c6460dd --- /dev/null +++ b/packages/jsx/src/esbuild.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.esbuild as typeof unplugin.esbuild diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts new file mode 100644 index 000000000..7d9049647 --- /dev/null +++ b/packages/jsx/src/index.ts @@ -0,0 +1,33 @@ +import { resolveOptions, type Options } from '@vue-macros/config' +import VueJsxDirective from '@vue-macros/jsx-directive' + +import { + createCombinePlugin, + type UnpluginCombineInstance, +} from 'unplugin-combine' +import { generatePluginName } from '#macros' with { type: 'macro' } + +export { defineConfig, resolveOptions, type Options } from '@vue-macros/config' + +export type JSXOptions = Pick + +const name = generatePluginName() +const plugin: UnpluginCombineInstance = + createCombinePlugin((userOptions = {}, meta) => { + const options = resolveOptions(userOptions) + + const framework = meta.framework! + + const plugins = [ + options.jsxDirective + ? VueJsxDirective[framework](options.jsxDirective) + : undefined, + ].filter((plugin) => !!plugin) + + return { + name, + plugins, + } + }) + +export default plugin diff --git a/packages/jsx/src/rolldown.ts b/packages/jsx/src/rolldown.ts new file mode 100644 index 000000000..082a55c18 --- /dev/null +++ b/packages/jsx/src/rolldown.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.rolldown as typeof unplugin.rolldown diff --git a/packages/jsx/src/rollup.ts b/packages/jsx/src/rollup.ts new file mode 100644 index 000000000..45545feb1 --- /dev/null +++ b/packages/jsx/src/rollup.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.rollup as typeof unplugin.rollup diff --git a/packages/jsx/src/rspack.ts b/packages/jsx/src/rspack.ts new file mode 100644 index 000000000..6df8a0299 --- /dev/null +++ b/packages/jsx/src/rspack.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.rspack as typeof unplugin.rspack diff --git a/packages/jsx/src/runtime.ts b/packages/jsx/src/runtime.ts new file mode 100644 index 000000000..76bffcd98 --- /dev/null +++ b/packages/jsx/src/runtime.ts @@ -0,0 +1 @@ +export { shallowRef as useRef } from 'vue' diff --git a/packages/jsx/src/vite.ts b/packages/jsx/src/vite.ts new file mode 100644 index 000000000..a7c5db2c1 --- /dev/null +++ b/packages/jsx/src/vite.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.vite as typeof unplugin.vite diff --git a/packages/jsx/src/volar.ts b/packages/jsx/src/volar.ts new file mode 100644 index 000000000..01218877d --- /dev/null +++ b/packages/jsx/src/volar.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/no-default-export +export { default } from '@vue-macros/volar/jsx' diff --git a/packages/jsx/src/webpack.ts b/packages/jsx/src/webpack.ts new file mode 100644 index 000000000..74c1c9020 --- /dev/null +++ b/packages/jsx/src/webpack.ts @@ -0,0 +1,3 @@ +import unplugin from '.' + +export default unplugin.webpack as typeof unplugin.webpack diff --git a/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap new file mode 100644 index 000000000..469e2fdc3 --- /dev/null +++ b/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap @@ -0,0 +1,14 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`fixtures > tests/fixtures/index.tsx 1`] = ` +"// index.js +import { createVNode } from 'vue'; + +var index = () => { + let foo = 1; + return foo === 1 ? createVNode("div", null, [foo]) : null; +}; + +export { index as default }; +" +`; diff --git a/packages/jsx/tests/fixtures.test.ts b/packages/jsx/tests/fixtures.test.ts new file mode 100644 index 000000000..cc94672ad --- /dev/null +++ b/packages/jsx/tests/fixtures.test.ts @@ -0,0 +1,28 @@ +import { resolve } from 'node:path' +import { + rollupBuild, + RollupEsbuildPlugin, + RollupVueJsx, + testFixtures, +} from '@vue-macros/test-utils' +import { describe } from 'vitest' +import VueJsxMacros from '../src/rollup' + +describe('fixtures', async () => { + await testFixtures( + ['tests/fixtures/**/*'], + (_, id) => { + return rollupBuild(id, [ + VueJsxMacros(), + RollupVueJsx(), + RollupEsbuildPlugin({ + target: 'esnext', + }), + ]) + }, + { + cwd: resolve(__dirname, '..'), + promise: true, + }, + ) +}) diff --git a/packages/jsx/tests/fixtures/index.tsx b/packages/jsx/tests/fixtures/index.tsx new file mode 100644 index 000000000..32481e904 --- /dev/null +++ b/packages/jsx/tests/fixtures/index.tsx @@ -0,0 +1,4 @@ +export default () => { + let foo = 1 + return
{foo}
+} diff --git a/packages/jsx/tsup.config.ts b/packages/jsx/tsup.config.ts new file mode 100644 index 000000000..e5efb9683 --- /dev/null +++ b/packages/jsx/tsup.config.ts @@ -0,0 +1,3 @@ +import { config } from '../../tsup.config.js' + +export default config() diff --git a/packages/volar/package.json b/packages/volar/package.json index 7b2302968..4161d3c44 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -102,6 +102,11 @@ "require": "./dist/export-render.js", "import": "./dist/export-render.mjs" }, + "./jsx": { + "dev": "./src/jsx.ts", + "require": "./dist/jsx.js", + "import": "./dist/jsx.mjs" + }, "./jsx-directive": { "dev": "./src/jsx-directive.ts", "require": "./dist/jsx-directive.js", @@ -224,6 +229,10 @@ "require": "./dist/export-render.js", "import": "./dist/export-render.mjs" }, + "./jsx": { + "require": "./dist/jsx.js", + "import": "./dist/jsx.mjs" + }, "./jsx-directive": { "require": "./dist/jsx-directive.js", "import": "./dist/jsx-directive.mjs" diff --git a/packages/volar/src/jsx.ts b/packages/volar/src/jsx.ts new file mode 100644 index 000000000..c03095234 --- /dev/null +++ b/packages/volar/src/jsx.ts @@ -0,0 +1,28 @@ +import { createPlugin, type PluginReturn } from 'ts-macro' +import jsxDirective from './jsx-directive' +import jsxMacros from './jsx-macros' +import jsxRef from './jsx-ref' +import type { Options } from '@vue-macros/config' + +const jsxPlugins = { + jsxDirective, + jsxMacros, + jsxRef, +} + +type JSXOptions = { + jsxDirective?: Options['jsxDirective'] + jsxMacros?: Options['jsxMacros'] + jsxRef?: Options['jsxRef'] +} + +const plugin: PluginReturn = createPlugin( + (ctx, userOptions) => + Object.entries(jsxPlugins).flatMap(([name, plugin]) => { + const options = userOptions?.[name as keyof JSXOptions] ?? {} + if (!options) return [] + return plugin(options === true ? {} : options)(ctx) + }), +) + +export default plugin diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db71ff8da..5de73b214 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -641,6 +641,25 @@ importers: specifier: 'catalog:' version: 1.15.0(webpack-sources@3.2.3) + packages/jsx: + dependencies: + '@vue-macros/config': + specifier: workspace:* + version: link:../config + '@vue-macros/jsx-directive': + specifier: workspace:* + version: link:../jsx-directive + '@vue-macros/volar': + specifier: workspace:* + version: link:../volar + unplugin-combine: + specifier: ^1.0.3 + version: 1.0.3(@rspack/core@1.1.1(@swc/helpers@0.5.15))(esbuild@0.24.0)(rolldown@0.14.0)(rollup@4.27.2)(vite@5.4.11(@types/node@22.9.0)(less@4.2.0)(terser@5.36.0))(webpack@5.96.1(esbuild@0.24.0)) + devDependencies: + vue: + specifier: 'catalog:' + version: 3.5.13(typescript@5.6.3) + packages/jsx-directive: dependencies: '@vue-macros/common': From bdc3b7ed4858410b7ad5463bda8871a93bef3c87 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 20:22:24 +0800 Subject: [PATCH 087/156] chore: add changeset --- .changeset/nasty-bees-tickle.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/nasty-bees-tickle.md diff --git a/.changeset/nasty-bees-tickle.md b/.changeset/nasty-bees-tickle.md new file mode 100644 index 000000000..c8d638d9b --- /dev/null +++ b/.changeset/nasty-bees-tickle.md @@ -0,0 +1,7 @@ +--- +"@vue-macros/volar": patch +"@vue-macros/jsx": patch +--- + +introduce jsx + \ No newline at end of file From 433f9a961266aeba3eb718ec2947bbfff013c631 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 21 Nov 2024 20:27:24 +0800 Subject: [PATCH 088/156] chore: add changeset --- .changeset/friendly-rings-destroy.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/friendly-rings-destroy.md diff --git a/.changeset/friendly-rings-destroy.md b/.changeset/friendly-rings-destroy.md new file mode 100644 index 000000000..9c3fb14a9 --- /dev/null +++ b/.changeset/friendly-rings-destroy.md @@ -0,0 +1,6 @@ +--- +"@vue-macros/common": patch +--- + +add `as` option for importHelperFn + \ No newline at end of file From 8d0d5bb70201b736effa13353101e69a3dec0903 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 23 Nov 2024 09:51:22 +0800 Subject: [PATCH 089/156] feat: add jsx-runtime --- packages/jsx/jsx-runtime/dom.ts | 1655 ++++++++++++++++++++++++++ packages/jsx/jsx-runtime/global.d.ts | 160 +++ packages/jsx/jsx-runtime/index.cjs | 15 + packages/jsx/jsx-runtime/index.d.ts | 25 + packages/jsx/jsx-runtime/index.js | 12 + packages/jsx/package.json | 17 +- pnpm-lock.yaml | 3 + 7 files changed, 1886 insertions(+), 1 deletion(-) create mode 100644 packages/jsx/jsx-runtime/dom.ts create mode 100644 packages/jsx/jsx-runtime/global.d.ts create mode 100644 packages/jsx/jsx-runtime/index.cjs create mode 100644 packages/jsx/jsx-runtime/index.d.ts create mode 100644 packages/jsx/jsx-runtime/index.js diff --git a/packages/jsx/jsx-runtime/dom.ts b/packages/jsx/jsx-runtime/dom.ts new file mode 100644 index 000000000..dc4d2a764 --- /dev/null +++ b/packages/jsx/jsx-runtime/dom.ts @@ -0,0 +1,1655 @@ +// Note: this file is auto concatenated to the end of the bundled d.ts during +// build. + +// This code is based on react definition in DefinitelyTyped published under the MIT license. +// Repository: https://github.com/DefinitelyTyped/DefinitelyTyped +// Path in the repository: types/react/index.d.ts +// +// Copyrights of original definition are: +// AssureSign +// Microsoft +// John Reilly +// Benoit Benezech +// Patricio Zavolinsky +// Digiguru +// Eric Anderson +// Dovydas Navickas +// Josh Rutherford +// Guilherme Hübner +// Ferdy Budhidharma +// Johann Rakotoharisoa +// Olivier Pascal +// Martin Hochel +// Frank Li +// Jessica Franco +// Saransh Kataria +// Kanitkorn Sujautra +// Sebastian Silbermann + +import type * as CSS from 'csstype' + +export interface CSSProperties + extends CSS.Properties, + CSS.PropertiesHyphen { + /** + * The index signature was removed to enable closed typing for style + * using CSSType. You're able to use type assertion or module augmentation + * to add properties or an index signature of your own. + * + * For examples and more information, visit: + * https://github.com/frenic/csstype#what-should-i-do-when-i-get-type-errors + */ + [v: `--${string}`]: string | number | undefined +} + +type Booleanish = boolean | 'true' | 'false' +type Numberish = number | string + +// All the WAI-ARIA 1.1 attributes from https://www.w3.org/TR/wai-aria-1.1/ +export interface AriaAttributes { + /** Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application. */ + 'aria-activedescendant'?: string + /** Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. */ + 'aria-atomic'?: Booleanish + /** + * Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be + * presented if they are made. + */ + 'aria-autocomplete'?: 'none' | 'inline' | 'list' | 'both' + /** Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user. */ + 'aria-busy'?: Booleanish + /** + * Indicates the current "checked" state of checkboxes, radio buttons, and other widgets. + * @see aria-pressed @see aria-selected. + */ + 'aria-checked'?: Booleanish | 'mixed' + /** + * Defines the total number of columns in a table, grid, or treegrid. + * @see aria-colindex. + */ + 'aria-colcount'?: Numberish + /** + * Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. + * @see aria-colcount @see aria-colspan. + */ + 'aria-colindex'?: Numberish + /** + * Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. + * @see aria-colindex @see aria-rowspan. + */ + 'aria-colspan'?: Numberish + /** + * Identifies the element (or elements) whose contents or presence are controlled by the current element. + * @see aria-owns. + */ + 'aria-controls'?: string + /** Indicates the element that represents the current item within a container or set of related elements. */ + 'aria-current'?: Booleanish | 'page' | 'step' | 'location' | 'date' | 'time' + /** + * Identifies the element (or elements) that describes the object. + * @see aria-labelledby + */ + 'aria-describedby'?: string + /** + * Identifies the element that provides a detailed, extended description for the object. + * @see aria-describedby. + */ + 'aria-details'?: string + /** + * Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. + * @see aria-hidden @see aria-readonly. + */ + 'aria-disabled'?: Booleanish + /** + * Indicates what functions can be performed when a dragged object is released on the drop target. + * @deprecated in ARIA 1.1 + */ + 'aria-dropeffect'?: 'none' | 'copy' | 'execute' | 'link' | 'move' | 'popup' + /** + * Identifies the element that provides an error message for the object. + * @see aria-invalid @see aria-describedby. + */ + 'aria-errormessage'?: string + /** Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. */ + 'aria-expanded'?: Booleanish + /** + * Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, + * allows assistive technology to override the general default of reading in document source order. + */ + 'aria-flowto'?: string + /** + * Indicates an element's "grabbed" state in a drag-and-drop operation. + * @deprecated in ARIA 1.1 + */ + 'aria-grabbed'?: Booleanish + /** Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. */ + 'aria-haspopup'?: Booleanish | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' + /** + * Indicates whether the element is exposed to an accessibility API. + * @see aria-disabled. + */ + 'aria-hidden'?: Booleanish + /** + * Indicates the entered value does not conform to the format expected by the application. + * @see aria-errormessage. + */ + 'aria-invalid'?: Booleanish | 'grammar' | 'spelling' + /** Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. */ + 'aria-keyshortcuts'?: string + /** + * Defines a string value that labels the current element. + * @see aria-labelledby. + */ + 'aria-label'?: string + /** + * Identifies the element (or elements) that labels the current element. + * @see aria-describedby. + */ + 'aria-labelledby'?: string + /** Defines the hierarchical level of an element within a structure. */ + 'aria-level'?: Numberish + /** Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. */ + 'aria-live'?: 'off' | 'assertive' | 'polite' + /** Indicates whether an element is modal when displayed. */ + 'aria-modal'?: Booleanish + /** Indicates whether a text box accepts multiple lines of input or only a single line. */ + 'aria-multiline'?: Booleanish + /** Indicates that the user may select more than one item from the current selectable descendants. */ + 'aria-multiselectable'?: Booleanish + /** Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous. */ + 'aria-orientation'?: 'horizontal' | 'vertical' + /** + * Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship + * between DOM elements where the DOM hierarchy cannot be used to represent the relationship. + * @see aria-controls. + */ + 'aria-owns'?: string + /** + * Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. + * A hint could be a sample value or a brief description of the expected format. + */ + 'aria-placeholder'?: string + /** + * Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. + * @see aria-setsize. + */ + 'aria-posinset'?: Numberish + /** + * Indicates the current "pressed" state of toggle buttons. + * @see aria-checked @see aria-selected. + */ + 'aria-pressed'?: Booleanish | 'mixed' + /** + * Indicates that the element is not editable, but is otherwise operable. + * @see aria-disabled. + */ + 'aria-readonly'?: Booleanish + /** + * Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. + * @see aria-atomic. + */ + 'aria-relevant'?: + | 'additions' + | 'additions removals' + | 'additions text' + | 'all' + | 'removals' + | 'removals additions' + | 'removals text' + | 'text' + | 'text additions' + | 'text removals' + /** Indicates that user input is required on the element before a form may be submitted. */ + 'aria-required'?: Booleanish + /** Defines a human-readable, author-localized description for the role of an element. */ + 'aria-roledescription'?: string + /** + * Defines the total number of rows in a table, grid, or treegrid. + * @see aria-rowindex. + */ + 'aria-rowcount'?: Numberish + /** + * Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. + * @see aria-rowcount @see aria-rowspan. + */ + 'aria-rowindex'?: Numberish + /** + * Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. + * @see aria-rowindex @see aria-colspan. + */ + 'aria-rowspan'?: Numberish + /** + * Indicates the current "selected" state of various widgets. + * @see aria-checked @see aria-pressed. + */ + 'aria-selected'?: Booleanish + /** + * Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. + * @see aria-posinset. + */ + 'aria-setsize'?: Numberish + /** Indicates if items in a table or grid are sorted in ascending or descending order. */ + 'aria-sort'?: 'none' | 'ascending' | 'descending' | 'other' + /** Defines the maximum allowed value for a range widget. */ + 'aria-valuemax'?: Numberish + /** Defines the minimum allowed value for a range widget. */ + 'aria-valuemin'?: Numberish + /** + * Defines the current value for a range widget. + * @see aria-valuetext. + */ + 'aria-valuenow'?: Numberish + /** Defines the human readable text alternative of aria-valuenow for a range widget. */ + 'aria-valuetext'?: string +} + +/** + * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin MDN} + */ +type CrossOrigin = 'anonymous' | 'use-credentials' | '' + +// Vue's style normalization supports nested arrays +export type StyleValue = + | false + | null + | undefined + | string + | CSSProperties + | Array + +export interface HTMLAttributes + extends AriaAttributes, + EventHandlers> { + innerHTML?: string + + class?: any + style?: StyleValue + + // Standard HTML Attributes + accesskey?: string + autocapitalize?: + | 'off' + | 'none' + | 'on' + | 'sentences' + | 'words' + | 'characters' + | undefined + | (string & {}) + autofocus?: Booleanish + contenteditable?: Booleanish | 'inherit' | 'plaintext-only' + contextmenu?: string + dir?: string + draggable?: Booleanish + enterKeyHint?: + | 'enter' + | 'done' + | 'go' + | 'next' + | 'previous' + | 'search' + | 'send' + hidden?: Booleanish | '' | 'hidden' | 'until-found' + id?: string + inert?: Booleanish + lang?: string + nonce?: string + placeholder?: string + spellcheck?: Booleanish + tabindex?: Numberish + title?: string + translate?: 'yes' | 'no' + + // Unknown + radiogroup?: string // , + + // WAI-ARIA + role?: string + + // RDFa Attributes + about?: string + content?: string + datatype?: string + inlist?: any + prefix?: string + property?: string + rel?: string + resource?: string + rev?: string + typeof?: string + vocab?: string + + // Non-standard Attributes + autocorrect?: string + autosave?: string + color?: string + itemprop?: string + itemscope?: Booleanish + itemtype?: string + itemid?: string + itemref?: string + results?: Numberish + security?: string + unselectable?: 'on' | 'off' + + // Living Standard + /** + * Hints at the type of data that might be entered by the user while editing the element or its contents + * @see https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-inputmode-attribute + */ + inputmode?: + | 'none' + | 'text' + | 'tel' + | 'url' + | 'email' + | 'numeric' + | 'decimal' + | 'search' + /** + * Specify that a standard HTML element should behave like a defined custom built-in element + * @see https://html.spec.whatwg.org/multipage/custom-elements.html#attr-is + */ + is?: string +} + +type HTMLAttributeReferrerPolicy = + | '' + | 'no-referrer' + | 'no-referrer-when-downgrade' + | 'origin' + | 'origin-when-cross-origin' + | 'same-origin' + | 'strict-origin' + | 'strict-origin-when-cross-origin' + | 'unsafe-url' + +export interface AnchorHTMLAttributes extends HTMLAttributes { + download?: any + href?: string + hreflang?: string + media?: string + ping?: string + rel?: string + target?: string + type?: string + referrerpolicy?: HTMLAttributeReferrerPolicy +} + +export interface AreaHTMLAttributes extends HTMLAttributes { + alt?: string + coords?: string + download?: any + href?: string + hreflang?: string + media?: string + referrerpolicy?: HTMLAttributeReferrerPolicy + shape?: string + target?: string +} + +export interface AudioHTMLAttributes extends MediaHTMLAttributes {} + +export interface BaseHTMLAttributes extends HTMLAttributes { + href?: string + target?: string +} + +export interface BlockquoteHTMLAttributes extends HTMLAttributes { + cite?: string +} + +export interface ButtonHTMLAttributes extends HTMLAttributes { + disabled?: Booleanish + form?: string + formaction?: string + formenctype?: string + formmethod?: string + formnovalidate?: Booleanish + formtarget?: string + name?: string + type?: 'submit' | 'reset' | 'button' + value?: string | ReadonlyArray | number +} + +export interface CanvasHTMLAttributes extends HTMLAttributes { + height?: Numberish + width?: Numberish +} + +export interface ColHTMLAttributes extends HTMLAttributes { + span?: Numberish + width?: Numberish +} + +export interface ColgroupHTMLAttributes extends HTMLAttributes { + span?: Numberish +} + +export interface DataHTMLAttributes extends HTMLAttributes { + value?: string | ReadonlyArray | number +} + +export interface DetailsHTMLAttributes extends HTMLAttributes { + name?: string + open?: Booleanish + onToggle?: (payload: ToggleEvent) => void +} + +export interface DelHTMLAttributes extends HTMLAttributes { + cite?: string + datetime?: string +} + +export interface DialogHTMLAttributes extends HTMLAttributes { + open?: Booleanish + onClose?: (payload: Event) => void +} + +export interface EmbedHTMLAttributes extends HTMLAttributes { + height?: Numberish + src?: string + type?: string + width?: Numberish +} + +export interface FieldsetHTMLAttributes extends HTMLAttributes { + disabled?: Booleanish + form?: string + name?: string +} + +export interface FormHTMLAttributes extends HTMLAttributes { + acceptcharset?: string + action?: string + autocomplete?: string + enctype?: string + method?: string + name?: string + novalidate?: Booleanish + target?: string +} + +export interface HtmlHTMLAttributes extends HTMLAttributes { + manifest?: string +} + +export interface IframeHTMLAttributes extends HTMLAttributes { + allow?: string + allowfullscreen?: Booleanish + allowtransparency?: Booleanish + /** @deprecated */ + frameborder?: Numberish + height?: Numberish + loading?: 'eager' | 'lazy' + /** @deprecated */ + marginheight?: Numberish + /** @deprecated */ + marginwidth?: Numberish + name?: string + referrerpolicy?: HTMLAttributeReferrerPolicy + sandbox?: string + /** @deprecated */ + scrolling?: string + seamless?: Booleanish + src?: string + srcdoc?: string + width?: Numberish +} + +export interface ImgHTMLAttributes extends HTMLAttributes { + alt?: string + crossorigin?: CrossOrigin + decoding?: 'async' | 'auto' | 'sync' + height?: Numberish + loading?: 'eager' | 'lazy' + referrerpolicy?: HTMLAttributeReferrerPolicy + sizes?: string + src?: string + srcset?: string + usemap?: string + width?: Numberish +} + +export interface InsHTMLAttributes extends HTMLAttributes { + cite?: string + datetime?: string +} + +export type InputTypeHTMLAttribute = + | 'button' + | 'checkbox' + | 'color' + | 'date' + | 'datetime-local' + | 'email' + | 'file' + | 'hidden' + | 'image' + | 'month' + | 'number' + | 'password' + | 'radio' + | 'range' + | 'reset' + | 'search' + | 'submit' + | 'tel' + | 'text' + | 'time' + | 'url' + | 'week' + | (string & {}) + +type AutoFillAddressKind = 'billing' | 'shipping' +type AutoFillBase = '' | 'off' | 'on' +type AutoFillContactField = + | 'email' + | 'tel' + | 'tel-area-code' + | 'tel-country-code' + | 'tel-extension' + | 'tel-local' + | 'tel-local-prefix' + | 'tel-local-suffix' + | 'tel-national' +type AutoFillContactKind = 'home' | 'mobile' | 'work' +type AutoFillCredentialField = 'webauthn' +type AutoFillNormalField = + | 'additional-name' + | 'address-level1' + | 'address-level2' + | 'address-level3' + | 'address-level4' + | 'address-line1' + | 'address-line2' + | 'address-line3' + | 'bday-day' + | 'bday-month' + | 'bday-year' + | 'cc-csc' + | 'cc-exp' + | 'cc-exp-month' + | 'cc-exp-year' + | 'cc-family-name' + | 'cc-given-name' + | 'cc-name' + | 'cc-number' + | 'cc-type' + | 'country' + | 'country-name' + | 'current-password' + | 'family-name' + | 'given-name' + | 'honorific-prefix' + | 'honorific-suffix' + | 'name' + | 'new-password' + | 'one-time-code' + | 'organization' + | 'postal-code' + | 'street-address' + | 'transaction-amount' + | 'transaction-currency' + | 'username' +type OptionalPrefixToken = `${T} ` | '' +type OptionalPostfixToken = ` ${T}` | '' +type AutoFillField = + | AutoFillNormalField + | `${OptionalPrefixToken}${AutoFillContactField}` +type AutoFillSection = `section-${string}` +type AutoFill = + | AutoFillBase + | `${OptionalPrefixToken}${OptionalPrefixToken}${AutoFillField}${OptionalPostfixToken}` +type HTMLInputAutoCompleteAttribute = AutoFill | (string & {}) + +export interface InputHTMLAttributes extends HTMLAttributes { + accept?: string + alt?: string + autocomplete?: HTMLInputAutoCompleteAttribute + capture?: boolean | 'user' | 'environment' // https://www.w3.org/tr/html-media-capture/#the-capture-attribute + checked?: Booleanish | any[] | Set // for IDE v-model multi-checkbox support + disabled?: Booleanish + form?: string + formaction?: string + formenctype?: string + formmethod?: string + formnovalidate?: Booleanish + formtarget?: string + height?: Numberish + indeterminate?: boolean + list?: string + max?: Numberish + maxlength?: Numberish + min?: Numberish + minlength?: Numberish + multiple?: Booleanish + name?: string + pattern?: string + placeholder?: string + readonly?: Booleanish + required?: Booleanish + size?: Numberish + src?: string + step?: Numberish + type?: InputTypeHTMLAttribute + value?: any // we support :value to be bound to anything w/ v-model + width?: Numberish +} + +export interface KeygenHTMLAttributes extends HTMLAttributes { + challenge?: string + disabled?: Booleanish + form?: string + keytype?: string + keyparams?: string + name?: string +} + +export interface LabelHTMLAttributes extends HTMLAttributes { + for?: string + form?: string +} + +export interface LiHTMLAttributes extends HTMLAttributes { + value?: string | ReadonlyArray | number +} + +export interface LinkHTMLAttributes extends HTMLAttributes { + as?: string + crossorigin?: CrossOrigin + fetchPriority?: 'high' | 'low' | 'auto' + href?: string + hreflang?: string + integrity?: string + media?: string + imageSrcSet?: string + imageSizes?: string + referrerpolicy?: HTMLAttributeReferrerPolicy + sizes?: string + type?: string + charset?: string +} + +export interface MapHTMLAttributes extends HTMLAttributes { + name?: string +} + +export interface MenuHTMLAttributes extends HTMLAttributes { + type?: string +} + +export interface MediaHTMLAttributes extends HTMLAttributes { + autoplay?: Booleanish + controls?: Booleanish + controlslist?: string + crossorigin?: CrossOrigin + loop?: Booleanish + mediagroup?: string + muted?: Booleanish + playsinline?: Booleanish + preload?: string + src?: string +} + +export interface MetaHTMLAttributes extends HTMLAttributes { + charset?: string + content?: string + httpequiv?: string + media?: string | undefined + name?: string +} + +export interface MeterHTMLAttributes extends HTMLAttributes { + form?: string + high?: Numberish + low?: Numberish + max?: Numberish + min?: Numberish + optimum?: Numberish + value?: string | ReadonlyArray | number +} + +export interface QuoteHTMLAttributes extends HTMLAttributes { + cite?: string +} + +export interface ObjectHTMLAttributes extends HTMLAttributes { + classid?: string + data?: string + form?: string + height?: Numberish + name?: string + type?: string + usemap?: string + width?: Numberish + wmode?: string +} + +export interface OlHTMLAttributes extends HTMLAttributes { + reversed?: Booleanish + start?: Numberish + type?: '1' | 'a' | 'A' | 'i' | 'I' +} + +export interface OptgroupHTMLAttributes extends HTMLAttributes { + disabled?: Booleanish + label?: string +} + +export interface OptionHTMLAttributes extends HTMLAttributes { + disabled?: Booleanish + label?: string + selected?: Booleanish + value?: any // we support :value to be bound to anything w/ v-model +} + +export interface OutputHTMLAttributes extends HTMLAttributes { + for?: string + form?: string + name?: string +} + +export interface ParamHTMLAttributes extends HTMLAttributes { + name?: string + value?: string | ReadonlyArray | number +} + +export interface ProgressHTMLAttributes extends HTMLAttributes { + max?: Numberish + value?: string | ReadonlyArray | number +} + +export interface ScriptHTMLAttributes extends HTMLAttributes { + async?: Booleanish + /** @deprecated */ + charset?: string + crossorigin?: CrossOrigin + defer?: Booleanish + integrity?: string + nomodule?: Booleanish + referrerpolicy?: HTMLAttributeReferrerPolicy + src?: string + type?: string +} + +export interface SelectHTMLAttributes extends HTMLAttributes { + autocomplete?: string + disabled?: Booleanish + form?: string + multiple?: Booleanish + name?: string + required?: Booleanish + size?: Numberish + value?: any // we support :value to be bound to anything w/ v-model +} + +export interface SourceHTMLAttributes extends HTMLAttributes { + height?: number + media?: string + sizes?: string + src?: string + srcset?: string + type?: string + width?: number +} + +export interface StyleHTMLAttributes extends HTMLAttributes { + media?: string + scoped?: Booleanish + type?: string +} + +export interface TableHTMLAttributes extends HTMLAttributes { + align?: 'left' | 'center' | 'right' + bgcolor?: string + border?: number + cellpadding?: Numberish + cellspacing?: Numberish + frame?: Booleanish + rules?: 'none' | 'groups' | 'rows' | 'columns' | 'all' + summary?: string + width?: Numberish +} + +export interface TextareaHTMLAttributes extends HTMLAttributes { + autocomplete?: string + cols?: Numberish + dirname?: string + disabled?: Booleanish + form?: string + maxlength?: Numberish + minlength?: Numberish + name?: string + placeholder?: string + readonly?: Booleanish + required?: Booleanish + rows?: Numberish + value?: string | ReadonlyArray | number | null + wrap?: string +} + +export interface TdHTMLAttributes extends HTMLAttributes { + align?: 'left' | 'center' | 'right' | 'justify' | 'char' + colspan?: Numberish + headers?: string + rowspan?: Numberish + scope?: string + abbr?: string + height?: Numberish + width?: Numberish + valign?: 'top' | 'middle' | 'bottom' | 'baseline' +} + +export interface ThHTMLAttributes extends HTMLAttributes { + align?: 'left' | 'center' | 'right' | 'justify' | 'char' + colspan?: Numberish + headers?: string + rowspan?: Numberish + scope?: string + abbr?: string +} + +export interface TimeHTMLAttributes extends HTMLAttributes { + datetime?: string +} + +export interface TrackHTMLAttributes extends HTMLAttributes { + default?: Booleanish + kind?: string + label?: string + src?: string + srclang?: string +} + +export interface VideoHTMLAttributes extends MediaHTMLAttributes { + height?: Numberish + playsinline?: Booleanish + poster?: string + width?: Numberish + disablePictureInPicture?: Booleanish + disableRemotePlayback?: Booleanish +} + +export interface WebViewHTMLAttributes extends HTMLAttributes { + allowfullscreen?: Booleanish + allowpopups?: Booleanish + autosize?: Booleanish + blinkfeatures?: string + disableblinkfeatures?: string + disableguestresize?: Booleanish + disablewebsecurity?: Booleanish + guestinstance?: string + httpreferrer?: string + nodeintegration?: Booleanish + partition?: string + plugins?: Booleanish + preload?: string + src?: string + useragent?: string + webpreferences?: string +} + +export interface SVGAttributes extends AriaAttributes, EventHandlers { + innerHTML?: string + + /** + * SVG Styling Attributes + * @see https://www.w3.org/TR/SVG/styling.html#ElementSpecificStyling + */ + class?: any + style?: StyleValue + + color?: string + height?: Numberish + id?: string + lang?: string + max?: Numberish + media?: string + method?: string + min?: Numberish + name?: string + target?: string + type?: string + width?: Numberish + + // Other HTML properties supported by SVG elements in browsers + role?: string + tabindex?: Numberish + crossOrigin?: CrossOrigin + + // SVG Specific attributes + 'accent-height'?: Numberish + accumulate?: 'none' | 'sum' + additive?: 'replace' | 'sum' + 'alignment-baseline'?: + | 'auto' + | 'baseline' + | 'before-edge' + | 'text-before-edge' + | 'middle' + | 'central' + | 'after-edge' + | 'text-after-edge' + | 'ideographic' + | 'alphabetic' + | 'hanging' + | 'mathematical' + | 'inherit' + allowReorder?: 'no' | 'yes' + alphabetic?: Numberish + amplitude?: Numberish + 'arabic-form'?: 'initial' | 'medial' | 'terminal' | 'isolated' + ascent?: Numberish + attributeName?: string + attributeType?: string + autoReverse?: Numberish + azimuth?: Numberish + baseFrequency?: Numberish + 'baseline-shift'?: Numberish + baseProfile?: Numberish + bbox?: Numberish + begin?: Numberish + bias?: Numberish + by?: Numberish + calcMode?: Numberish + 'cap-height'?: Numberish + clip?: Numberish + 'clip-path'?: string + clipPathUnits?: Numberish + 'clip-rule'?: Numberish + 'color-interpolation'?: Numberish + 'color-interpolation-filters'?: 'auto' | 'sRGB' | 'linearRGB' | 'inherit' + 'color-profile'?: Numberish + 'color-rendering'?: Numberish + contentScriptType?: Numberish + contentStyleType?: Numberish + cursor?: Numberish + cx?: Numberish + cy?: Numberish + d?: string + decelerate?: Numberish + descent?: Numberish + diffuseConstant?: Numberish + direction?: Numberish + display?: Numberish + divisor?: Numberish + 'dominant-baseline'?: Numberish + dur?: Numberish + dx?: Numberish + dy?: Numberish + edgeMode?: Numberish + elevation?: Numberish + 'enable-background'?: Numberish + end?: Numberish + exponent?: Numberish + externalResourcesRequired?: Numberish + fill?: string + 'fill-opacity'?: Numberish + 'fill-rule'?: 'nonzero' | 'evenodd' | 'inherit' + filter?: string + filterRes?: Numberish + filterUnits?: Numberish + 'flood-color'?: Numberish + 'flood-opacity'?: Numberish + focusable?: Numberish + 'font-family'?: string + 'font-size'?: Numberish + 'font-size-adjust'?: Numberish + 'font-stretch'?: Numberish + 'font-style'?: Numberish + 'font-variant'?: Numberish + 'font-weight'?: Numberish + format?: Numberish + from?: Numberish + fx?: Numberish + fy?: Numberish + g1?: Numberish + g2?: Numberish + 'glyph-name'?: Numberish + 'glyph-orientation-horizontal'?: Numberish + 'glyph-orientation-vertical'?: Numberish + glyphRef?: Numberish + gradientTransform?: string + gradientUnits?: string + hanging?: Numberish + 'horiz-adv-x'?: Numberish + 'horiz-origin-x'?: Numberish + href?: string + ideographic?: Numberish + 'image-rendering'?: Numberish + in2?: Numberish + in?: string + intercept?: Numberish + k1?: Numberish + k2?: Numberish + k3?: Numberish + k4?: Numberish + k?: Numberish + kernelMatrix?: Numberish + kernelUnitLength?: Numberish + kerning?: Numberish + keyPoints?: Numberish + keySplines?: Numberish + keyTimes?: Numberish + lengthAdjust?: Numberish + 'letter-spacing'?: Numberish + 'lighting-color'?: Numberish + limitingConeAngle?: Numberish + local?: Numberish + 'marker-end'?: string + markerHeight?: Numberish + 'marker-mid'?: string + 'marker-start'?: string + markerUnits?: Numberish + markerWidth?: Numberish + mask?: string + maskContentUnits?: Numberish + maskUnits?: Numberish + mathematical?: Numberish + mode?: Numberish + numOctaves?: Numberish + offset?: Numberish + opacity?: Numberish + operator?: Numberish + order?: Numberish + orient?: Numberish + orientation?: Numberish + origin?: Numberish + overflow?: Numberish + 'overline-position'?: Numberish + 'overline-thickness'?: Numberish + 'paint-order'?: Numberish + 'panose-1'?: Numberish + pathLength?: Numberish + patternContentUnits?: string + patternTransform?: Numberish + patternUnits?: string + 'pointer-events'?: Numberish + points?: string + pointsAtX?: Numberish + pointsAtY?: Numberish + pointsAtZ?: Numberish + preserveAlpha?: Numberish + preserveAspectRatio?: string + primitiveUnits?: Numberish + r?: Numberish + radius?: Numberish + refX?: Numberish + refY?: Numberish + renderingIntent?: Numberish + repeatCount?: Numberish + repeatDur?: Numberish + requiredExtensions?: Numberish + requiredFeatures?: Numberish + restart?: Numberish + result?: string + rotate?: Numberish + rx?: Numberish + ry?: Numberish + scale?: Numberish + seed?: Numberish + 'shape-rendering'?: Numberish + slope?: Numberish + spacing?: Numberish + specularConstant?: Numberish + specularExponent?: Numberish + speed?: Numberish + spreadMethod?: string + startOffset?: Numberish + stdDeviation?: Numberish + stemh?: Numberish + stemv?: Numberish + stitchTiles?: Numberish + 'stop-color'?: string + 'stop-opacity'?: Numberish + 'strikethrough-position'?: Numberish + 'strikethrough-thickness'?: Numberish + string?: Numberish + stroke?: string + 'stroke-dasharray'?: Numberish + 'stroke-dashoffset'?: Numberish + 'stroke-linecap'?: 'butt' | 'round' | 'square' | 'inherit' + 'stroke-linejoin'?: 'miter' | 'round' | 'bevel' | 'inherit' + 'stroke-miterlimit'?: Numberish + 'stroke-opacity'?: Numberish + 'stroke-width'?: Numberish + surfaceScale?: Numberish + systemLanguage?: Numberish + tableValues?: Numberish + targetX?: Numberish + targetY?: Numberish + 'text-anchor'?: string + 'text-decoration'?: Numberish + textLength?: Numberish + 'text-rendering'?: Numberish + to?: Numberish + transform?: string + u1?: Numberish + u2?: Numberish + 'underline-position'?: Numberish + 'underline-thickness'?: Numberish + unicode?: Numberish + 'unicode-bidi'?: Numberish + 'unicode-range'?: Numberish + 'unitsPer-em'?: Numberish + 'v-alphabetic'?: Numberish + values?: string + 'vector-effect'?: Numberish + version?: string + 'vert-adv-y'?: Numberish + 'vert-origin-x'?: Numberish + 'vert-origin-y'?: Numberish + 'v-hanging'?: Numberish + 'v-ideographic'?: Numberish + viewBox?: string + viewTarget?: Numberish + visibility?: Numberish + 'v-mathematical'?: Numberish + widths?: Numberish + 'word-spacing'?: Numberish + 'writing-mode'?: Numberish + x1?: Numberish + x2?: Numberish + x?: Numberish + xChannelSelector?: string + 'x-height'?: Numberish + xlinkActuate?: string + xlinkArcrole?: string + xlinkHref?: string + xlinkRole?: string + xlinkShow?: string + xlinkTitle?: string + xlinkType?: string + xmlns?: string + xmlnsXlink?: string + y1?: Numberish + y2?: Numberish + y?: Numberish + yChannelSelector?: string + z?: Numberish + zoomAndPan?: string +} + +export interface IntrinsicElementAttributes { + a: AnchorHTMLAttributes + abbr: HTMLAttributes + address: HTMLAttributes + area: AreaHTMLAttributes + article: HTMLAttributes + aside: HTMLAttributes + audio: AudioHTMLAttributes + b: HTMLAttributes + base: BaseHTMLAttributes + bdi: HTMLAttributes + bdo: HTMLAttributes + big: HTMLAttributes + blockquote: BlockquoteHTMLAttributes + body: HTMLAttributes + br: HTMLAttributes + button: ButtonHTMLAttributes + canvas: CanvasHTMLAttributes + caption: HTMLAttributes + cite: HTMLAttributes + code: HTMLAttributes + col: ColHTMLAttributes + colgroup: ColgroupHTMLAttributes + data: DataHTMLAttributes + datalist: HTMLAttributes + dd: HTMLAttributes + del: DelHTMLAttributes + details: DetailsHTMLAttributes + dfn: HTMLAttributes + dialog: DialogHTMLAttributes + div: HTMLAttributes + dl: HTMLAttributes + dt: HTMLAttributes + em: HTMLAttributes + embed: EmbedHTMLAttributes + fieldset: FieldsetHTMLAttributes + figcaption: HTMLAttributes + figure: HTMLAttributes + footer: HTMLAttributes + form: FormHTMLAttributes + h1: HTMLAttributes + h2: HTMLAttributes + h3: HTMLAttributes + h4: HTMLAttributes + h5: HTMLAttributes + h6: HTMLAttributes + head: HTMLAttributes + header: HTMLAttributes + hgroup: HTMLAttributes + hr: HTMLAttributes + html: HtmlHTMLAttributes + i: HTMLAttributes + iframe: IframeHTMLAttributes + img: ImgHTMLAttributes + input: InputHTMLAttributes + ins: InsHTMLAttributes + kbd: HTMLAttributes + keygen: KeygenHTMLAttributes + label: LabelHTMLAttributes + legend: HTMLAttributes + li: LiHTMLAttributes + link: LinkHTMLAttributes + main: HTMLAttributes + map: MapHTMLAttributes + mark: HTMLAttributes + menu: MenuHTMLAttributes + menuitem: HTMLAttributes + meta: MetaHTMLAttributes + meter: MeterHTMLAttributes + nav: HTMLAttributes + noindex: HTMLAttributes + noscript: HTMLAttributes + object: ObjectHTMLAttributes + ol: OlHTMLAttributes + optgroup: OptgroupHTMLAttributes + option: OptionHTMLAttributes + output: OutputHTMLAttributes + p: HTMLAttributes + param: ParamHTMLAttributes + picture: HTMLAttributes + pre: HTMLAttributes + progress: ProgressHTMLAttributes + q: QuoteHTMLAttributes + rp: HTMLAttributes + rt: HTMLAttributes + ruby: HTMLAttributes + s: HTMLAttributes + samp: HTMLAttributes + search: HTMLAttributes + script: ScriptHTMLAttributes + section: HTMLAttributes + select: SelectHTMLAttributes + small: HTMLAttributes + source: SourceHTMLAttributes + span: HTMLAttributes + strong: HTMLAttributes + style: StyleHTMLAttributes + sub: HTMLAttributes + summary: HTMLAttributes + sup: HTMLAttributes + table: TableHTMLAttributes + template: HTMLAttributes + tbody: HTMLAttributes + td: TdHTMLAttributes + textarea: TextareaHTMLAttributes + tfoot: HTMLAttributes + th: ThHTMLAttributes + thead: HTMLAttributes + time: TimeHTMLAttributes + title: HTMLAttributes + tr: HTMLAttributes + track: TrackHTMLAttributes + u: HTMLAttributes + ul: HTMLAttributes + var: HTMLAttributes + video: VideoHTMLAttributes + wbr: HTMLAttributes + webview: WebViewHTMLAttributes + + // SVG + svg: SVGAttributes + + animate: SVGAttributes + animateMotion: SVGAttributes + animateTransform: SVGAttributes + circle: SVGAttributes + clipPath: SVGAttributes + defs: SVGAttributes + desc: SVGAttributes + ellipse: SVGAttributes + feBlend: SVGAttributes + feColorMatrix: SVGAttributes + feComponentTransfer: SVGAttributes + feComposite: SVGAttributes + feConvolveMatrix: SVGAttributes + feDiffuseLighting: SVGAttributes + feDisplacementMap: SVGAttributes + feDistantLight: SVGAttributes + feDropShadow: SVGAttributes + feFlood: SVGAttributes + feFuncA: SVGAttributes + feFuncB: SVGAttributes + feFuncG: SVGAttributes + feFuncR: SVGAttributes + feGaussianBlur: SVGAttributes + feImage: SVGAttributes + feMerge: SVGAttributes + feMergeNode: SVGAttributes + feMorphology: SVGAttributes + feOffset: SVGAttributes + fePointLight: SVGAttributes + feSpecularLighting: SVGAttributes + feSpotLight: SVGAttributes + feTile: SVGAttributes + feTurbulence: SVGAttributes + filter: SVGAttributes + foreignObject: SVGAttributes + g: SVGAttributes + image: SVGAttributes + line: SVGAttributes + linearGradient: SVGAttributes + marker: SVGAttributes + mask: SVGAttributes + metadata: SVGAttributes + mpath: SVGAttributes + path: SVGAttributes + pattern: SVGAttributes + polygon: SVGAttributes + polyline: SVGAttributes + radialGradient: SVGAttributes + rect: SVGAttributes + stop: SVGAttributes + switch: SVGAttributes + symbol: SVGAttributes + text: SVGAttributes + textPath: SVGAttributes + tspan: SVGAttributes + use: SVGAttributes + view: SVGAttributes +} + +export interface Events { + // clipboard events + onCopy: ClipboardEventHandler + onCut: ClipboardEventHandler + onPaste: ClipboardEventHandler + + // composition events + onCompositionend: CompositionEventHandler + onCompositionstart: CompositionEventHandler + onCompositionupdate: CompositionEventHandler + + // drag drop events + onDrag: DragEventHandler + onDragend: DragEventHandler + onDragenter: DragEventHandler + onDragexit: DragEventHandler + onDragleave: DragEventHandler + onDragover: DragEventHandler + onDragstart: DragEventHandler + onDrop: DragEventHandler + + // focus events + onFocus: FocusEventHandler + onFocusin: FocusEventHandler + onFocusout: FocusEventHandler + onBlur: FocusEventHandler + + // form events + onChange: ChangeEventHandler + onBeforeinput: FormEventHandler + onInput: FormEventHandler + onReset: FormEventHandler + onSubmit: FormEventHandler + onInvalid: FormEventHandler + + // image events + onLoad: BaseEventHandler + onError: BaseEventHandler + + // keyboard events + onKeydown: KeyboardEventHandler + onKeypress: KeyboardEventHandler + onKeyup: KeyboardEventHandler + + // mouse events + onAuxclick: MouseEventHandler + onClick: MouseEventHandler + onContextmenu: MouseEventHandler + onDblclick: MouseEventHandler + onMousedown: MouseEventHandler + onMouseenter: MouseEventHandler + onMouseleave: MouseEventHandler + onMousemove: MouseEventHandler + onMouseout: MouseEventHandler + onMouseover: MouseEventHandler + onMouseup: MouseEventHandler + + // media events + onAbort: BaseEventHandler + onCanplay: BaseEventHandler + onCanplaythrough: BaseEventHandler + onDurationchange: BaseEventHandler + onEmptied: BaseEventHandler + onEncrypted: BaseEventHandler + onEnded: BaseEventHandler + onLoadeddata: BaseEventHandler + onLoadedmetadata: BaseEventHandler + onLoadstart: BaseEventHandler + onPause: BaseEventHandler + onPlay: BaseEventHandler + onPlaying: BaseEventHandler + onProgress: BaseEventHandler + onRatechange: BaseEventHandler + onSeeked: BaseEventHandler + onSeeking: BaseEventHandler + onStalled: BaseEventHandler + onSuspend: BaseEventHandler + onTimeupdate: BaseEventHandler + onVolumechange: BaseEventHandler + onWaiting: BaseEventHandler + + // selection events + onSelect: BaseEventHandler + + // scroll events + onScroll: UIEventHandler + onScrollend: UIEventHandler + + // touch events + onTouchcancel: TouchEvent + onTouchend: TouchEvent + onTouchmove: TouchEvent + onTouchstart: TouchEvent + + // pointer events + onPointerdown: PointerEvent + onPointermove: PointerEvent + onPointerup: PointerEvent + onPointercancel: PointerEvent + onPointerenter: PointerEvent + onPointerleave: PointerEvent + onPointerover: PointerEvent + onPointerout: PointerEvent + + // wheel events + onWheel: WheelEventHandler + + // animation events + onAnimationstart: AnimationEventHandler + onAnimationend: AnimationEventHandler + onAnimationiteration: AnimationEventHandler + + // transition events + onTransitionend: TransitionEventHandler + onTransitionstart: TransitionEventHandler +} + +type EventHandlers = { + [K in keyof E]?: E[K] extends (...args: any) => any + ? E[K] + : (payload: E[K]) => void +} + +export type ReservedProps = { + key?: PropertyKey + ref?: import('vue').VNodeRef + ref_for?: boolean + ref_key?: string +} + +export type NativeElements = { + [K in keyof IntrinsicElementAttributes]: IntrinsicElementAttributes[K] & + ReservedProps +} + +interface BaseSyntheticEvent { + nativeEvent: E + currentTarget: C + target: T + bubbles: boolean + cancelable: boolean + defaultPrevented: boolean + eventPhase: number + isTrusted: boolean + preventDefault: () => void + isDefaultPrevented: () => boolean + stopPropagation: () => void + isPropagationStopped: () => boolean + persist: () => void + timeStamp: number + type: string +} + +/** + * currentTarget - a reference to the element on which the event listener is registered. + * + * target - a reference to the element from which the event was originally dispatched. + * This might be a child element to the element on which the event listener is registered. + * If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11508#issuecomment-256045682 + */ +interface SyntheticEvent + extends BaseSyntheticEvent {} + +type EventHandler> = { + bivarianceHack: (event: E) => void +}['bivarianceHack'] + +type BaseEventHandler = EventHandler> + +interface ClipboardEvent + extends SyntheticEvent { + clipboardData: DataTransfer +} +type ClipboardEventHandler = EventHandler> + +interface CompositionEvent + extends SyntheticEvent { + data: string +} +type CompositionEventHandler = EventHandler> + +interface DragEvent extends MouseEvent { + dataTransfer: DataTransfer +} +type DragEventHandler = EventHandler> + +interface FocusEvent + extends SyntheticEvent { + relatedTarget: (EventTarget & RelatedTarget) | null + target: EventTarget & Target +} +type FocusEventHandler = EventHandler> + +interface FormEvent extends SyntheticEvent {} +type FormEventHandler = EventHandler> + +interface ChangeEvent extends SyntheticEvent { + target: EventTarget & T +} +type ChangeEventHandler = EventHandler> + +interface KeyboardEvent + extends UIEvent { + altKey: boolean + /** @deprecated */ + charCode: number + ctrlKey: boolean + code: string + /** + * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. + */ + getModifierState: (key: ModifierKey) => boolean + /** + * See the [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#named-key-attribute-values). for possible values + */ + key: string + /** @deprecated */ + keyCode: number + locale: string + location: number + metaKey: boolean + repeat: boolean + shiftKey: boolean + /** @deprecated */ + which: number +} +type KeyboardEventHandler = EventHandler> + +export type ModifierKey = + | 'Alt' + | 'AltGraph' + | 'CapsLock' + | 'Control' + | 'Fn' + | 'FnLock' + | 'Hyper' + | 'Meta' + | 'NumLock' + | 'ScrollLock' + | 'Shift' + | 'Super' + | 'Symbol' + | 'SymbolLock' +interface MouseEvent + extends UIEvent { + altKey: boolean + button: number + buttons: number + clientX: number + clientY: number + ctrlKey: boolean + /** + * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. + */ + getModifierState: (key: ModifierKey) => boolean + metaKey: boolean + movementX: number + movementY: number + pageX: number + pageY: number + relatedTarget: EventTarget | null + screenX: number + screenY: number + shiftKey: boolean +} +type MouseEventHandler = EventHandler> + +interface AbstractView { + styleMedia: StyleMedia + document: Document +} +interface UIEvent + extends SyntheticEvent { + detail: number + view: AbstractView +} +type UIEventHandler = EventHandler> + +interface WheelEvent extends MouseEvent { + deltaMode: number + deltaX: number + deltaY: number + deltaZ: number +} +type WheelEventHandler = EventHandler> + +interface AnimationEvent + extends SyntheticEvent { + animationName: string + elapsedTime: number + pseudoElement: string +} +type AnimationEventHandler = EventHandler> + +interface TransitionEvent + extends SyntheticEvent { + elapsedTime: number + propertyName: string + pseudoElement: string +} +type TransitionEventHandler = EventHandler> diff --git a/packages/jsx/jsx-runtime/global.d.ts b/packages/jsx/jsx-runtime/global.d.ts new file mode 100644 index 000000000..8ae2ddd88 --- /dev/null +++ b/packages/jsx/jsx-runtime/global.d.ts @@ -0,0 +1,160 @@ +/* +React projects that don't include the DOM library need these interfaces to compile. +React Native applications use React, but there is no DOM available. The JavaScript runtime +is ES6/ES2015 only. These definitions allow such projects to compile with only `--lib ES6`. + +Warning: all of these interfaces are empty. If you want type definitions for various properties +(such as HTMLInputElement.prototype.value), you need to add `--lib DOM` (via command line or tsconfig.json). +*/ + +interface Event {} +interface AnimationEvent extends Event {} +interface ClipboardEvent extends Event {} +interface CompositionEvent extends Event {} +interface DragEvent extends Event {} +interface FocusEvent extends Event {} +interface KeyboardEvent extends Event {} +interface MouseEvent extends Event {} +interface TouchEvent extends Event {} +interface PointerEvent extends Event {} +interface ToggleEvent extends Event {} +interface TransitionEvent extends Event {} +interface UIEvent extends Event {} +interface WheelEvent extends Event {} + +interface EventTarget {} +interface Document {} +interface DataTransfer {} +interface StyleMedia {} + +interface Element {} +interface DocumentFragment {} + +interface HTMLElement extends Element {} +interface HTMLAnchorElement extends HTMLElement {} +interface HTMLAreaElement extends HTMLElement {} +interface HTMLAudioElement extends HTMLElement {} +interface HTMLBaseElement extends HTMLElement {} +interface HTMLBodyElement extends HTMLElement {} +interface HTMLBRElement extends HTMLElement {} +interface HTMLButtonElement extends HTMLElement {} +interface HTMLCanvasElement extends HTMLElement {} +interface HTMLDataElement extends HTMLElement {} +interface HTMLDataListElement extends HTMLElement {} +interface HTMLDetailsElement extends HTMLElement {} +interface HTMLDialogElement extends HTMLElement {} +interface HTMLDivElement extends HTMLElement {} +interface HTMLDListElement extends HTMLElement {} +interface HTMLEmbedElement extends HTMLElement {} +interface HTMLFieldSetElement extends HTMLElement {} +interface HTMLFormElement extends HTMLElement {} +interface HTMLHeadingElement extends HTMLElement {} +interface HTMLHeadElement extends HTMLElement {} +interface HTMLHRElement extends HTMLElement {} +interface HTMLHtmlElement extends HTMLElement {} +interface HTMLIFrameElement extends HTMLElement {} +interface HTMLImageElement extends HTMLElement {} +interface HTMLInputElement extends HTMLElement {} +interface HTMLModElement extends HTMLElement {} +interface HTMLLabelElement extends HTMLElement {} +interface HTMLLegendElement extends HTMLElement {} +interface HTMLLIElement extends HTMLElement {} +interface HTMLLinkElement extends HTMLElement {} +interface HTMLMapElement extends HTMLElement {} +interface HTMLMetaElement extends HTMLElement {} +interface HTMLMeterElement extends HTMLElement {} +interface HTMLObjectElement extends HTMLElement {} +interface HTMLOListElement extends HTMLElement {} +interface HTMLOptGroupElement extends HTMLElement {} +interface HTMLOptionElement extends HTMLElement {} +interface HTMLOutputElement extends HTMLElement {} +interface HTMLParagraphElement extends HTMLElement {} +interface HTMLParamElement extends HTMLElement {} +interface HTMLPreElement extends HTMLElement {} +interface HTMLProgressElement extends HTMLElement {} +interface HTMLQuoteElement extends HTMLElement {} +interface HTMLSlotElement extends HTMLElement {} +interface HTMLScriptElement extends HTMLElement {} +interface HTMLSelectElement extends HTMLElement {} +interface HTMLSourceElement extends HTMLElement {} +interface HTMLSpanElement extends HTMLElement {} +interface HTMLStyleElement extends HTMLElement {} +interface HTMLTableElement extends HTMLElement {} +interface HTMLTableColElement extends HTMLElement {} +interface HTMLTableDataCellElement extends HTMLElement {} +interface HTMLTableHeaderCellElement extends HTMLElement {} +interface HTMLTableRowElement extends HTMLElement {} +interface HTMLTableSectionElement extends HTMLElement {} +interface HTMLTemplateElement extends HTMLElement {} +interface HTMLTextAreaElement extends HTMLElement {} +interface HTMLTimeElement extends HTMLElement {} +interface HTMLTitleElement extends HTMLElement {} +interface HTMLTrackElement extends HTMLElement {} +interface HTMLUListElement extends HTMLElement {} +interface HTMLVideoElement extends HTMLElement {} +interface HTMLWebViewElement extends HTMLElement {} + +interface SVGElement extends Element {} +interface SVGSVGElement extends SVGElement {} +interface SVGCircleElement extends SVGElement {} +interface SVGClipPathElement extends SVGElement {} +interface SVGDefsElement extends SVGElement {} +interface SVGDescElement extends SVGElement {} +interface SVGEllipseElement extends SVGElement {} +interface SVGFEBlendElement extends SVGElement {} +interface SVGFEColorMatrixElement extends SVGElement {} +interface SVGFEComponentTransferElement extends SVGElement {} +interface SVGFECompositeElement extends SVGElement {} +interface SVGFEConvolveMatrixElement extends SVGElement {} +interface SVGFEDiffuseLightingElement extends SVGElement {} +interface SVGFEDisplacementMapElement extends SVGElement {} +interface SVGFEDistantLightElement extends SVGElement {} +interface SVGFEDropShadowElement extends SVGElement {} +interface SVGFEFloodElement extends SVGElement {} +interface SVGFEFuncAElement extends SVGElement {} +interface SVGFEFuncBElement extends SVGElement {} +interface SVGFEFuncGElement extends SVGElement {} +interface SVGFEFuncRElement extends SVGElement {} +interface SVGFEGaussianBlurElement extends SVGElement {} +interface SVGFEImageElement extends SVGElement {} +interface SVGFEMergeElement extends SVGElement {} +interface SVGFEMergeNodeElement extends SVGElement {} +interface SVGFEMorphologyElement extends SVGElement {} +interface SVGFEOffsetElement extends SVGElement {} +interface SVGFEPointLightElement extends SVGElement {} +interface SVGFESpecularLightingElement extends SVGElement {} +interface SVGFESpotLightElement extends SVGElement {} +interface SVGFETileElement extends SVGElement {} +interface SVGFETurbulenceElement extends SVGElement {} +interface SVGFilterElement extends SVGElement {} +interface SVGForeignObjectElement extends SVGElement {} +interface SVGGElement extends SVGElement {} +interface SVGImageElement extends SVGElement {} +interface SVGLineElement extends SVGElement {} +interface SVGLinearGradientElement extends SVGElement {} +interface SVGMarkerElement extends SVGElement {} +interface SVGMaskElement extends SVGElement {} +interface SVGMetadataElement extends SVGElement {} +interface SVGPathElement extends SVGElement {} +interface SVGPatternElement extends SVGElement {} +interface SVGPolygonElement extends SVGElement {} +interface SVGPolylineElement extends SVGElement {} +interface SVGRadialGradientElement extends SVGElement {} +interface SVGRectElement extends SVGElement {} +interface SVGSetElement extends SVGElement {} +interface SVGStopElement extends SVGElement {} +interface SVGSwitchElement extends SVGElement {} +interface SVGSymbolElement extends SVGElement {} +interface SVGTextElement extends SVGElement {} +interface SVGTextPathElement extends SVGElement {} +interface SVGTSpanElement extends SVGElement {} +interface SVGUseElement extends SVGElement {} +interface SVGViewElement extends SVGElement {} + +interface FormData {} +interface Text {} +interface TouchList {} +interface WebGLRenderingContext {} +interface WebGL2RenderingContext {} + +interface TrustedHTML {} diff --git a/packages/jsx/jsx-runtime/index.cjs b/packages/jsx/jsx-runtime/index.cjs new file mode 100644 index 000000000..73b137d52 --- /dev/null +++ b/packages/jsx/jsx-runtime/index.cjs @@ -0,0 +1,15 @@ +const { h, Fragment } = require('vue') + +function jsx(type, props, key) { + const { children } = props + delete props.children + if (arguments.length > 2) { + props.key = key + } + return h(type, props, children) +} + +exports.jsx = jsx +exports.jsxs = jsx +exports.jsxDEV = jsx +exports.Fragment = Fragment diff --git a/packages/jsx/jsx-runtime/index.d.ts b/packages/jsx/jsx-runtime/index.d.ts new file mode 100644 index 000000000..32b2e2968 --- /dev/null +++ b/packages/jsx/jsx-runtime/index.d.ts @@ -0,0 +1,25 @@ +import type { NativeElements } from './dom' + +export const Fragment: typeof import('vue').Fragment = {} +export const jsx: typeof import('vue').h = {} +export const jsxs: typeof import('vue').h = {} +export const jsxDEV: typeof import('vue').h = {} + +declare global { + declare namespace JSX { + interface Element extends import('vue').VNode {} + interface ElementClass { + $props: {} + } + interface ElementAttributesProperty { + $props: {} + } + interface IntrinsicElements extends NativeElements { + [name: string]: any + } + interface IntrinsicAttributes + extends import('vue').ReservedProps, + import('vue').AllowedComponentProps, + import('vue').ComponentCustomProps {} + } +} diff --git a/packages/jsx/jsx-runtime/index.js b/packages/jsx/jsx-runtime/index.js new file mode 100644 index 000000000..dd99a614f --- /dev/null +++ b/packages/jsx/jsx-runtime/index.js @@ -0,0 +1,12 @@ +import { Fragment, h } from 'vue' + +function jsx(type, props, key) { + const { children } = props + delete props.children + if (arguments.length > 2) { + props.key = key + } + return h(type, props, children) +} + +export { Fragment, jsx, jsx as jsxs, jsx as jsxDEV } diff --git a/packages/jsx/package.json b/packages/jsx/package.json index f629d597f..61c3e3ecf 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -25,7 +25,8 @@ }, "author": "三咲智子 ", "files": [ - "dist" + "dist", + "jsx-runtime" ], "main": "dist/index.cjs", "module": "dist/index.js", @@ -76,10 +77,18 @@ "require": "./dist/webpack.cjs", "import": "./dist/webpack.js" }, + "./jsx-runtime": { + "types": "./jsx-runtime/index.d.ts", + "require": "./jsx-runtime/index.cjs", + "import": "./jsx-runtime/index.js" + }, "./*": "./*" }, "typesVersions": { "*": { + "jsx-runtime": [ + "./jsx-runtime/index.d.ts" + ], "*": [ "./dist/*", "./*" @@ -125,6 +134,11 @@ "require": "./dist/webpack.cjs", "import": "./dist/webpack.js" }, + "./jsx-runtime": { + "types": "./jsx-runtime/index.d.ts", + "require": "./jsx-runtime/index.cjs", + "import": "./jsx-runtime/index.js" + }, "./*": "./*" } }, @@ -142,6 +156,7 @@ "unplugin-combine": "^1.0.3" }, "devDependencies": { + "csstype": "^3.1.3", "vue": "catalog:" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5de73b214..6c46e17f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -656,6 +656,9 @@ importers: specifier: ^1.0.3 version: 1.0.3(@rspack/core@1.1.1(@swc/helpers@0.5.15))(esbuild@0.24.0)(rolldown@0.14.0)(rollup@4.27.2)(vite@5.4.11(@types/node@22.9.0)(less@4.2.0)(terser@5.36.0))(webpack@5.96.1(esbuild@0.24.0)) devDependencies: + csstype: + specifier: ^3.1.3 + version: 3.1.3 vue: specifier: 'catalog:' version: 3.5.13(typescript@5.6.3) From 3bfdbae985810d67b16f7534d2cfe6692e69e457 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 23 Nov 2024 12:14:38 +0800 Subject: [PATCH 090/156] fix: mono --- packages/jsx/jsx-runtime/index.cjs | 15 ------- packages/jsx/jsx-runtime/index.d.ts | 25 ------------ packages/jsx/jsx-runtime/index.js | 12 ------ packages/jsx/package.json | 25 +++++------- packages/jsx/src/jsx-runtime.ts | 39 +++++++++++++++++++ packages/jsx/{ => src}/jsx-runtime/dom.ts | 0 .../jsx/{ => src}/jsx-runtime/global.d.ts | 9 +---- 7 files changed, 50 insertions(+), 75 deletions(-) delete mode 100644 packages/jsx/jsx-runtime/index.cjs delete mode 100644 packages/jsx/jsx-runtime/index.d.ts delete mode 100644 packages/jsx/jsx-runtime/index.js create mode 100644 packages/jsx/src/jsx-runtime.ts rename packages/jsx/{ => src}/jsx-runtime/dom.ts (100%) rename packages/jsx/{ => src}/jsx-runtime/global.d.ts (93%) diff --git a/packages/jsx/jsx-runtime/index.cjs b/packages/jsx/jsx-runtime/index.cjs deleted file mode 100644 index 73b137d52..000000000 --- a/packages/jsx/jsx-runtime/index.cjs +++ /dev/null @@ -1,15 +0,0 @@ -const { h, Fragment } = require('vue') - -function jsx(type, props, key) { - const { children } = props - delete props.children - if (arguments.length > 2) { - props.key = key - } - return h(type, props, children) -} - -exports.jsx = jsx -exports.jsxs = jsx -exports.jsxDEV = jsx -exports.Fragment = Fragment diff --git a/packages/jsx/jsx-runtime/index.d.ts b/packages/jsx/jsx-runtime/index.d.ts deleted file mode 100644 index 32b2e2968..000000000 --- a/packages/jsx/jsx-runtime/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { NativeElements } from './dom' - -export const Fragment: typeof import('vue').Fragment = {} -export const jsx: typeof import('vue').h = {} -export const jsxs: typeof import('vue').h = {} -export const jsxDEV: typeof import('vue').h = {} - -declare global { - declare namespace JSX { - interface Element extends import('vue').VNode {} - interface ElementClass { - $props: {} - } - interface ElementAttributesProperty { - $props: {} - } - interface IntrinsicElements extends NativeElements { - [name: string]: any - } - interface IntrinsicAttributes - extends import('vue').ReservedProps, - import('vue').AllowedComponentProps, - import('vue').ComponentCustomProps {} - } -} diff --git a/packages/jsx/jsx-runtime/index.js b/packages/jsx/jsx-runtime/index.js deleted file mode 100644 index dd99a614f..000000000 --- a/packages/jsx/jsx-runtime/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Fragment, h } from 'vue' - -function jsx(type, props, key) { - const { children } = props - delete props.children - if (arguments.length > 2) { - props.key = key - } - return h(type, props, children) -} - -export { Fragment, jsx, jsx as jsxs, jsx as jsxDEV } diff --git a/packages/jsx/package.json b/packages/jsx/package.json index 61c3e3ecf..14043a878 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -25,8 +25,7 @@ }, "author": "三咲智子 ", "files": [ - "dist", - "jsx-runtime" + "dist" ], "main": "dist/index.cjs", "module": "dist/index.js", @@ -42,6 +41,11 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, + "./jsx-runtime": { + "dev": "./src/jsx-runtime.ts", + "require": "./dist/jsx-runtime.cjs", + "import": "./dist/jsx-runtime.js" + }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.cjs", @@ -77,18 +81,10 @@ "require": "./dist/webpack.cjs", "import": "./dist/webpack.js" }, - "./jsx-runtime": { - "types": "./jsx-runtime/index.d.ts", - "require": "./jsx-runtime/index.cjs", - "import": "./jsx-runtime/index.js" - }, "./*": "./*" }, "typesVersions": { "*": { - "jsx-runtime": [ - "./jsx-runtime/index.d.ts" - ], "*": [ "./dist/*", "./*" @@ -106,6 +102,10 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, + "./jsx-runtime": { + "require": "./dist/jsx-runtime.cjs", + "import": "./dist/jsx-runtime.js" + }, "./rolldown": { "require": "./dist/rolldown.cjs", "import": "./dist/rolldown.js" @@ -134,11 +134,6 @@ "require": "./dist/webpack.cjs", "import": "./dist/webpack.js" }, - "./jsx-runtime": { - "types": "./jsx-runtime/index.d.ts", - "require": "./jsx-runtime/index.cjs", - "import": "./jsx-runtime/index.js" - }, "./*": "./*" } }, diff --git a/packages/jsx/src/jsx-runtime.ts b/packages/jsx/src/jsx-runtime.ts new file mode 100644 index 000000000..fda1753a9 --- /dev/null +++ b/packages/jsx/src/jsx-runtime.ts @@ -0,0 +1,39 @@ +import { Fragment, h } from 'vue' +import type { NativeElements } from './jsx-runtime/dom' + +function jsx(type: any, props: any, key: any): ReturnType { + const { children } = props + delete props.children + if (arguments.length > 2) { + props.key = key + } + return h(type, props, children) +} + +export { Fragment, jsx, jsx as jsxs, jsx as jsxDEV } + +type VNode = import('vue').VNode +type ReservedProps = import('vue').ReservedProps +type AllowedComponentProps = import('vue').AllowedComponentProps +type ComponentCustomProps = import('vue').ComponentCustomProps + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace JSX { + interface Element extends VNode {} + interface ElementClass { + $props: {} + } + interface ElementAttributesProperty { + $props: {} + } + interface IntrinsicElements extends NativeElements { + [name: string]: any + } + + interface IntrinsicAttributes + extends ReservedProps, + AllowedComponentProps, + ComponentCustomProps {} + } +} diff --git a/packages/jsx/jsx-runtime/dom.ts b/packages/jsx/src/jsx-runtime/dom.ts similarity index 100% rename from packages/jsx/jsx-runtime/dom.ts rename to packages/jsx/src/jsx-runtime/dom.ts diff --git a/packages/jsx/jsx-runtime/global.d.ts b/packages/jsx/src/jsx-runtime/global.d.ts similarity index 93% rename from packages/jsx/jsx-runtime/global.d.ts rename to packages/jsx/src/jsx-runtime/global.d.ts index 8ae2ddd88..9fa3ed42c 100644 --- a/packages/jsx/jsx-runtime/global.d.ts +++ b/packages/jsx/src/jsx-runtime/global.d.ts @@ -1,11 +1,4 @@ -/* -React projects that don't include the DOM library need these interfaces to compile. -React Native applications use React, but there is no DOM available. The JavaScript runtime -is ES6/ES2015 only. These definitions allow such projects to compile with only `--lib ES6`. - -Warning: all of these interfaces are empty. If you want type definitions for various properties -(such as HTMLInputElement.prototype.value), you need to add `--lib DOM` (via command line or tsconfig.json). -*/ +// Copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/global.d.ts interface Event {} interface AnimationEvent extends Event {} From 88f20e6941fd6f93771994776c69bbaffa3f5c47 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 23 Nov 2024 12:23:06 +0800 Subject: [PATCH 091/156] fix: cspell:check --- .vscode/settings.json | 3 ++- packages/jsx/src/jsx-runtime/dom.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 21a6f6f41..aee36b9c6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,8 @@ "unplugin", "vitest", "vmodel", - "vueuse" + "vueuse", + "jsxs" ], "eslint.options": { "flags": ["unstable_ts_config"] diff --git a/packages/jsx/src/jsx-runtime/dom.ts b/packages/jsx/src/jsx-runtime/dom.ts index dc4d2a764..21fa30c82 100644 --- a/packages/jsx/src/jsx-runtime/dom.ts +++ b/packages/jsx/src/jsx-runtime/dom.ts @@ -1,3 +1,4 @@ +/* cSpell:disable */ // Note: this file is auto concatenated to the end of the bundled d.ts during // build. From a11d8d641ebebc45a945b70bb3bdf7edfef3a6c1 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 23 Nov 2024 12:31:38 +0800 Subject: [PATCH 092/156] fix: cspell --- .vscode/settings.json | 12 ------------ cspell.json | 1 + 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index aee36b9c6..9dc3afe22 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,16 +1,4 @@ { - "cSpell.words": [ - "attributify", - "esbuild", - "sxzz", - "tsup", - "unocss", - "unplugin", - "vitest", - "vmodel", - "vueuse", - "jsxs" - ], "eslint.options": { "flags": ["unstable_ts_config"] }, diff --git a/cspell.json b/cspell.json index 4942fff36..96dc91464 100644 --- a/cspell.json +++ b/cspell.json @@ -30,6 +30,7 @@ "foobaz", "importx", "interface", + "jsxs", "monoman", "mousemove", "nolebase", From ccc71f9e1e218bdcfac901461d45760e3a963561 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 23 Nov 2024 15:33:21 +0800 Subject: [PATCH 093/156] feat: add jsx-macros --- packages/jsx/package.json | 1 + packages/jsx/src/index.ts | 4 ++++ pnpm-lock.yaml | 3 +++ 3 files changed, 8 insertions(+) diff --git a/packages/jsx/package.json b/packages/jsx/package.json index 14043a878..7a2b022e2 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -147,6 +147,7 @@ "dependencies": { "@vue-macros/config": "workspace:*", "@vue-macros/jsx-directive": "workspace:*", + "@vue-macros/jsx-macros": "workspace:*", "@vue-macros/volar": "workspace:*", "unplugin-combine": "^1.0.3" }, diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index 7d9049647..f61509ec9 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -1,5 +1,6 @@ import { resolveOptions, type Options } from '@vue-macros/config' import VueJsxDirective from '@vue-macros/jsx-directive' +import VueJsxMacros from '@vue-macros/jsx-macros' import { createCombinePlugin, @@ -22,6 +23,9 @@ const plugin: UnpluginCombineInstance = options.jsxDirective ? VueJsxDirective[framework](options.jsxDirective) : undefined, + options.jsxMacros + ? VueJsxMacros[framework](options.jsxMacros) + : undefined, ].filter((plugin) => !!plugin) return { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c46e17f9..85c5d04c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -649,6 +649,9 @@ importers: '@vue-macros/jsx-directive': specifier: workspace:* version: link:../jsx-directive + '@vue-macros/jsx-macros': + specifier: workspace:* + version: link:../jsx-macros '@vue-macros/volar': specifier: workspace:* version: link:../volar From 2f65a210dece5d67cccd79e188416012f07f1405 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 23 Nov 2024 15:36:03 +0800 Subject: [PATCH 094/156] feat: use slots instead of vSlots --- packages/volar/src/jsx-directive/context.ts | 4 ++-- packages/volar/src/jsx-macros/transform.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 1f11e4f95..43ac88ee6 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -43,10 +43,10 @@ declare function __VLS_getFunctionalComponentCtx( ? { expose: (exposed: (typeof __VLS_nativeElements)[S]) => any } : '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } - ? { slots: Ctx['props']['vSlots'] } & Ctx + ? Ctx : never : T extends (props: infer P, ctx: infer Ctx) => any - ? { props: P; slots: P['vSlots']; } & Ctx + ? { props: P; } & Ctx : {};\n`) } diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts index be49f20bf..e8a67bb16 100644 --- a/packages/volar/src/jsx-macros/transform.ts +++ b/packages/volar/src/jsx-macros/transform.ts @@ -32,6 +32,7 @@ export function transformJsxMacros( getStart(root.parameters, options), getStart(root.parameters, options), `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType},`, + `${HELPER_PREFIX}placeholder?: {},`, `${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, ) if (ts.isArrowFunction(root)) { @@ -59,7 +60,7 @@ export function transformJsxMacros( ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { - const defaultProps = [] + const props = [...(map.defineModel ?? [])] const elements = root.parameters[0] && !root.parameters[0].type && @@ -68,7 +69,7 @@ export function transformJsxMacros( : [] for (const element of elements) { if (ts.isIdentifier(element.name)) - defaultProps.push( + props.push( `${element.name.escapedText}${ element.initializer && ts.isNonNullExpression(element.initializer) @@ -87,9 +88,8 @@ export function transformJsxMacros( source, getStart(node, options), getStart(node.expression, options), - `return {\nprops: {} as `, - defaultProps.length ? `{ ${defaultProps.join(', ')} } & ` : '', - `{ vSlots?: ${map.defineSlots ?? '{}'}, ${map.defineModel?.join(', ') ?? ''} }`, + `return {\nprops: {} as { ${props.join(', ')} }`, + `,\nslots: {} as ${map.defineSlots ?? '{}'}`, `,\nexpose: (exposed: ${ options.lib === 'vue' ? `import('vue').ShallowUnwrapRef` From 9e7d673c968a875e69e06cf5474302f58d2dbc63 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 25 Nov 2024 17:05:28 +0800 Subject: [PATCH 095/156] feat: enabled jsxMacros by default --- packages/jsx/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index f61509ec9..ff8d70f63 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -15,6 +15,7 @@ export type JSXOptions = Pick const name = generatePluginName() const plugin: UnpluginCombineInstance = createCombinePlugin((userOptions = {}, meta) => { + userOptions.jsxMacros ??= true const options = resolveOptions(userOptions) const framework = meta.framework! From c6d0e4350b4a8853ab7807101e5330e5d449edf0 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 28 Nov 2024 19:45:18 +0800 Subject: [PATCH 096/156] chore: update --- packages/volar/src/jsx-macros/transform.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts index e8a67bb16..9da7d24dd 100644 --- a/packages/volar/src/jsx-macros/transform.ts +++ b/packages/volar/src/jsx-macros/transform.ts @@ -31,12 +31,20 @@ export function transformJsxMacros( source, getStart(root.parameters, options), getStart(root.parameters, options), + ts.isArrowFunction(root) && root.parameters.pos === root.pos ? '(' : '', `${HELPER_PREFIX}props: Awaited>['props'] & ${propsType},`, `${HELPER_PREFIX}placeholder?: {},`, `${HELPER_PREFIX}setup = (${asyncModifier ? 'async' : ''}(`, ) if (ts.isArrowFunction(root)) { - replaceSourceRange(codes, source, root.end, root.end, `)) => `, result) + replaceSourceRange( + codes, + source, + root.end, + root.end, + `))${root.pos === root.parameters.pos ? ')' : ''} => `, + result, + ) } else { replaceSourceRange( codes, From c2a120446b49593180d91352ec04b3cc2181d1b9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 28 Nov 2024 20:05:49 +0800 Subject: [PATCH 097/156] fix: lint --- packages/jsx-macros/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 054ac5402..64512f5e5 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -8,12 +8,12 @@ import { type BaseOptions, type MarkRequired, } from '@vue-macros/common' +import { generatePluginName } from '#macros' with { type: 'macro' } import { createUnplugin, type UnpluginContextMeta, type UnpluginInstance, } from 'unplugin' -import { generatePluginName } from '#macros' with { type: 'macro' } import { transformJsxMacros } from './core' import { helperPrefix, From 10bd2ac47953a792e69822243dd43c2cb655d07a Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 8 Dec 2024 22:56:45 +0800 Subject: [PATCH 098/156] feat: support react 19 --- .../src/core/define-expose/index.ts | 4 +- .../src/core/define-expose/react.ts | 62 ++++++++++++++----- packages/jsx-macros/src/core/index.ts | 17 ++++- .../tests/__snapshots__/fixtures.test.ts.snap | 59 +++++++++++++++++- packages/jsx-macros/tests/fixtures.test.ts | 36 ++++++++--- .../tests/fixtures/define-expose.tsx | 16 ++++- packages/volar/src/jsx-directive/context.ts | 4 +- 7 files changed, 163 insertions(+), 35 deletions(-) diff --git a/packages/jsx-macros/src/core/define-expose/index.ts b/packages/jsx-macros/src/core/define-expose/index.ts index 1a5655e0d..812bb85fa 100644 --- a/packages/jsx-macros/src/core/define-expose/index.ts +++ b/packages/jsx-macros/src/core/define-expose/index.ts @@ -9,13 +9,15 @@ export { transformReactDefineExpose } from './react' export function transformDefineExpose( node: CallExpression, + propsName: string, root: FunctionalNode, s: MagicStringAST, lib: string, + version: number, ): void { if (lib.includes('vue')) { transformVueDefineExpose(node, s, lib) } else if (lib.includes('react')) { - transformReactDefineExpose(node, root, s, lib) + transformReactDefineExpose(node, propsName, root, s, lib, version) } } diff --git a/packages/jsx-macros/src/core/define-expose/react.ts b/packages/jsx-macros/src/core/define-expose/react.ts index 6fe23a60a..ab2a57c66 100644 --- a/packages/jsx-macros/src/core/define-expose/react.ts +++ b/packages/jsx-macros/src/core/define-expose/react.ts @@ -9,31 +9,63 @@ import type { CallExpression, Node } from '@babel/types' export function transformReactDefineExpose( node: CallExpression, + propsName: string, root: FunctionalNode, s: MagicStringAST, lib: string, + version: number, ): void { - if (root.type === 'FunctionDeclaration' && root.id) { - s.prependLeft(root.start!, `const ${s.sliceNode(root.id)} = `) - } - s.appendLeft( - root.start!, - `${importHelperFn(s, 0, 'forwardRef', lib === 'preact' ? 'preact/compat' : lib)}(`, + const useImperativeHandle = importHelperFn( + s, + 0, + 'useImperativeHandle', + lib === 'preact' ? 'preact/hooks' : lib, ) + const isReact19 = lib === 'react' && version >= 19 + let refName = '' + if (isReact19) { + if (root.params[0]?.type === 'ObjectPattern') { + for (const prop of root.params[0].properties) { + if ( + prop.type === 'ObjectProperty' && + prop.key.type === 'Identifier' && + prop.key.name === 'ref' + ) { + refName = + prop.value.type === 'Identifier' ? prop.value.name : prop.key.name + break + } + } + } else { + refName = `${propsName}.ref` + } + } else { + const forwardRef = importHelperFn( + s, + 0, + 'forwardRef', + lib === 'preact' ? 'preact/compat' : lib, + ) + if (root.type === 'FunctionDeclaration' && root.id) { + s.appendLeft(root.start!, `const ${root.id.name} = `) + } + s.appendLeft(root.start!, `${forwardRef}(`) - const refName = root.params[1] - ? s.sliceNode(root.params[1]) - : `${HELPER_PREFIX}ref` - if (!root.params[0]) { - s.appendRight(getParamsStart(root, s.original), `, ${refName}`) - } else if (!root.params[1]) { - s.appendLeft(root.params[0].end!, `, ${refName}`) + refName = root.params[1] + ? s.sliceNode(root.params[1]) + : `${HELPER_PREFIX}ref` + if (!root.params[0]) { + s.appendRight(getParamsStart(root, s.original), `, ${refName}`) + } else if (!root.params[1]) { + s.appendLeft(root.params[0].end!, `, ${refName}`) + } + s.appendRight(root.end!, `)`) } s.overwrite( node.start!, node.arguments[0].start!, - `${importHelperFn(s, 0, 'useImperativeHandle', lib === 'preact' ? 'preact/hooks' : lib)}(${refName}, () =>(`, + `${useImperativeHandle}(${refName}, () =>(`, ) const result = new Set() walkIdentifiers( @@ -68,6 +100,4 @@ export function transformReactDefineExpose( node.arguments[0].end!, `), ${`[${result.size ? [...result] : ''}]`}`, ) - - s.appendRight(root.end!, `)`) } diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index e574a0b5d..0eee9b01d 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -65,7 +65,13 @@ export function transformJsxMacros( propsName = root.params[0].name } else if (root.params[0].type === 'ObjectPattern') { const lastProp = root.params[0].properties.at(-1) - if (lastProp?.type !== 'RestElement') { + if ( + !map.defineComponent && + lastProp?.type === 'RestElement' && + lastProp.argument.type === 'Identifier' + ) { + propsName = lastProp.argument.name + } else { s.appendRight( root.params[0].extra?.trailingComma ? (root.params[0].extra?.trailingComma as number) + 1 @@ -95,7 +101,14 @@ export function transformJsxMacros( transformDefineSlots(map.defineSlots, propsName, s, options.lib) } if (map.defineExpose) { - transformDefineExpose(map.defineExpose, root, s, options.lib) + transformDefineExpose( + map.defineExpose, + propsName, + root, + s, + options.lib, + options.version, + ) } } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 926343be1..a5afb9373 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -54,7 +54,21 @@ let __temp, __restore exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export default function (__MACROS_props) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export function Comp (__MACROS_props) { + __MACROS_useExpose(__MACROS_getCurrentInstance(), { + foo: 1, + }) + return
+} + +export const Comp1 = function(_props: any){ + __MACROS_useExpose(__MACROS_getCurrentInstance(), { + foo: 1, + }) + return
+} + +export const Comp2 = ({ref: _ref, ...__MACROS_props}: any)=>{ __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) @@ -128,8 +142,22 @@ export default __MACROS_defineComponent((__MACROS_props) => { exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { forwardRef as __MACROS_forwardRef } from "react"; -import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export default __MACROS_forwardRef(function (__MACROS_props, __MACROS_ref) { +import { useImperativeHandle as __MACROS_useImperativeHandle } from "react"; +import { forwardRef as __MACROS_forwardRef } from "react";export const Comp = __MACROS_forwardRef(function Comp (__MACROS_props, __MACROS_ref) { + __MACROS_useImperativeHandle(__MACROS_ref, () =>({ + foo: 1, + }), []) + return
+}) + +export const Comp1 = __MACROS_forwardRef(function(_props: any, __MACROS_ref){ + __MACROS_useImperativeHandle(__MACROS_ref, () =>({ + foo: 1, + }), []) + return
+}) + +export const Comp2 = __MACROS_forwardRef(({ref: _ref, ...__MACROS_props}: any, __MACROS_ref)=>{ __MACROS_useImperativeHandle(__MACROS_ref, () =>({ foo: 1, }), []) @@ -137,3 +165,28 @@ import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";expo }) " `; + +exports[`react19 fixtures > ./fixtures/define-expose.tsx 1`] = ` +" +import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export function Comp (__MACROS_props) { + __MACROS_useImperativeHandle(__MACROS_props.ref, () =>({ + foo: 1, + }), []) + return
+} + +export const Comp1 = function(_props: any){ + __MACROS_useImperativeHandle(_props.ref, () =>({ + foo: 1, + }), []) + return
+} + +export const Comp2 = ({ref: _ref, ...__MACROS_props}: any)=>{ + __MACROS_useImperativeHandle(_ref, () =>({ + foo: 1, + }), []) + return
+} +" +`; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index dd93d84e6..00a1276f6 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -2,6 +2,14 @@ import { testFixtures } from '@vue-macros/test-utils' import { describe } from 'vitest' import { transformJsxMacros } from '../src/core' +const options = { + defineModel: { alias: ['defineModel'] }, + defineSlots: { alias: ['defineSlots'] }, + defineStyle: { alias: ['defineStyle'] }, + defineExpose: { alias: ['defineExpose'] }, + defineComponent: { alias: ['defineComponent'] }, +} + describe('fixtures', async () => { await testFixtures( import.meta.glob('./fixtures/**/*.tsx', { @@ -13,11 +21,7 @@ describe('fixtures', async () => { lib: 'vue', include: ['*.tsx'], version: 3.5, - defineModel: { alias: ['defineModel'] }, - defineSlots: { alias: ['defineSlots'] }, - defineStyle: { alias: ['defineStyle'] }, - defineExpose: { alias: ['defineExpose'] }, - defineComponent: { alias: ['defineComponent'] }, + ...options, })?.code, ) }) @@ -33,11 +37,23 @@ describe('react fixtures', async () => { lib: 'react', include: ['*.tsx'], version: 18, - defineModel: { alias: ['defineModel'] }, - defineSlots: { alias: ['defineSlots'] }, - defineStyle: { alias: ['defineStyle'] }, - defineExpose: { alias: ['defineExpose'] }, - defineComponent: { alias: ['defineComponent'] }, + ...options, + })?.code, + ) +}) + +describe('react19 fixtures', async () => { + await testFixtures( + import.meta.glob('./fixtures/**/define-expose.tsx', { + eager: true, + as: 'raw', + }), + (args, id, code) => + transformJsxMacros(code, id, new Map(), { + lib: 'react', + include: ['*.tsx'], + version: 19, + ...options, })?.code, ) }) diff --git a/packages/jsx-macros/tests/fixtures/define-expose.tsx b/packages/jsx-macros/tests/fixtures/define-expose.tsx index 88c3978ba..962893de3 100644 --- a/packages/jsx-macros/tests/fixtures/define-expose.tsx +++ b/packages/jsx-macros/tests/fixtures/define-expose.tsx @@ -1,4 +1,18 @@ -export default function () { +export function Comp () { + defineExpose({ + foo: 1, + }) + return
+} + +export const Comp1 = function(_props: any){ + defineExpose({ + foo: 1, + }) + return
+} + +export const Comp2 = ({ref: _ref}: any)=>{ defineExpose({ foo: 1, }) diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 43ac88ee6..1f11e4f95 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -43,10 +43,10 @@ declare function __VLS_getFunctionalComponentCtx( ? { expose: (exposed: (typeof __VLS_nativeElements)[S]) => any } : '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } - ? Ctx + ? { slots: Ctx['props']['vSlots'] } & Ctx : never : T extends (props: infer P, ctx: infer Ctx) => any - ? { props: P; } & Ctx + ? { props: P; slots: P['vSlots']; } & Ctx : {};\n`) } From 85f56223358620a0f667ee5d1e96ca59b5adff96 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 9 Dec 2024 11:28:06 +0800 Subject: [PATCH 099/156] feat: support hmr --- packages/jsx-macros/src/core/common.ts | 52 +++++++++++++++++++ .../src/core/define-component/index.ts | 19 ++----- packages/jsx-macros/src/core/define-style.ts | 2 +- packages/jsx-macros/src/core/index.ts | 17 ++++-- .../tests/__snapshots__/fixtures.test.ts.snap | 12 ++--- packages/volar/src/jsx-macros/global-types.ts | 2 +- packages/volar/src/jsx-macros/index.ts | 10 ++-- .../vue3/src/examples/jsx-macros/index.tsx | 40 +++++++------- 8 files changed, 101 insertions(+), 53 deletions(-) create mode 100644 packages/jsx-macros/src/core/common.ts diff --git a/packages/jsx-macros/src/core/common.ts b/packages/jsx-macros/src/core/common.ts new file mode 100644 index 000000000..5c783a92d --- /dev/null +++ b/packages/jsx-macros/src/core/common.ts @@ -0,0 +1,52 @@ +import type { Program } from '@babel/types' +import type { MagicString } from 'vue/compiler-sfc' + +const importedMap = new WeakMap>() +export function importHelper({ + s, + ast, + local, + as = local, + isDefault, + from = 'vue', + offset = 0, +}: { + s: MagicString + ast: Program + local: string + as?: string + isDefault?: boolean + from?: string + offset?: number +}): string { + let hasBeenImported = false + ast.body.forEach((node) => { + if (node.type === 'ImportDeclaration' && node.source.value === from) { + for (const specifier of node.specifiers) { + if (specifier.local.name === as) { + hasBeenImported = true + break + } + } + } + }) + if (hasBeenImported) return as + + const imported = isDefault ? 'default' : local + const cacheKey = `${from}@${imported}` + if (!importedMap.get(s)?.has(cacheKey)) { + s.appendLeft( + offset, + `\nimport ${ + isDefault ? as : `{ ${imported}${as !== local ? ` as ${as}` : ''} }` + } from ${JSON.stringify(from)};`, + ) + if (!importedMap.has(s)) { + importedMap.set(s, new Set([cacheKey])) + } else { + importedMap.get(s)!.add(cacheKey) + } + } + + return as +} diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index b405cc7ec..87a35df18 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,30 +1,21 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' +import { importHelper } from '../common' import type { FunctionalNode, RootMapValue } from '..' -import type { OptionsResolved } from '../..' import { transformAwait } from './await' import { restructure } from './restructure' -import type { ObjectExpression } from '@babel/types' +import type { ObjectExpression, Program } from '@babel/types' export function transformDefineComponent( root: FunctionalNode, propsName: string, map: RootMapValue, s: MagicStringAST, - options: OptionsResolved, + ast: Program, + alias: string, ): void { if (!map.defineComponent) return - s.overwriteNode( - map.defineComponent.callee, - importHelperFn( - s, - 0, - `defineComponent`, - 'vue', - false, - options.defineComponent.alias[0], - ), - ) + importHelper({ s, ast, local: alias }) let hasRestProp = false const props: Record = {} diff --git a/packages/jsx-macros/src/core/define-style.ts b/packages/jsx-macros/src/core/define-style.ts index 37f863664..ab657b0e1 100644 --- a/packages/jsx-macros/src/core/define-style.ts +++ b/packages/jsx-macros/src/core/define-style.ts @@ -85,7 +85,7 @@ export function transformDefineStyle( s.appendLeft( 0, isDeclaration - ? `import style${index} from "${importId}"` + ? `import style${index} from "${importId}";` : `import "${importId}";`, ) s.overwriteNode(expression, isDeclaration ? `style${index}` : '') diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 0eee9b01d..ce1cef123 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -19,6 +19,7 @@ import type { FunctionDeclaration, FunctionExpression, Node, + Program, } from '@babel/types' export type FunctionalNode = @@ -50,7 +51,8 @@ export function transformJsxMacros( options: OptionsResolved, ): CodeTransform | undefined { const s = new MagicStringAST(code) - const rootMap = getRootMap(s, id, options) + const ast = babelParse(s.original, getLang(id)) + const rootMap = getRootMap(ast, s, options) for (const [root, map] of rootMap) { map.defineStyle?.forEach((defineStyle, index) => { @@ -90,7 +92,14 @@ export function transformJsxMacros( } if (map.defineComponent) { - transformDefineComponent(root, propsName, map, s, options) + transformDefineComponent( + root, + propsName, + map, + s, + ast, + options.defineComponent.alias[0], + ) } if (map.defineModel?.length) { map.defineModel.forEach(({ expression }) => { @@ -115,10 +124,10 @@ export function transformJsxMacros( return generateTransform(s, id) } -function getRootMap(s: MagicStringAST, id: string, options: OptionsResolved) { +function getRootMap(ast: Program, s: MagicStringAST, options: OptionsResolved) { const parents: (Node | undefined | null)[] = [] const rootMap = new Map() - walkAST(babelParse(s.original, getLang(id)), { + walkAST(ast, { enter(node, parent) { parents.unshift(parent) const root = diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index a5afb9373..e8acba509 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -2,13 +2,12 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " -import { defineComponent as __MACROS_defineComponent } from "vue"; import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { useAttrs as __MACROS_useAttrs } from "vue"; import { useModel as __MACROS_defineModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' -const Comp = __MACROS_defineComponent( +const Comp = defineComponent( (__MACROS_props) => { const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});const attrs = __MACROS_useAttrs(); const foo = __MACROS_defineModel(__MACROS_props, 'foo', { @@ -25,12 +24,12 @@ const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, }, required: false, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, ) -const Comp1 = __MACROS_defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { +const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { const foo = __MACROS_defineModel(props, 'foo') return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null } }) -const Comp2 = __MACROS_defineComponent(async (__MACROS_props) => { +const Comp2 = defineComponent(async (__MACROS_props) => { let __temp, __restore ;( @@ -114,8 +113,7 @@ export default function (__MACROS_props) { `; exports[`fixtures > ./fixtures/define-style.tsx 1`] = ` -"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=true&lang.css";import style0 from "/vue-macros/jsx-macros/define-style?index=0&scopeId=426a859d&scoped=false&lang.module.scss" -import { defineComponent as __MACROS_defineComponent } from "vue";import "/vue-macros/jsx-macros/define-style?index=0&scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' +"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=true&lang.css";import style0 from "/vue-macros/jsx-macros/define-style?index=0&scopeId=426a859d&scoped=false&lang.module.scss";import "/vue-macros/jsx-macros/define-style?index=0&scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' export const Comp = (__MACROS_props) => { const color = ref('red') @@ -123,7 +121,7 @@ export const Comp = (__MACROS_props) => { return
foo
} -export default __MACROS_defineComponent((__MACROS_props) => { +export default defineComponent((__MACROS_props) => { const color = ref('red') const styles = style0 return () => ( diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index 87415c36a..94eb1f74f 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -9,6 +9,6 @@ declare function ${options.defineSlots.alias[0]}>( declare function ${options.defineExpose.alias[0]} = Record>(exposed?: Exposed): Exposed; type __VLS_StyleArgs = [style: string, options?: { scoped?: boolean }]; declare const ${options.defineStyle.alias[0]}: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T }; -declare function ${HELPER_PREFIX}${options.defineComponent.alias[0]} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; +declare function ${HELPER_PREFIX}${options.defineComponent.alias[0]} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; ` } diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 72d5e0b7b..69b93fa74 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -109,11 +109,11 @@ function getMacro( return ( ts.isIdentifier(expression.expression) && [ - ...(options.defineModel.alias ?? ['defineModel']), - ...(options.defineSlots.alias ?? ['defineSlots']), - ...(options.defineStyle.alias ?? ['defineStyle']), - ...(options.defineExpose.alias ?? ['defineExpose']), - ...(options.defineComponent.alias ?? ['defineComponent']), + ...options.defineModel.alias, + ...options.defineSlots.alias, + ...options.defineStyle.alias, + ...options.defineExpose.alias, + ...options.defineComponent.alias, ].includes(expression.expression.escapedText!) && node ) diff --git a/playground/vue3/src/examples/jsx-macros/index.tsx b/playground/vue3/src/examples/jsx-macros/index.tsx index c92aaf16c..42e2e0c5e 100644 --- a/playground/vue3/src/examples/jsx-macros/index.tsx +++ b/playground/vue3/src/examples/jsx-macros/index.tsx @@ -3,26 +3,24 @@ import { useRef } from 'unplugin-vue-macros/runtime' import { ref } from 'vue' import { Comp } from './comp' -export default { - setup: () => { - const foo = ref('1') - const compRef = useRef() - expectTypeOf(compRef.value?.foo).toEqualTypeOf<1 | undefined>() +export default defineComponent(() => { + const foo = ref('1') + const compRef = useRef() + expectTypeOf(compRef.value?.foo).toEqualTypeOf<1 | undefined>() - return () => ( -
- (compRef.value = e)} - v-model_trim={foo.value} - foo={1} - v-slot={{ bar }} - > - {bar} - + return () => ( +
+ (compRef.value = e)} + v-model_trim={foo.value} + foo={1} + v-slot={{ bar }} + > + {bar} + - - {foo.value} -
- ) - }, -} + + {foo.value} +
+ ) +}) From 4b7bfa7506bb5cb1ed9b1d3c1a9134d20d18d316 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 9 Dec 2024 11:34:46 +0800 Subject: [PATCH 100/156] fix: lint --- .../tests/__snapshots__/fixtures.test.ts.snap | 18 +++++++++--------- .../tests/fixtures/define-expose.tsx | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index e8acba509..6fa7b57a3 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -53,21 +53,21 @@ let __temp, __restore exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export function Comp (__MACROS_props) { +import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export function Comp(__MACROS_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) return
} -export const Comp1 = function(_props: any){ +export const Comp1 = function (_props: any) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) return
} -export const Comp2 = ({ref: _ref, ...__MACROS_props}: any)=>{ +export const Comp2 = ({ ref: _ref, ...__MACROS_props }: any) => { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, }) @@ -141,21 +141,21 @@ export default defineComponent((__MACROS_props) => { exports[`react fixtures > ./fixtures/define-expose.tsx 1`] = ` " import { useImperativeHandle as __MACROS_useImperativeHandle } from "react"; -import { forwardRef as __MACROS_forwardRef } from "react";export const Comp = __MACROS_forwardRef(function Comp (__MACROS_props, __MACROS_ref) { +import { forwardRef as __MACROS_forwardRef } from "react";export const Comp = __MACROS_forwardRef(function Comp(__MACROS_props, __MACROS_ref) { __MACROS_useImperativeHandle(__MACROS_ref, () =>({ foo: 1, }), []) return
}) -export const Comp1 = __MACROS_forwardRef(function(_props: any, __MACROS_ref){ +export const Comp1 = __MACROS_forwardRef(function (_props: any, __MACROS_ref) { __MACROS_useImperativeHandle(__MACROS_ref, () =>({ foo: 1, }), []) return
}) -export const Comp2 = __MACROS_forwardRef(({ref: _ref, ...__MACROS_props}: any, __MACROS_ref)=>{ +export const Comp2 = __MACROS_forwardRef(({ ref: _ref, ...__MACROS_props }: any, __MACROS_ref) => { __MACROS_useImperativeHandle(__MACROS_ref, () =>({ foo: 1, }), []) @@ -166,21 +166,21 @@ export const Comp2 = __MACROS_forwardRef(({ref: _ref, ...__MACROS_props}: any, _ exports[`react19 fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export function Comp (__MACROS_props) { +import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";export function Comp(__MACROS_props) { __MACROS_useImperativeHandle(__MACROS_props.ref, () =>({ foo: 1, }), []) return
} -export const Comp1 = function(_props: any){ +export const Comp1 = function (_props: any) { __MACROS_useImperativeHandle(_props.ref, () =>({ foo: 1, }), []) return
} -export const Comp2 = ({ref: _ref, ...__MACROS_props}: any)=>{ +export const Comp2 = ({ ref: _ref, ...__MACROS_props }: any) => { __MACROS_useImperativeHandle(_ref, () =>({ foo: 1, }), []) diff --git a/packages/jsx-macros/tests/fixtures/define-expose.tsx b/packages/jsx-macros/tests/fixtures/define-expose.tsx index 962893de3..edaad350b 100644 --- a/packages/jsx-macros/tests/fixtures/define-expose.tsx +++ b/packages/jsx-macros/tests/fixtures/define-expose.tsx @@ -1,18 +1,18 @@ -export function Comp () { +export function Comp() { defineExpose({ foo: 1, }) return
} -export const Comp1 = function(_props: any){ +export const Comp1 = function (_props: any) { defineExpose({ foo: 1, }) return
} -export const Comp2 = ({ref: _ref}: any)=>{ +export const Comp2 = ({ ref: _ref }: any) => { defineExpose({ foo: 1, }) From 4507e198caab4e7b18c8bcf319cd7a5d5277b3fd Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 9 Dec 2024 11:53:35 +0800 Subject: [PATCH 101/156] fix: pnpm-lock --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15fdbe51c..700df46fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -659,7 +659,7 @@ importers: version: link:../volar unplugin-combine: specifier: ^1.0.3 - version: 1.0.3(@rspack/core@1.1.4(@swc/helpers@0.5.15))(esbuild@0.24.0)(rolldown@0.14.0)(rollup@4.27.4)(vite@6.0.0(@types/node@22.10.0)(jiti@2.4.0)(less@4.2.1)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))(webpack@5.96.1(esbuild@0.24.0)) + version: 1.0.3(@rspack/core@1.1.5(@swc/helpers@0.5.15))(esbuild@0.24.0)(rolldown@0.15.0(@babel/runtime@7.26.0))(rollup@4.28.1)(vite@6.0.2(@types/node@22.10.1)(jiti@2.4.1)(less@4.2.1)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))(webpack@5.97.1(esbuild@0.24.0)) devDependencies: csstype: specifier: ^3.1.3 From 852a606d41f22e0be255502aa947589a6b7e63db Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 14 Dec 2024 15:38:20 +0800 Subject: [PATCH 102/156] feat: support vue-sfc --- packages/jsx-macros/src/index.ts | 3 ++- packages/volar/src/jsx-macros/define-style.ts | 9 +++---- packages/volar/src/jsx-macros/global-types.ts | 7 +++--- packages/volar/src/jsx-macros/index.ts | 24 +++++++++++-------- packages/volar/src/jsx-macros/transform.ts | 7 +++--- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 64512f5e5..85cde5df5 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -4,6 +4,7 @@ import { FilterFileType, getFilterPattern, normalizePath, + REGEX_NODE_MODULES, REGEX_SETUP_SFC, type BaseOptions, type MarkRequired, @@ -55,7 +56,7 @@ function resolveOptions( const include = getFilterPattern([FilterFileType.SRC_FILE], framework) return { include, - exclude: [REGEX_SETUP_SFC], + exclude: [REGEX_SETUP_SFC, REGEX_NODE_MODULES], ...options, version, lib, diff --git a/packages/volar/src/jsx-macros/define-style.ts b/packages/volar/src/jsx-macros/define-style.ts index e0cfdeed0..33001ae68 100644 --- a/packages/volar/src/jsx-macros/define-style.ts +++ b/packages/volar/src/jsx-macros/define-style.ts @@ -1,3 +1,4 @@ +import { HELPER_PREFIX } from '@vue-macros/common' import { generateCssClassProperty } from '@vue/language-core/lib/codegen/script/template.js' import { parseCssClassNames } from '@vue/language-core/lib/utils/parseCssClassNames.js' import { replaceSourceRange } from 'muggle-string' @@ -22,13 +23,13 @@ export function transformDefineStyle( source, expression.arguments.pos - 1, expression.arguments.pos - 1, - '<{}', - ...getCssClassesType( + `<${HELPER_PREFIX}PrettifyLocal<{}`, + ...generateCssClassesType( getText(expression.arguments[0], options).slice(1, -1), getStart(expression.arguments[0], options) + 1, index, ), - '>', + '>>', ) } @@ -36,7 +37,7 @@ export function transformDefineStyle( }) } -function* getCssClassesType(css: string, offset: number, index: number) { +function* generateCssClassesType(css: string, offset: number, index: number) { for (const className of [...parseCssClassNames(css)]) { yield* generateCssClassProperty( index, diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index 94eb1f74f..ed3a51e2d 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -4,11 +4,12 @@ import type { TransformOptions } from '.' export function getGlobalTypes(options: TransformOptions): string { return ` const { defineModel${options.defineModel.alias[0] !== 'defineModel' ? `: ${options.defineModel.alias[0]}` : ''} } = await import('vue') +declare function ${HELPER_PREFIX}${options.defineComponent.alias[0]} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; declare function ${options.defineSlots.alias[0]}>(): Partial; declare function ${options.defineSlots.alias[0]}>(slots: T): T; declare function ${options.defineExpose.alias[0]} = Record>(exposed?: Exposed): Exposed; -type __VLS_StyleArgs = [style: string, options?: { scoped?: boolean }]; -declare const ${options.defineStyle.alias[0]}: { (...args: __VLS_StyleArgs): T; scss: (...args: __VLS_StyleArgs)=> T; sass: (...args: __VLS_StyleArgs)=> T; stylus: (...args: __VLS_StyleArgs)=> T; less: (...args: __VLS_StyleArgs)=> T; postcss: (...args: __VLS_StyleArgs)=> T }; -declare function ${HELPER_PREFIX}${options.defineComponent.alias[0]} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; +declare const ${options.defineStyle.alias[0]}: { (...args: ${HELPER_PREFIX}StyleArgs): T; scss: (...args: ${HELPER_PREFIX}StyleArgs)=> T; sass: (...args: ${HELPER_PREFIX}StyleArgs)=> T; stylus: (...args: ${HELPER_PREFIX}StyleArgs)=> T; less: (...args: ${HELPER_PREFIX}StyleArgs)=> T; postcss: (...args: ${HELPER_PREFIX}StyleArgs)=> T }; +type ${HELPER_PREFIX}StyleArgs = [style: string, options?: { scoped?: boolean }]; +type ${HELPER_PREFIX}PrettifyLocal = { [K in keyof T]: T[K]; } & {}; ` } diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 69b93fa74..5d14e4a41 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -47,7 +47,8 @@ export type JsxMacros = { export type RootMap = Map< | import('typescript').ArrowFunction | import('typescript').FunctionExpression - | import('typescript').FunctionDeclaration, + | import('typescript').FunctionDeclaration + | undefined, JsxMacros > @@ -141,7 +142,6 @@ export function getRootMap(options: TransformOptions): RootMap { ts.isFunctionDeclaration(parents[1])) ? parents[1] : undefined - if (!root) return if ( parents[2] && @@ -171,6 +171,15 @@ export function getRootMap(options: TransformOptions): RootMap { let isRequired = macro.isRequired if (!rootMap.has(root)) rootMap.set(root, {}) const macroName = getText(expression.expression, options) + if (macroName.startsWith('defineStyle')) { + ;(rootMap.get(root)!.defineStyle ??= [])!.push({ + expression, + isCssModules: !!ts.isVariableStatement(node), + }) + } + + if (!root) return + if (options.defineModel.alias.includes(macroName)) { const modelName = expression.arguments[0] && @@ -232,7 +241,7 @@ export function getRootMap(options: TransformOptions): RootMap { source, getStart(expression, options), getStart(expression, options), - `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots =`, + `// @ts-ignore\n${HELPER_PREFIX}slots;\nconst ${HELPER_PREFIX}slots = `, ) rootMap.get(root)!.defineSlots = `Partial` } else if (options.defineExpose.alias.includes(macroName)) { @@ -241,14 +250,9 @@ export function getRootMap(options: TransformOptions): RootMap { source, getStart(expression, options), getStart(expression, options), - `// @ts-ignore\n${HELPER_PREFIX}expose;\nconst ${HELPER_PREFIX}expose =`, + `// @ts-ignore\n${HELPER_PREFIX}exposed;\nconst ${HELPER_PREFIX}exposed = `, ) - rootMap.get(root)!.defineExpose = `typeof ${HELPER_PREFIX}expose` - } else if (macroName.startsWith('defineStyle')) { - ;(rootMap.get(root)!.defineStyle ??= [])!.push({ - expression, - isCssModules: !!ts.isVariableStatement(node), - }) + rootMap.get(root)!.defineExpose = `typeof ${HELPER_PREFIX}exposed` } } diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts index 9da7d24dd..b5b81299a 100644 --- a/packages/volar/src/jsx-macros/transform.ts +++ b/packages/volar/src/jsx-macros/transform.ts @@ -11,7 +11,10 @@ export function transformJsxMacros( const { ts, source, codes } = options for (const [root, map] of rootMap) { - if (!root.body) continue + transformDefineStyle(map.defineStyle, options) + + if (!root?.body) continue + const asyncModifier = root.modifiers?.find( (modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword, ) @@ -64,8 +67,6 @@ export function transformJsxMacros( ) } - transformDefineStyle(map.defineStyle, options) - ts.forEachChild(root.body, (node) => { if (ts.isReturnStatement(node) && node.expression) { const props = [...(map.defineModel ?? [])] From 30f3da21d22c34b0f51bc41a9f06464e4f0a300c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sat, 14 Dec 2024 17:04:23 +0800 Subject: [PATCH 103/156] fix: typecheck --- packages/jsx-macros/src/core/index.ts | 1 + packages/volar/src/jsx-directive/custom-directive.ts | 2 +- packages/volar/src/jsx-macros/index.ts | 1 + playground/vue3/src/examples/jsx-directive/v-on/child.vue | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index ce1cef123..76c5acedc 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -134,6 +134,7 @@ function getRootMap(ast: Program, s: MagicStringAST, options: OptionsResolved) { parents[1] && isFunctionalNode(parents[1]) ? parents[1] : undefined if ( + root && parents[2]?.type === 'CallExpression' && options.defineComponent.alias.includes(s.sliceNode(parents[2].callee)) ) { diff --git a/packages/volar/src/jsx-directive/custom-directive.ts b/packages/volar/src/jsx-directive/custom-directive.ts index 9a586839e..9941d1b10 100644 --- a/packages/volar/src/jsx-directive/custom-directive.ts +++ b/packages/volar/src/jsx-directive/custom-directive.ts @@ -41,7 +41,7 @@ function transform( if (directiveName.includes(':')) { ;[directiveName, arg] = directiveName.split(':') } - const start = attribute.getStart(ast) + const start = getStart(attribute, options) const offset = start + directiveName.length + 2 replaceSourceRange( codes, diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 5d14e4a41..cce7b3fac 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -144,6 +144,7 @@ export function getRootMap(options: TransformOptions): RootMap { : undefined if ( + root && parents[2] && ts.isCallExpression(parents[2]) && !parents[2].typeArguments && diff --git a/playground/vue3/src/examples/jsx-directive/v-on/child.vue b/playground/vue3/src/examples/jsx-directive/v-on/child.vue index 41d9c13b9..1ae8082c4 100644 --- a/playground/vue3/src/examples/jsx-directive/v-on/child.vue +++ b/playground/vue3/src/examples/jsx-directive/v-on/child.vue @@ -11,7 +11,7 @@ const emit = defineEmits<{ defineRender(() => (
emit('log', 1)}> - + )) From 2eb750c7613e1093a72b999f81023ea0b4896546 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 15 Dec 2024 14:29:19 +0800 Subject: [PATCH 104/156] feat: support reactivity-transform --- packages/jsx-macros/src/core/define-model.ts | 11 +------- packages/jsx-macros/src/core/index.ts | 16 +++++++----- .../tests/__snapshots__/fixtures.test.ts.snap | 25 +++++++++---------- .../tests/fixtures/define-component.tsx | 7 +++--- .../tests/fixtures/define-model.tsx | 8 +++--- packages/volar/src/jsx-macros/index.ts | 2 +- 6 files changed, 31 insertions(+), 38 deletions(-) diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index 3c5cef6e6..cbf5ce577 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -1,5 +1,4 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' -import type { OptionsResolved } from '..' import { useModelHelperId } from './helper' import type { CallExpression } from '@babel/types' @@ -7,18 +6,10 @@ export function transformDefineModel( node: CallExpression, propsName: string, s: MagicStringAST, - options: OptionsResolved, ): void { s.overwriteNode( node.callee, - importHelperFn( - s, - 0, - 'useModel', - useModelHelperId, - false, - options.defineModel.alias[0], - ), + importHelperFn(s, 0, 'useModel', useModelHelperId), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 76c5acedc..296cc1c8b 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -103,7 +103,7 @@ export function transformJsxMacros( } if (map.defineModel?.length) { map.defineModel.forEach(({ expression }) => { - transformDefineModel(expression, propsName, s, options) + transformDefineModel(expression, propsName, s) }) } if (map.defineSlots) { @@ -146,10 +146,14 @@ function getRootMap(ast: Program, s: MagicStringAST, options: OptionsResolved) { const expression = node.type === 'VariableDeclaration' - ? node.declarations[0].init + ? node.declarations[0].init?.type === 'CallExpression' && + s.sliceNode(node.declarations[0].init.callee) === '$' + ? node.declarations[0].init.arguments[0] + : node.declarations[0].init : node.type === 'ExpressionStatement' ? node.expression : undefined + if (!expression) return const macroExpression = getMacroExpression(expression, options) if (!macroExpression) return if (!rootMap.has(root)) rootMap.set(root, {}) @@ -162,7 +166,7 @@ function getRootMap(ast: Program, s: MagicStringAST, options: OptionsResolved) { if (options.defineModel.alias.includes(macroName)) { ;(rootMap.get(root)!.defineModel ??= []).push({ expression: macroExpression, - isRequired: expression?.type === 'TSNonNullExpression', + isRequired: expression.type === 'TSNonNullExpression', }) } else if (options.defineStyle.alias.includes(macroName)) { const lang = @@ -199,14 +203,14 @@ export function isFunctionalNode(node?: Node | null): node is FunctionalNode { } export function getMacroExpression( - node: Node | null | undefined, + node: Node, options: OptionsResolved, ): CallExpression | undefined { - if (node?.type === 'TSNonNullExpression') { + if (node.type === 'TSNonNullExpression') { node = node.expression } - if (node?.type === 'CallExpression') { + if (node.type === 'CallExpression') { if ( node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 6fa7b57a3..b39cf2ea4 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -4,28 +4,27 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { useAttrs as __MACROS_useAttrs } from "vue"; -import { useModel as __MACROS_defineModel } from "/vue-macros/jsx-macros/use-model"; +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' const Comp = defineComponent( (__MACROS_props) => { const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});const attrs = __MACROS_useAttrs(); - const foo = __MACROS_defineModel(__MACROS_props, 'foo', { + const foo = $(__MACROS_useModel(__MACROS_props, 'foo', { validator: (value) => { return value === 'foo' }, - required: false, type: String, - }) - return () =>
{[foo.value, __MACROS_default_props.bar, attrs.baz]}
+ })!) + return () =>
{[foo, __MACROS_default_props.bar, attrs.baz]}
}, - {props: { 'bar': { required: true }, 'foo': { validator: (value) => { + {props: { 'bar': { required: true }, 'foo': { required: true, validator: (value) => { return value === 'foo' - }, required: false, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, + }, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, ) const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { - const foo = __MACROS_defineModel(props, 'foo') + const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null } }) @@ -78,16 +77,16 @@ export const Comp2 = ({ ref: _ref, ...__MACROS_props }: any) => { exports[`fixtures > ./fixtures/define-model.tsx 1`] = ` " -import { useModel as __MACROS_defineModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { - const foo = __MACROS_defineModel(__MACROS_props, 'foo', { default: bar })! +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { + const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) return
{foo.value}
} export default function (__MACROS_props) { - const modelValue = __MACROS_defineModel(__MACROS_props, 'modelValue',)! + const modelValue = $(__MACROS_useModel(__MACROS_props, 'modelValue',)!) return ( - - {modelValue.value} + + {modelValue} ) } diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 527a37cd8..916b14eb5 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -2,14 +2,13 @@ import { defineComponent, nextTick } from 'vue' const Comp = defineComponent( ({ bar = 'bar'!, ...attrs }: { bar: 'bar'; baz: 'baz' }) => { - const foo = defineModel('foo', { + const foo = $(defineModel('foo', { validator: (value) => { return value === 'foo' }, - required: false, type: String, - }) - return () =>
{[foo.value, bar, attrs.baz]}
+ })!) + return () =>
{[foo, bar, attrs.baz]}
}, { name: 'Comp' }, ) diff --git a/packages/jsx-macros/tests/fixtures/define-model.tsx b/packages/jsx-macros/tests/fixtures/define-model.tsx index 0ef6a10c7..1767dccf8 100644 --- a/packages/jsx-macros/tests/fixtures/define-model.tsx +++ b/packages/jsx-macros/tests/fixtures/define-model.tsx @@ -1,13 +1,13 @@ export const Comp = ({ bar }: { bar: string }) => { - const foo = defineModel('foo', { default: bar })! + const foo = defineModel('foo', { default: bar }) return
{foo.value}
} export default function () { - const modelValue = defineModel()! + const modelValue = $(defineModel()!) return ( - - {modelValue.value} + + {modelValue} ) } diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index cce7b3fac..726dba52b 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -210,7 +210,7 @@ export function getRootMap(options: TransformOptions): RootMap { source, modelOptions.end - 1, modelOptions.end - 1, - `${expression.arguments.hasTrailingComma ? '' : ','} required: true`, + `${!modelOptions.properties.hasTrailingComma && modelOptions.properties.length ? ',' : ''} required: true`, ) } } else if (isRequired) { From 03b69b8da627d7d683c914db6f567aa0f4c6af48 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 15 Dec 2024 14:40:55 +0800 Subject: [PATCH 105/156] fix: format --- .../tests/__snapshots__/fixtures.test.ts.snap | 18 ++++++++++-------- .../tests/fixtures/define-component.tsx | 14 ++++++++------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index b39cf2ea4..86523eb84 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -10,17 +10,19 @@ import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { def const Comp = defineComponent( (__MACROS_props) => { const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});const attrs = __MACROS_useAttrs(); - const foo = $(__MACROS_useModel(__MACROS_props, 'foo', { - validator: (value) => { - return value === 'foo' - }, - type: String, - })!) + const foo = $( + __MACROS_useModel(__MACROS_props, 'foo', { + validator: (value) => { + return value === 'foo' + }, + type: String, + })!, + ) return () =>
{[foo, __MACROS_default_props.bar, attrs.baz]}
}, {props: { 'bar': { required: true }, 'foo': { required: true, validator: (value) => { - return value === 'foo' - }, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, + return value === 'foo' + }, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, ) const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 916b14eb5..56cd83670 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -2,12 +2,14 @@ import { defineComponent, nextTick } from 'vue' const Comp = defineComponent( ({ bar = 'bar'!, ...attrs }: { bar: 'bar'; baz: 'baz' }) => { - const foo = $(defineModel('foo', { - validator: (value) => { - return value === 'foo' - }, - type: String, - })!) + const foo = $( + defineModel('foo', { + validator: (value) => { + return value === 'foo' + }, + type: String, + })!, + ) return () =>
{[foo, bar, attrs.baz]}
}, { name: 'Comp' }, From 4e4fc9b8ea5a40e139e01fa2c69ef1b484ee66a5 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 15 Dec 2024 16:06:49 +0800 Subject: [PATCH 106/156] feat: support return JSX --- .../src/core/define-component/index.ts | 7 +++++-- .../src/core/define-component/return.ts | 21 +++++++++++++++++++ packages/jsx-macros/src/core/index.ts | 12 ++--------- .../tests/fixtures/define-component.tsx | 4 ++-- 4 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 packages/jsx-macros/src/core/define-component/return.ts diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 87a35df18..016a23595 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -2,8 +2,10 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' import { importHelper } from '../common' import type { FunctionalNode, RootMapValue } from '..' +import type { OptionsResolved } from '../..' import { transformAwait } from './await' import { restructure } from './restructure' +import { transformReturn } from './return' import type { ObjectExpression, Program } from '@babel/types' export function transformDefineComponent( @@ -12,10 +14,10 @@ export function transformDefineComponent( map: RootMapValue, s: MagicStringAST, ast: Program, - alias: string, + options: OptionsResolved, ): void { if (!map.defineComponent) return - importHelper({ s, ast, local: alias }) + importHelper({ s, ast, local: options.defineComponent.alias[0] }) let hasRestProp = false const props: Record = {} @@ -89,6 +91,7 @@ export function transformDefineComponent( } transformAwait(root, s) + transformReturn(root, s, options.lib) } function prependObjectExpression( diff --git a/packages/jsx-macros/src/core/define-component/return.ts b/packages/jsx-macros/src/core/define-component/return.ts new file mode 100644 index 000000000..2364930c0 --- /dev/null +++ b/packages/jsx-macros/src/core/define-component/return.ts @@ -0,0 +1,21 @@ +import { isFunctionalNode, type FunctionalNode } from '..' +import type { MagicStringAST } from '@vue-macros/common' + +export function transformReturn( + root: FunctionalNode, + s: MagicStringAST, + lib: string, +): void { + if (lib !== 'vue') return + + const node = + root.body.type === 'BlockStatement' + ? root.body.body.find((node) => node.type === 'ReturnStatement')?.argument + : root.body + if (!node || isFunctionalNode(node)) return + + s.appendRight( + node.extra?.parenthesized ? (node.extra.parenStart as number) : node.start!, + '() => ', + ) +} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 296cc1c8b..c8966be38 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -92,14 +92,7 @@ export function transformJsxMacros( } if (map.defineComponent) { - transformDefineComponent( - root, - propsName, - map, - s, - ast, - options.defineComponent.alias[0], - ) + transformDefineComponent(root, propsName, map, s, ast, options) } if (map.defineModel?.length) { map.defineModel.forEach(({ expression }) => { @@ -130,8 +123,7 @@ function getRootMap(ast: Program, s: MagicStringAST, options: OptionsResolved) { walkAST(ast, { enter(node, parent) { parents.unshift(parent) - const root = - parents[1] && isFunctionalNode(parents[1]) ? parents[1] : undefined + const root = isFunctionalNode(parents[1]) ? parents[1] : undefined if ( root && diff --git a/packages/jsx-macros/tests/fixtures/define-component.tsx b/packages/jsx-macros/tests/fixtures/define-component.tsx index 56cd83670..f80899a39 100644 --- a/packages/jsx-macros/tests/fixtures/define-component.tsx +++ b/packages/jsx-macros/tests/fixtures/define-component.tsx @@ -10,14 +10,14 @@ const Comp = defineComponent( type: String, })!, ) - return () =>
{[foo, bar, attrs.baz]}
+ return
{[foo, bar, attrs.baz]}
}, { name: 'Comp' }, ) const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { const foo = defineModel('foo') - return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
+ return
{[foo.value, props['bar'], props['onUpdate:bar']]}
}) const Comp2 = defineComponent(async () => { From eb40f80c135b1daf93b4652e534870dcd00e7b2d Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 16 Dec 2024 02:12:26 +0800 Subject: [PATCH 107/156] chore: add docs --- docs/.vitepress/config/theme.ts | 4 + docs/macros/index.md | 1 + docs/macros/jsx-macros.md | 316 +++++++++++++++++++ docs/vue-macros.config.ts | 1 + docs/zh-CN/macros/index.md | 1 + docs/zh-CN/macros/jsx-macros.md | 317 ++++++++++++++++++++ packages/volar/src/jsx-directive/context.ts | 4 +- packages/volar/src/jsx-directive/v-slot.ts | 2 +- 8 files changed, 643 insertions(+), 3 deletions(-) create mode 100644 docs/macros/jsx-macros.md create mode 100644 docs/zh-CN/macros/jsx-macros.md diff --git a/docs/.vitepress/config/theme.ts b/docs/.vitepress/config/theme.ts index d30e21d91..8bd66f5ef 100644 --- a/docs/.vitepress/config/theme.ts +++ b/docs/.vitepress/config/theme.ts @@ -181,6 +181,10 @@ export function getLocaleConfig(lang: string) { text: 'defineStyleX', link: `/define-stylex`, }, + { + text: 'jsxMacros', + link: `/jsx-macros`, + }, ], }, ], diff --git a/docs/macros/index.md b/docs/macros/index.md index 00a8f5066..a7187d8b6 100644 --- a/docs/macros/index.md +++ b/docs/macros/index.md @@ -26,3 +26,4 @@ Please make sure `unplugin-vue-macros` is set up correctly. If you haven't yet, - [setupSFC](./setup-sfc.md) - [chainCall](./chain-call.md) - [defineStyleX](./define-stylex.md) +- [jsxMacros](./jsx-macros.md) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md new file mode 100644 index 000000000..75da05a33 --- /dev/null +++ b/docs/macros/jsx-macros.md @@ -0,0 +1,316 @@ +# jsxMacros + + + +A collection of JSX macros. + +| Directive | vue3 / vapor | react / preact | Volar | +| :---------------: | :----------------: | :----------------: | :----------------: | +| `defineComponent` | :white_check_mark: | :x: | :white_check_mark: | +| `defineModel` | :white_check_mark: | :x: | :white_check_mark: | +| `defineSlots` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| `defineExpose` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| `defineStyle` | :white_check_mark: | :white_check_mark: | :white_check_mark: | + +## Options + +```ts +interface Options { + /** + * @default 'vue' + */ + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' +} +``` + +## defineComponent + +- Support directly returns JSX. +- Automatically collects used props to the props option. +- Support using `getCurrentInstance()` after an `await` expression. + +```vue twoslash + +``` + +::: details Compiled Code + +```tsx +import { getCurrentInstance, withAsyncContext } from 'vue' +defineComponent( + async (props) => { + let __temp, __restore + ;([__temp, __restore] = withAsyncContext(() => nextTick())), + await __temp, + __restore() + const i = getCurrentInstance() + return () => ( +
+ {props.foo} +
+ ) + }, + { props: { foo: null } }, +) +``` + +::: + +- The destructured props will be automatically restructured. +- If a rest prop is defined, it will be converted to `attrs`, and the `inheritAttrs` option will default to `false`. +- If the prop's default value ends with `!`, the prop will be inferred as required. + +```vue twoslash + +``` + +::: details Compiled Code + +```tsx +import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults' +defineComponent( + (_props) => { + const props = createPropsDefaultProxy(_props, { bar: '' }) + const attrs = useAttrs() + return () => ( +
+ {_props.foo} +
+ ) + }, + { props: { foo: null, bar: { required: true } }, inheritAttrs: false }, +) +``` + +::: + +## defineModel + +- Doesn't support hyphenated model names. +- Will be inferred as a required prop when the expression ends with `!`. +- The modified model's value can be read synchronously, without needing to `await nextTick()`. Related issue: https://github.com/vuejs/core/issues/11080 + +```vue twoslash + +``` + +::: details Compiled Code + +```tsx +import { ref } from 'vue' +import { useModel } from '/vue-macros/jsx-macros/use-model' + +function Comp(_props: { + modelValue: string + 'onUpdate:modelValue': (value: string) => any +}) { + const modelValue = useModel(_props, 'modelValue', { required: true }) + return
{modelValue.value}
+} +``` + +::: + +## defineExpose + +Just like in Vue SFC. + +```vue twoslash + +``` + +## defineSlots + +- If using generics to define slots, all slots will be optional. + +```tsx +const slots = defineSlots<{ + default: () => any +}>() + +slots.default?.() +// ^ optional +``` + +- Support default slots (Recommended). + +```vue twoslash + +``` + +## defineStyle + +```ts +declare function defineStyle( + style: string, + options?: { scoped?: boolean }, +): void +``` + +- Support defining multiple style macros in a file. +- Support CSS-variable and JS-variable binding. +- Support CSS pre-processors: `css`, `scss`, `sass`, `less`, `stylus`, `postcss`. + +```ts +defineStyle.scss(`...`) +defineStyle.stylus(`...`) +// ... +``` + +- Support scoped mode. + - If defined at the top level of the file, the scoped option is `false`. + - If defined within a function and not a `CSS module`, the scoped option defaults to `true`. + +```tsx +function Comp({ color = 'red' }) { + defineStyle.scss(` + .foo { + color: ${color}; + + :deep(.bar) { + color: blue; + } + } + `) + return +} + +defineStyle(` + .bar { + background: black; + } +`) +``` + +- Support `css modules`, if the macro is an assignment expression. + +```vue twoslash + +``` + +## Volar Configuration + +```json {5} [tsconfig.json] +{ + "vueCompilerOptions": { + "plugins": ["unplugin-vue-macros/volar"], + "vueMacros": { + "jsxMacros": true, + "scriptSFC": true + } + } +} +``` diff --git a/docs/vue-macros.config.ts b/docs/vue-macros.config.ts index cfec2aefc..1d4aa7e95 100644 --- a/docs/vue-macros.config.ts +++ b/docs/vue-macros.config.ts @@ -6,6 +6,7 @@ export default defineConfig({ defineProp: true, defineStyleX: true, exportRender: true, + jsxMacros: true, jsxRef: true, scriptLang: true, setupSFC: true, diff --git a/docs/zh-CN/macros/index.md b/docs/zh-CN/macros/index.md index 86c959d47..554bbe4dc 100644 --- a/docs/zh-CN/macros/index.md +++ b/docs/zh-CN/macros/index.md @@ -26,3 +26,4 @@ - [setupSFC](./setup-sfc.md) - [chainCall](./chain-call.md) - [defineStyleX](./define-stylex.md) +- [jsxMaros](./define-macros.md) diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md new file mode 100644 index 000000000..d79b6c69c --- /dev/null +++ b/docs/zh-CN/macros/jsx-macros.md @@ -0,0 +1,317 @@ +# jsxMacros + + + +JSX 的宏集合. + +| Directive | vue3 / vapor | react / preact | Volar | +| :---------------: | :----------------: | :----------------: | :----------------: | +| `defineComponent` | :white_check_mark: | :x: | :white_check_mark: | +| `defineModel` | :white_check_mark: | :x: | :white_check_mark: | +| `defineSlots` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| `defineExpose` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| `defineStyle` | :white_check_mark: | :white_check_mark: | :white_check_mark: | + +## 选项 + +```ts +interface Options { + /** + * @default 'vue' + */ + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' +} +``` + +## defineComponent + +- 支持直接返回 `JSX`. +- 自动收集使用过的 prop 到 defineComponent 的 props 选项中。 +- 支持在 `await` 表达式后使用 `getCurrentInstance()`。 + +```vue twoslash + +``` + +::: details 编译后代码 + +```tsx +import { getCurrentInstance, withAsyncContext } from 'vue' + +defineComponent( + async (props) => { + let __temp, __restore + ;([__temp, __restore] = withAsyncContext(() => nextTick())), + await __temp, + __restore() + const i = getCurrentInstance() + return () => ( +
+ {props.foo} +
+ ) + }, + { props: { foo: null } }, +) +``` + +::: + +- 解构的 props 将自动重构。 +- 如果定义了 rest prop,它将被转换为 `useAttrs()`,并且 `inheritAttrs` 选项默认为 `false`。 +- 如果 prop 的默认值以 `!` 结尾,该 prop 将被推断为必传的。 + +```vue twoslash + +``` + +::: details 编译后代码 + +```tsx +import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults' +defineComponent( + (_props) => { + const props = createPropsDefaultProxy(_props, { bar: '' }) + const attrs = useAttrs() + return () => ( +
+ {_props.foo} +
+ ) + }, + { props: { foo: null, bar: { required: true } }, inheritAttrs: false }, +) +``` + +::: + +## defineModel + +- 不支持使用连字符的 model 名称。 +- 当表达式以 `!` 结尾时,将被推断为必需的 model。 +- 修改后的 model 可以同步读取,无需 `await nextTick()`。相关问题:https://github.com/vuejs/core/issues/11080 + +```vue twoslash + +``` + +::: details 编译后代码 + +```tsx +import { ref } from 'vue' +import { useModel } from '/vue-macros/jsx-macros/use-model' + +function Comp(_props: { + modelValue: string + 'onUpdate:modelValue': (value: string) => any +}) { + const modelValue = useModel(_props, 'modelValue', { required: true }) + return
{modelValue.value}
+} +``` + +::: + +## defineExpose + +就像在 Vue SFC 中一样。 + +```vue twoslash + +``` + +## defineSlots + +- 如果使用泛型定义插槽,所有插槽将是可选的。 + +```tsx +const slots = defineSlots<{ + default: () => any +}>() + +slots.default?.() +// ^ optional +``` + +- 支持默认插槽(推荐)。 + +```vue twoslash + +``` + +## defineStyle + +```ts +declare function defineStyle( + style: string, + options?: { scoped?: boolean }, +): void +``` + +- 支持在一个文件中定义多个 style 宏。 +- 支持 CSS 变量和 JS 变量绑定。 +- 支持 CSS 预处理器:`css`、`scss`、`sass`、`less`、`stylus`、`postcss`。 + +```ts +defineStyle.scss(`...`) +defineStyle.stylus(`...`) +// ... +``` + +- 支持 scoped 模式。 + - 如果在文件的顶层定义,scoped 选项为 `false`。 + - 如果在函数内定义且不是 `CSS module`,scoped 选项默认为 `true`。 + +```tsx +function Comp({ color = 'red' }) { + defineStyle.scss(` + .foo { + color: ${color}; + + :deep(.bar) { + color: blue; + } + } + `) + return +} + +defineStyle(` + .bar { + background: black; + } +`) +``` + +- 支持 `css modules`, 如果宏是赋值表达式。 + +```vue twoslash + +``` + +## Volar Configuration + +```json {5} [tsconfig.json] +{ + "vueCompilerOptions": { + "plugins": ["unplugin-vue-macros/volar"], + "vueMacros": { + "jsxMacros": true, + "scriptSFC": true + } + } +} +``` diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 1f11e4f95..47b923c0c 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -43,10 +43,10 @@ declare function __VLS_getFunctionalComponentCtx( ? { expose: (exposed: (typeof __VLS_nativeElements)[S]) => any } : '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } - ? { slots: Ctx['props']['vSlots'] } & Ctx + ? Ctx : never : T extends (props: infer P, ctx: infer Ctx) => any - ? { props: P; slots: P['vSlots']; } & Ctx + ? { props: P } & Ctx : {};\n`) } diff --git a/packages/volar/src/jsx-directive/v-slot.ts b/packages/volar/src/jsx-directive/v-slot.ts index 27950ad4c..84726a2db 100644 --- a/packages/volar/src/jsx-directive/v-slot.ts +++ b/packages/volar/src/jsx-directive/v-slot.ts @@ -28,7 +28,7 @@ export function transformVSlot( const { codes, ts, ast, source, prefix } = options nodeMap.forEach(({ attributeMap, vSlotAttribute }, node) => { - const result: Code[] = [' vSlots={{'] + const result: Code[] = [' v-slots={{'] const attributes = Array.from(attributeMap) attributes.forEach( ([attribute, { children, vIfAttribute, vForAttribute }], index) => { From d8db31c0f0125fa01607325a73e6013d10365315 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 16 Dec 2024 02:17:51 +0800 Subject: [PATCH 108/156] fix: typo --- docs/zh-CN/macros/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh-CN/macros/index.md b/docs/zh-CN/macros/index.md index 554bbe4dc..f9d093146 100644 --- a/docs/zh-CN/macros/index.md +++ b/docs/zh-CN/macros/index.md @@ -26,4 +26,4 @@ - [setupSFC](./setup-sfc.md) - [chainCall](./chain-call.md) - [defineStyleX](./define-stylex.md) -- [jsxMaros](./define-macros.md) +- [jsxMaros](./jsx-macros.md) From da458a07e4004867bcc14f0a85b4834433c00c0c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 16 Dec 2024 09:13:48 +0800 Subject: [PATCH 109/156] fix: typo --- docs/macros/jsx-macros.md | 8 ++++---- docs/zh-CN/macros/jsx-macros.md | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md index 75da05a33..f4b2d15ae 100644 --- a/docs/macros/jsx-macros.md +++ b/docs/macros/jsx-macros.md @@ -26,8 +26,8 @@ interface Options { ## defineComponent - Support directly returns JSX. -- Automatically collects used props to the props option. - Support using `getCurrentInstance()` after an `await` expression. +- Automatically collects used props to the defineComponent's props option. ```vue twoslash ``` @@ -245,8 +245,8 @@ declare function defineStyle( ): void ``` -- Support defining multiple style macros in a file. - Support CSS-variable and JS-variable binding. +- Support defining multiple style macros in a file. - Support CSS pre-processors: `css`, `scss`, `sass`, `less`, `stylus`, `postcss`. ```ts diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md index d79b6c69c..5799c4208 100644 --- a/docs/zh-CN/macros/jsx-macros.md +++ b/docs/zh-CN/macros/jsx-macros.md @@ -26,7 +26,7 @@ interface Options { ## defineComponent - 支持直接返回 `JSX`. -- 自动收集使用过的 prop 到 defineComponent 的 props 选项中。 +- 自动收集使用过的 props 到 defineComponent 的 props 选项中。 - 支持在 `await` 表达式后使用 `getCurrentInstance()`。 ```vue twoslash @@ -83,8 +83,8 @@ defineComponent( ::: - 解构的 props 将自动重构。 -- 如果定义了 rest prop,它将被转换为 `useAttrs()`,并且 `inheritAttrs` 选项默认为 `false`。 - 如果 prop 的默认值以 `!` 结尾,该 prop 将被推断为必传的。 +- 如果定义了 rest prop,它将被转换为 `useAttrs()`,并且 `inheritAttrs` 选项默认为 `false`。 ```vue twoslash ``` @@ -246,8 +246,8 @@ declare function defineStyle( ): void ``` -- 支持在一个文件中定义多个 style 宏。 - 支持 CSS 变量和 JS 变量绑定。 +- 支持在一个文件中定义多个 style 宏。 - 支持 CSS 预处理器:`css`、`scss`、`sass`、`less`、`stylus`、`postcss`。 ```ts From f4ebeabbe336468a6b4e0641c6105f9126c6de48 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 16 Dec 2024 10:15:59 +0800 Subject: [PATCH 110/156] docs: add react --- docs/macros/jsx-macros.md | 142 +++++++++++++---- docs/zh-CN/macros/jsx-macros.md | 146 ++++++++++++++---- .../tests/__snapshots__/fixtures.test.ts.snap | 36 ++--- .../tests/fixtures/define-expose.tsx | 8 +- 4 files changed, 256 insertions(+), 76 deletions(-) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md index f4b2d15ae..e3b24271e 100644 --- a/docs/macros/jsx-macros.md +++ b/docs/macros/jsx-macros.md @@ -52,7 +52,7 @@ const Comp = defineComponent( export default () => ( - + ) @@ -105,6 +105,7 @@ export default () => foo={1} bar="bar" /> ::: details Compiled Code ```tsx +import { defineComponent } from 'vue' import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults' defineComponent( (_props) => { @@ -126,7 +127,7 @@ defineComponent( - Doesn't support hyphenated model names. - Will be inferred as a required prop when the expression ends with `!`. -- The modified model's value can be read synchronously, without needing to `await nextTick()`. Related issue: https://github.com/vuejs/core/issues/11080 +- The modified model's value can be read synchronously, without needing to `await nextTick()`. [Related issue](https://github.com/vuejs/core/issues/11080) ```vue twoslash -``` - ## defineSlots - If using generics to define slots, all slots will be optional. @@ -236,6 +213,119 @@ export default () => ( ``` +## defineExpose + +Just like in Vue SFC. + +```vue twoslash + +``` + +::: details Compiled Code + +::: code-group + +```tsx [vue] +import { getCurrentInstance, shallowRef as useRef } from 'vue' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = ({ foo }) => { + useExpose(getCurrentInstance(), { + foo, + }) + return
+} +``` + +```tsx [react] +/** + * vite.config.ts + * + * jsxMacros({ + * lib: 'react' + * }) + */ +import { forwardRef, useImperativeHandle } from 'react' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = forwardRef(({ foo }, _ref) => { + useImperativeHandle( + _ref, + () => ({ + foo, + }), + [foo], + ) + return
+}) +``` + +```tsx [react19] +/** + * vite.config.ts + * + * jsxMacros({ + * lib: 'react', + * version: 19 + * }) + */ +import { forwardRef, useImperativeHandle } from 'react' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = ({ foo, ..._props }) => { + useImperativeHandle( + _props.ref, + () => ({ + foo, + }), + [foo], + ) + return
+} +``` + +```tsx [preact] +/** + * vite.config.ts + * + * jsxMacros({ + * lib: 'preact' + * }) + */ +import { forwardRef } from 'preact/compat' +import { useImperativeHandle } from 'preact/hooks' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = forwardRef(({ foo }, _ref) => { + useImperativeHandle( + _ref, + () => ({ + foo, + }), + [foo], + ) + return
+}) +``` + +::: + ## defineStyle ```ts diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md index 5799c4208..6bb7edebc 100644 --- a/docs/zh-CN/macros/jsx-macros.md +++ b/docs/zh-CN/macros/jsx-macros.md @@ -26,8 +26,8 @@ interface Options { ## defineComponent - 支持直接返回 `JSX`. -- 自动收集使用过的 props 到 defineComponent 的 props 选项中。 - 支持在 `await` 表达式后使用 `getCurrentInstance()`。 +- 自动收集使用过的 props 到 defineComponent 的 props 选项中。 ```vue twoslash @@ -106,6 +106,7 @@ export default () => foo={1} bar="bar" /> ::: details 编译后代码 ```tsx +import { defineComponent } from 'vue' import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults' defineComponent( (_props) => { @@ -127,7 +128,7 @@ defineComponent( - 不支持使用连字符的 model 名称。 - 当表达式以 `!` 结尾时,将被推断为必需的 model。 -- 修改后的 model 可以同步读取,无需 `await nextTick()`。相关问题:https://github.com/vuejs/core/issues/11080 +- 修改后的 model 可以同步读取,无需 `await nextTick()`。[相关问题](https://github.com/vuejs/core/issues/11080) ```vue twoslash -``` - ## defineSlots - 如果使用泛型定义插槽,所有插槽将是可选的。 @@ -237,6 +214,119 @@ export default () => ( ``` +## defineExpose + +就像在 Vue SFC 中一样。 + +```vue twoslash + +``` + +::: details 编译后代码 + +::: code-group + +```tsx [vue] +import { getCurrentInstance, shallowRef as useRef } from 'vue' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = ({ foo }) => { + useExpose(getCurrentInstance(), { + foo, + }) + return
+} +``` + +```tsx [react] +/** + * vite.config.ts + * + * jsxMacros({ + * lib: 'react' + * }) + */ +import { forwardRef, useImperativeHandle } from 'react' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = forwardRef(({ foo }, _ref) => { + useImperativeHandle( + _ref, + () => ({ + foo, + }), + [foo], + ) + return
+}) +``` + +```tsx [react19] +/** + * vite.config.ts + * + * jsxMacros({ + * lib: 'react', + * version: 19 + * }) + */ +import { forwardRef, useImperativeHandle } from 'react' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = ({ foo, ..._props }) => { + useImperativeHandle( + _props.ref, + () => ({ + foo, + }), + [foo], + ) + return
+} +``` + +```tsx [preact] +/** + * vite.config.ts + * + * jsxMacros({ + * lib: 'preact' + * }) + */ +import { forwardRef } from 'preact/compat' +import { useImperativeHandle } from 'preact/hooks' +import { useExpose } from '/vue-macros/jsx-macros/use-expose' + +const Comp = forwardRef(({ foo }, _ref) => { + useImperativeHandle( + _ref, + () => ({ + foo, + }), + [foo], + ) + return
+}) +``` + +::: + ## defineStyle ```ts @@ -302,7 +392,7 @@ export default () => { ``` -## Volar Configuration +## Volar 配置 ```json {5} [tsconfig.json] { diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 86523eb84..fbad19d86 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -61,16 +61,16 @@ import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export f return
} -export const Comp1 = function (_props: any) { +export const Comp1 = function (props: any) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { - foo: 1, + foo: props.foo, }) return
} -export const Comp2 = ({ ref: _ref, ...__MACROS_props }: any) => { +export const Comp2 = ({ foo, ...__MACROS_props }: any) => { __MACROS_useExpose(__MACROS_getCurrentInstance(), { - foo: 1, + foo, }) return
} @@ -149,17 +149,17 @@ import { forwardRef as __MACROS_forwardRef } from "react";export const Comp = __ return
}) -export const Comp1 = __MACROS_forwardRef(function (_props: any, __MACROS_ref) { +export const Comp1 = __MACROS_forwardRef(function (props: any, __MACROS_ref) { __MACROS_useImperativeHandle(__MACROS_ref, () =>({ - foo: 1, - }), []) + foo: props.foo, + }), [props.foo]) return
}) -export const Comp2 = __MACROS_forwardRef(({ ref: _ref, ...__MACROS_props }: any, __MACROS_ref) => { +export const Comp2 = __MACROS_forwardRef(({ foo, ...__MACROS_props }: any, __MACROS_ref) => { __MACROS_useImperativeHandle(__MACROS_ref, () =>({ - foo: 1, - }), []) + foo, + }), [foo]) return
}) " @@ -174,17 +174,17 @@ import { useImperativeHandle as __MACROS_useImperativeHandle } from "react";expo return
} -export const Comp1 = function (_props: any) { - __MACROS_useImperativeHandle(_props.ref, () =>({ - foo: 1, - }), []) +export const Comp1 = function (props: any) { + __MACROS_useImperativeHandle(props.ref, () =>({ + foo: props.foo, + }), [props.foo]) return
} -export const Comp2 = ({ ref: _ref, ...__MACROS_props }: any) => { - __MACROS_useImperativeHandle(_ref, () =>({ - foo: 1, - }), []) +export const Comp2 = ({ foo, ...__MACROS_props }: any) => { + __MACROS_useImperativeHandle(, () =>({ + foo, + }), [foo]) return
} " diff --git a/packages/jsx-macros/tests/fixtures/define-expose.tsx b/packages/jsx-macros/tests/fixtures/define-expose.tsx index edaad350b..ad6a8d2b4 100644 --- a/packages/jsx-macros/tests/fixtures/define-expose.tsx +++ b/packages/jsx-macros/tests/fixtures/define-expose.tsx @@ -5,16 +5,16 @@ export function Comp() { return
} -export const Comp1 = function (_props: any) { +export const Comp1 = function (props: any) { defineExpose({ - foo: 1, + foo: props.foo, }) return
} -export const Comp2 = ({ ref: _ref }: any) => { +export const Comp2 = ({ foo }: any) => { defineExpose({ - foo: 1, + foo, }) return
} From f43f4579bad6f07017c25cadd438d2d87d4d87ac Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 9 Jan 2025 08:41:44 +0800 Subject: [PATCH 111/156] feat: prevent any --- packages/volar/src/jsx-macros/transform.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/volar/src/jsx-macros/transform.ts b/packages/volar/src/jsx-macros/transform.ts index b5b81299a..e40eb5021 100644 --- a/packages/volar/src/jsx-macros/transform.ts +++ b/packages/volar/src/jsx-macros/transform.ts @@ -20,9 +20,9 @@ export function transformJsxMacros( ) if (asyncModifier && map.defineComponent) replaceSourceRange(codes, source, asyncModifier.pos, asyncModifier.end) - const result = `({}) as Awaited>['render'] & { __ctx: Awaited>['render'], {}> & { __ctx: Awaited> }` From e2963208a584142215ee8e30189746d21aa209ee Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 24 Jan 2025 21:01:11 +0800 Subject: [PATCH 112/156] fix: mono --- packages/jsx-macros/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 0a2903650..daff83f62 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,7 +1,7 @@ { "name": "@vue-macros/jsx-macros", "version": "0.0.0", - "packageManager": "pnpm@9.15.0", + "packageManager": "pnpm@10.0.0", "description": "jsxMacros feature from Vue Macros.", "type": "module", "keywords": [ From 637bcf8edfce6dd0253baa6e04a5fd0fc71073ec Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 24 Jan 2025 21:03:03 +0800 Subject: [PATCH 113/156] fix: build --- pnpm-lock.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 264a7330b..06a7a8433 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,7 +88,7 @@ overrides: patchedDependencies: '@nolebase/ui': - hash: e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8 + hash: nxir2t733332i4ydsdrc3oikym path: patches/@nolebase__ui.patch importers: @@ -712,14 +712,14 @@ importers: version: 2.0.0 unplugin: specifier: 'catalog:' - version: 1.16.0 + version: 1.16.1 devDependencies: '@types/hash-sum': specifier: ^1.0.2 version: 1.0.2 vue: specifier: 'catalog:' - version: 3.5.13(typescript@5.6.3) + version: 3.5.13(typescript@5.7.3) packages/macros: dependencies: @@ -4403,6 +4403,9 @@ packages: resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==} engines: {node: '>=8'} + hash-sum@2.0.0: + resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} + hast-util-from-html@2.0.3: resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} @@ -7864,7 +7867,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.18.0 - '@nolebase/ui@2.12.0(patch_hash=e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0)': + '@nolebase/ui@2.12.0(patch_hash=nxir2t733332i4ydsdrc3oikym)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0)': dependencies: '@iconify-json/octicon': 1.2.2 less: 4.2.1 @@ -7942,7 +7945,7 @@ snapshots: dependencies: '@iconify-json/carbon': 1.2.5 '@iconify-json/icon-park-outline': 1.2.2 - '@nolebase/ui': 2.12.0(patch_hash=e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) + '@nolebase/ui': 2.12.0(patch_hash=nxir2t733332i4ydsdrc3oikym)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) less: 4.2.1 vitepress: 1.5.0(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(less@4.2.1)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) transitivePeerDependencies: @@ -7980,7 +7983,7 @@ snapshots: '@nolebase/vitepress-plugin-git-changelog@2.12.0(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0)': dependencies: '@iconify-json/octicon': 1.2.2 - '@nolebase/ui': 2.12.0(patch_hash=e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) + '@nolebase/ui': 2.12.0(patch_hash=nxir2t733332i4ydsdrc3oikym)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) colorette: 2.0.20 date-fns: 4.1.0 defu: 6.1.4 @@ -10750,6 +10753,8 @@ snapshots: has-own-prop@2.0.0: {} + hash-sum@2.0.0: {} + hast-util-from-html@2.0.3: dependencies: '@types/hast': 3.0.4 From 818a3cb3107903948ef30b4e81dcf1019d7923ad Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 24 Jan 2025 21:11:38 +0800 Subject: [PATCH 114/156] fix: build --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06a7a8433..d2188eacd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,7 +88,7 @@ overrides: patchedDependencies: '@nolebase/ui': - hash: nxir2t733332i4ydsdrc3oikym + hash: e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8 path: patches/@nolebase__ui.patch importers: @@ -7867,7 +7867,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.18.0 - '@nolebase/ui@2.12.0(patch_hash=nxir2t733332i4ydsdrc3oikym)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0)': + '@nolebase/ui@2.12.0(patch_hash=e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0)': dependencies: '@iconify-json/octicon': 1.2.2 less: 4.2.1 @@ -7945,7 +7945,7 @@ snapshots: dependencies: '@iconify-json/carbon': 1.2.5 '@iconify-json/icon-park-outline': 1.2.2 - '@nolebase/ui': 2.12.0(patch_hash=nxir2t733332i4ydsdrc3oikym)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) + '@nolebase/ui': 2.12.0(patch_hash=e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) less: 4.2.1 vitepress: 1.5.0(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(less@4.2.1)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) transitivePeerDependencies: @@ -7983,7 +7983,7 @@ snapshots: '@nolebase/vitepress-plugin-git-changelog@2.12.0(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0)': dependencies: '@iconify-json/octicon': 1.2.2 - '@nolebase/ui': 2.12.0(patch_hash=nxir2t733332i4ydsdrc3oikym)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) + '@nolebase/ui': 2.12.0(patch_hash=e70da0ab1831d8bee2c77d8e85de30d32941cd0b01b1cb9d20d3b5d9f2cfcfd8)(@algolia/client-search@5.19.0)(@types/node@22.10.7)(change-case@5.4.4)(jiti@2.4.2)(postcss@8.5.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0) colorette: 2.0.20 date-fns: 4.1.0 defu: 6.1.4 From 2b6cea248fdb199f4d10da51c7c926e232cd59b8 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 24 Jan 2025 23:06:21 +0800 Subject: [PATCH 115/156] feat: support modifiers for defineComponent --- packages/jsx-macros/src/core/define-component/index.ts | 1 + packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 016a23595..066561bd2 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -70,6 +70,7 @@ export function transformDefineComponent( .join(', ')} }` : null props[`onUpdate:${propName}`] = null + props[`${propName === 'modelValue' ? 'model' : propName}Modifiers`] = null } const propsString = Object.entries(props) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index fbad19d86..2839092ab 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -22,13 +22,13 @@ const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, }, {props: { 'bar': { required: true }, 'foo': { required: true, validator: (value) => { return value === 'foo' - }, type: String }, 'onUpdate:foo': null },inheritAttrs: false, name: 'Comp' }, + }, type: String }, 'onUpdate:foo': null, 'fooModifiers': null },inheritAttrs: false, name: 'Comp' }, ) const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { const foo = __MACROS_useModel(props, 'foo') return () =>
{[foo.value, props['bar'], props['onUpdate:bar']]}
-}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null } }) +}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null, 'fooModifiers': null } }) const Comp2 = defineComponent(async (__MACROS_props) => { let __temp, __restore From 4499ee4d8a9a0f287d1805a28e59a4e80646d8fe Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 26 Jan 2025 00:09:46 +0800 Subject: [PATCH 116/156] refactor: support browsers --- docs/macros/jsx-macros.md | 4 +- docs/zh-CN/macros/jsx-macros.md | 4 +- packages/jsx-macros/src/api.ts | 110 +++++++++++++++ .../src/core/define-component/index.ts | 2 +- packages/jsx-macros/src/core/define-style.ts | 4 +- packages/jsx-macros/src/core/index.ts | 7 +- packages/jsx-macros/src/core/style.ts | 4 +- packages/jsx-macros/src/index.ts | 125 +----------------- 8 files changed, 127 insertions(+), 133 deletions(-) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md index e3b24271e..ef2929d05 100644 --- a/docs/macros/jsx-macros.md +++ b/docs/macros/jsx-macros.md @@ -346,8 +346,8 @@ defineStyle.stylus(`...`) ``` - Support scoped mode. - - If defined at the top level of the file, the scoped option is `false`. - - If defined within a function and not a `CSS module`, the scoped option defaults to `true`. + - If defined at the top level of the file, the scoped option defaults to `false`. + - If defined within a function, the scoped option defaults to `true`. ```tsx function Comp({ color = 'red' }) { diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md index 6bb7edebc..2e5001136 100644 --- a/docs/zh-CN/macros/jsx-macros.md +++ b/docs/zh-CN/macros/jsx-macros.md @@ -347,8 +347,8 @@ defineStyle.stylus(`...`) ``` - 支持 scoped 模式。 - - 如果在文件的顶层定义,scoped 选项为 `false`。 - - 如果在函数内定义且不是 `CSS module`,scoped 选项默认为 `true`。 + - 如果在文件的顶层定义,scoped 选项默认为 `false`。 + - 如果在函数内定义,scoped 选项默认为 `true`。 ```tsx function Comp({ color = 'red' }) { diff --git a/packages/jsx-macros/src/api.ts b/packages/jsx-macros/src/api.ts index d06b255c6..46420bcd0 100644 --- a/packages/jsx-macros/src/api.ts +++ b/packages/jsx-macros/src/api.ts @@ -1,3 +1,113 @@ +import { + createFilter, + detectVueVersion, + FilterFileType, + getFilterPattern, + normalizePath, + REGEX_NODE_MODULES, + REGEX_SETUP_SFC, + type BaseOptions, + type MarkRequired, +} from '@vue-macros/common' +import { generatePluginName } from '#macros' with { type: 'macro' } +import { transformJsxMacros } from './core' +import { + helperPrefix, + useExposeHelperCode, + useExposeHelperId, + useModelHelperCode, + useModelHelperId, + withDefaultsCode, + withDefaultsHelperId, +} from './core/helper' +import { transformStyle } from './core/style' +import type { UnpluginContextMeta, UnpluginFactory } from 'unplugin' + export * from './core' export { restructure } from './core/define-component/restructure' export { createPropsDefaultProxy } from './core/helper/with-defaults' + +export type Options = BaseOptions & { + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + defineComponent?: { alias: string[] } + defineModel?: { alias: string[] } + defineExpose?: { alias: string[] } + defineSlots?: { alias: string[] } + defineStyle?: { alias: string[] } +} +export type OptionsResolved = MarkRequired< + Options, + | 'include' + | 'version' + | 'lib' + | 'defineComponent' + | 'defineModel' + | 'defineExpose' + | 'defineSlots' + | 'defineStyle' +> + +function resolveOptions( + options: Options, + framework: UnpluginContextMeta['framework'], +): OptionsResolved { + const version = options.version || detectVueVersion() + const lib = options.lib || 'vue' + const include = getFilterPattern([FilterFileType.SRC_FILE], framework) + return { + include, + exclude: [REGEX_SETUP_SFC, REGEX_NODE_MODULES], + ...options, + version, + lib, + defineComponent: { + alias: options?.defineComponent?.alias ?? ['defineComponent'], + }, + defineModel: { alias: options?.defineModel?.alias ?? ['defineModel'] }, + defineSlots: { alias: options?.defineSlots?.alias ?? ['defineSlots'] }, + defineExpose: { alias: options?.defineExpose?.alias ?? ['defineExpose'] }, + defineStyle: { alias: options?.defineStyle?.alias ?? ['defineStyle'] }, + } +} + +const name = generatePluginName() + +const unplugin: UnpluginFactory = ( + userOptions: Options = {}, + meta = { framework: 'vite' }, +) => { + const { framework } = meta + const options = resolveOptions(userOptions, framework) + const filter = createFilter(options) + const importMap = new Map() + + return { + name, + enforce: 'pre', + + resolveId(id) { + if (normalizePath(id).startsWith(helperPrefix)) return id + }, + loadInclude(id) { + return normalizePath(id).startsWith(helperPrefix) + }, + load(_id) { + const id = normalizePath(_id) + if (id === useExposeHelperId) return useExposeHelperCode + else if (id === useModelHelperId) return useModelHelperCode + else if (id === withDefaultsHelperId) return withDefaultsCode + else if (importMap.get(id)) return importMap.get(id) + }, + + transformInclude(id) { + if (importMap.get(id)) return true + return filter(id) + }, + transform(code, id) { + if (importMap.get(id)) return transformStyle(code, id, options) + return transformJsxMacros(code, id, importMap, options) + }, + } +} +// eslint-disable-next-line import/no-default-export +export default unplugin diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 066561bd2..857f124f2 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -2,7 +2,7 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { walkIdentifiers } from '@vue/compiler-core' import { importHelper } from '../common' import type { FunctionalNode, RootMapValue } from '..' -import type { OptionsResolved } from '../..' +import type { OptionsResolved } from '../../api' import { transformAwait } from './await' import { restructure } from './restructure' import { transformReturn } from './return' diff --git a/packages/jsx-macros/src/core/define-style.ts b/packages/jsx-macros/src/core/define-style.ts index ab657b0e1..16c2488ca 100644 --- a/packages/jsx-macros/src/core/define-style.ts +++ b/packages/jsx-macros/src/core/define-style.ts @@ -48,7 +48,7 @@ export function transformDefineStyle( } } - let scoped = isDeclaration ? false : !!root + let scoped = !!root if (expression.arguments[1]?.type === 'ObjectExpression') { for (const prop of expression.arguments[1].properties) { if ( @@ -80,7 +80,7 @@ export function transformDefineStyle( .slice(1, -1) .replaceAll(/\/\/(.*)(?=\n)/g, '/*$1*/') const module = isDeclaration ? 'module.' : '' - const importId = `${helperPrefix}/define-style?index=${index}&scopeId=${scopeId}&scoped=${scoped}&lang.${module}${lang}` + const importId = `${helperPrefix}/define-style/${index}?scopeId=${scopeId}&scoped=${scoped}&lang.${module}${lang}` importMap.set(importId, css) s.appendLeft( 0, diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index c8966be38..0db27bbe1 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -7,7 +7,7 @@ import { walkAST, type CodeTransform, } from '@vue-macros/common' -import type { OptionsResolved } from '..' +import type { OptionsResolved } from '../api' import { transformDefineComponent } from './define-component' import { transformDefineExpose } from './define-expose' import { transformDefineModel } from './define-model' @@ -54,9 +54,10 @@ export function transformJsxMacros( const ast = babelParse(s.original, getLang(id)) const rootMap = getRootMap(ast, s, options) + let defineStyleIndex = 0 for (const [root, map] of rootMap) { - map.defineStyle?.forEach((defineStyle, index) => { - transformDefineStyle(defineStyle, index, root, s, importMap) + map.defineStyle?.forEach((defineStyle) => { + transformDefineStyle(defineStyle, defineStyleIndex++, root, s, importMap) }) if (root === undefined) continue diff --git a/packages/jsx-macros/src/core/style.ts b/packages/jsx-macros/src/core/style.ts index f936f94b9..798624a16 100644 --- a/packages/jsx-macros/src/core/style.ts +++ b/packages/jsx-macros/src/core/style.ts @@ -1,12 +1,12 @@ import { compileStyleAsync } from 'vue/compiler-sfc' -import type { OptionsResolved } from '..' +import type { OptionsResolved } from '../api' export async function transformStyle( code: string, id: string, options: OptionsResolved, ): Promise { - const query = new URLSearchParams(id.split('?')[1]) as any + const query = new URLSearchParams(id.split('?')[1]) const result = await compileStyleAsync({ filename: id, id: `data-v-${query.get('scopeId')}`, diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 85cde5df5..046c8a81b 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -1,124 +1,7 @@ -import { - createFilter, - detectVueVersion, - FilterFileType, - getFilterPattern, - normalizePath, - REGEX_NODE_MODULES, - REGEX_SETUP_SFC, - type BaseOptions, - type MarkRequired, -} from '@vue-macros/common' -import { generatePluginName } from '#macros' with { type: 'macro' } -import { - createUnplugin, - type UnpluginContextMeta, - type UnpluginInstance, -} from 'unplugin' -import { transformJsxMacros } from './core' -import { - helperPrefix, - useExposeHelperCode, - useExposeHelperId, - useModelHelperCode, - useModelHelperId, - withDefaultsCode, - withDefaultsHelperId, -} from './core/helper' -import { transformStyle } from './core/style' +import { createUnplugin, type UnpluginInstance } from 'unplugin' +import unplugin, { type Options } from './api' -export type Options = BaseOptions & { - lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' - defineComponent?: { alias: string[] } - defineModel?: { alias: string[] } - defineExpose?: { alias: string[] } - defineSlots?: { alias: string[] } - defineStyle?: { alias: string[] } -} -export type OptionsResolved = MarkRequired< - Options, - | 'include' - | 'version' - | 'lib' - | 'defineComponent' - | 'defineModel' - | 'defineExpose' - | 'defineSlots' - | 'defineStyle' -> +export type { Options } -function resolveOptions( - options: Options, - framework: UnpluginContextMeta['framework'], -): OptionsResolved { - const version = options.version || detectVueVersion() - const lib = options.lib || 'vue' - const include = getFilterPattern([FilterFileType.SRC_FILE], framework) - return { - include, - exclude: [REGEX_SETUP_SFC, REGEX_NODE_MODULES], - ...options, - version, - lib, - defineComponent: { - alias: options?.defineComponent?.alias ?? ['defineComponent'], - }, - defineModel: { alias: options?.defineModel?.alias ?? ['defineModel'] }, - defineSlots: { alias: options?.defineSlots?.alias ?? ['defineSlots'] }, - defineExpose: { alias: options?.defineExpose?.alias ?? ['defineExpose'] }, - defineStyle: { alias: options?.defineStyle?.alias ?? ['defineStyle'] }, - } -} - -const name = generatePluginName() - -const plugin: UnpluginInstance = createUnplugin( - (userOptions = {}, { framework }) => { - const options = resolveOptions(userOptions, framework) - const filter = createFilter(options) - const importMap = new Map() - - return [ - { - name, - enforce: 'pre', - - resolveId(id) { - if (normalizePath(id).startsWith(helperPrefix)) return id - }, - loadInclude(id) { - return normalizePath(id).startsWith(helperPrefix) - }, - load(_id) { - const id = normalizePath(_id) - if (id === useExposeHelperId) return useExposeHelperCode - else if (id === useModelHelperId) return useModelHelperCode - else if (id === withDefaultsHelperId) return withDefaultsCode - }, - - transformInclude(id) { - if (importMap.get(id)) return - return filter(id) - }, - transform(code, id) { - return transformJsxMacros(code, id, importMap, options) - }, - }, - { - name: 'unplugin-define-style', - loadInclude(id) { - return normalizePath(id).startsWith(helperPrefix) - }, - load(_id) { - const id = normalizePath(_id) - if (importMap.get(id)) return importMap.get(id) - }, - transformInclude: (id) => importMap.get(id), - transform(code: string, id: string) { - return transformStyle(code, id, options) - }, - }, - ] - }, -) +const plugin: UnpluginInstance = createUnplugin(unplugin) export default plugin From abf00c1b763486c0ca88aa9a0a0636def5abecc0 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 26 Jan 2025 00:14:39 +0800 Subject: [PATCH 117/156] chore: update test --- .../tests/__snapshots__/fixtures.test.ts.snap | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 2839092ab..0b125e42a 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -114,7 +114,7 @@ export default function (__MACROS_props) { `; exports[`fixtures > ./fixtures/define-style.tsx 1`] = ` -"import "/vue-macros/jsx-macros/define-style?index=0&scopeId=4e9d5cd0&scoped=true&lang.css";import style0 from "/vue-macros/jsx-macros/define-style?index=0&scopeId=426a859d&scoped=false&lang.module.scss";import "/vue-macros/jsx-macros/define-style?index=0&scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' +"import "/vue-macros/jsx-macros/define-style/0?scopeId=4e9d5cd0&scoped=true&lang.css";import style1 from "/vue-macros/jsx-macros/define-style/1?scopeId=426a859d&scoped=true&lang.module.scss";import "/vue-macros/jsx-macros/define-style/2?scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' export const Comp = (__MACROS_props) => { const color = ref('red') @@ -124,12 +124,12 @@ export const Comp = (__MACROS_props) => { export default defineComponent((__MACROS_props) => { const color = ref('red') - const styles = style0 + const styles = style1 return () => ( <> -
foo
-
- bar +
foo
+
+ bar
) From 1026029a15e0afb414a03e0d72d71d908e2faf1b Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 2 Feb 2025 23:57:49 +0800 Subject: [PATCH 118/156] refactor: expose raw --- packages/jsx-macros/package.json | 15 +- packages/jsx-macros/src/api.ts | 112 --------- .../src/core/define-component/index.ts | 5 +- .../src/core/define-component/restructure.ts | 217 ------------------ .../jsx-macros/src/core/define-expose/vue.ts | 3 +- packages/jsx-macros/src/core/helper/index.ts | 6 - .../jsx-macros/src/core/helper/use-expose.ts | 5 +- .../src/core/helper/with-defaults.ts | 38 --- packages/jsx-macros/src/core/index.ts | 2 +- packages/jsx-macros/src/core/plugin.ts | 97 ++++++++ packages/jsx-macros/src/core/style.ts | 2 +- packages/jsx-macros/src/helpers.ts | 3 + packages/jsx-macros/src/index.ts | 8 +- .../tests/__snapshots__/fixtures.test.ts.snap | 4 +- .../__snapshots__/restructure.spec.ts.snap | 37 --- packages/jsx-macros/tests/restructure.spec.ts | 63 ----- pnpm-lock.yaml | 3 + 17 files changed, 133 insertions(+), 487 deletions(-) delete mode 100644 packages/jsx-macros/src/core/define-component/restructure.ts delete mode 100644 packages/jsx-macros/src/core/helper/with-defaults.ts create mode 100644 packages/jsx-macros/src/core/plugin.ts create mode 100644 packages/jsx-macros/src/helpers.ts delete mode 100644 packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap delete mode 100644 packages/jsx-macros/tests/restructure.spec.ts diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index daff83f62..914395d8c 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -24,7 +24,10 @@ "url": "git+https://github.com/vue-macros/vue-macros.git", "directory": "packages/jsx-macros" }, - "author": "三咲智子 ", + "author": "zhiyuanzmj", + "contributors": [ + "三咲智子 " + ], "files": [ "dist" ], @@ -47,6 +50,11 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, + "./helpers": { + "dev": "./src/helpers.ts", + "require": "./dist/helpers.cjs", + "import": "./dist/helpers.js" + }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.cjs", @@ -97,6 +105,10 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, + "./helpers": { + "require": "./dist/helpers.cjs", + "import": "./dist/helpers.js" + }, "./rolldown": { "require": "./dist/rolldown.cjs", "import": "./dist/rolldown.js" @@ -129,6 +141,7 @@ }, "dependencies": { "@vue-macros/common": "workspace:*", + "@vue-macros/jsx-directive": "workspace:*", "@vue/compiler-core": "catalog:", "hash-sum": "^2.0.0", "unplugin": "catalog:" diff --git a/packages/jsx-macros/src/api.ts b/packages/jsx-macros/src/api.ts index 46420bcd0..46d458ad7 100644 --- a/packages/jsx-macros/src/api.ts +++ b/packages/jsx-macros/src/api.ts @@ -1,113 +1 @@ -import { - createFilter, - detectVueVersion, - FilterFileType, - getFilterPattern, - normalizePath, - REGEX_NODE_MODULES, - REGEX_SETUP_SFC, - type BaseOptions, - type MarkRequired, -} from '@vue-macros/common' -import { generatePluginName } from '#macros' with { type: 'macro' } -import { transformJsxMacros } from './core' -import { - helperPrefix, - useExposeHelperCode, - useExposeHelperId, - useModelHelperCode, - useModelHelperId, - withDefaultsCode, - withDefaultsHelperId, -} from './core/helper' -import { transformStyle } from './core/style' -import type { UnpluginContextMeta, UnpluginFactory } from 'unplugin' - export * from './core' -export { restructure } from './core/define-component/restructure' -export { createPropsDefaultProxy } from './core/helper/with-defaults' - -export type Options = BaseOptions & { - lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' - defineComponent?: { alias: string[] } - defineModel?: { alias: string[] } - defineExpose?: { alias: string[] } - defineSlots?: { alias: string[] } - defineStyle?: { alias: string[] } -} -export type OptionsResolved = MarkRequired< - Options, - | 'include' - | 'version' - | 'lib' - | 'defineComponent' - | 'defineModel' - | 'defineExpose' - | 'defineSlots' - | 'defineStyle' -> - -function resolveOptions( - options: Options, - framework: UnpluginContextMeta['framework'], -): OptionsResolved { - const version = options.version || detectVueVersion() - const lib = options.lib || 'vue' - const include = getFilterPattern([FilterFileType.SRC_FILE], framework) - return { - include, - exclude: [REGEX_SETUP_SFC, REGEX_NODE_MODULES], - ...options, - version, - lib, - defineComponent: { - alias: options?.defineComponent?.alias ?? ['defineComponent'], - }, - defineModel: { alias: options?.defineModel?.alias ?? ['defineModel'] }, - defineSlots: { alias: options?.defineSlots?.alias ?? ['defineSlots'] }, - defineExpose: { alias: options?.defineExpose?.alias ?? ['defineExpose'] }, - defineStyle: { alias: options?.defineStyle?.alias ?? ['defineStyle'] }, - } -} - -const name = generatePluginName() - -const unplugin: UnpluginFactory = ( - userOptions: Options = {}, - meta = { framework: 'vite' }, -) => { - const { framework } = meta - const options = resolveOptions(userOptions, framework) - const filter = createFilter(options) - const importMap = new Map() - - return { - name, - enforce: 'pre', - - resolveId(id) { - if (normalizePath(id).startsWith(helperPrefix)) return id - }, - loadInclude(id) { - return normalizePath(id).startsWith(helperPrefix) - }, - load(_id) { - const id = normalizePath(_id) - if (id === useExposeHelperId) return useExposeHelperCode - else if (id === useModelHelperId) return useModelHelperCode - else if (id === withDefaultsHelperId) return withDefaultsCode - else if (importMap.get(id)) return importMap.get(id) - }, - - transformInclude(id) { - if (importMap.get(id)) return true - return filter(id) - }, - transform(code, id) { - if (importMap.get(id)) return transformStyle(code, id, options) - return transformJsxMacros(code, id, importMap, options) - }, - } -} -// eslint-disable-next-line import/no-default-export -export default unplugin diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 857f124f2..0adfa172d 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,10 +1,10 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' +import { restructure } from '@vue-macros/jsx-directive/api' import { walkIdentifiers } from '@vue/compiler-core' import { importHelper } from '../common' import type { FunctionalNode, RootMapValue } from '..' -import type { OptionsResolved } from '../../api' +import type { OptionsResolved } from '../..' import { transformAwait } from './await' -import { restructure } from './restructure' import { transformReturn } from './return' import type { ObjectExpression, Program } from '@babel/types' @@ -26,6 +26,7 @@ export function transformDefineComponent( getWalkedIds(root, propsName).forEach((id) => (props[id] = null)) } else { const restructuredProps = restructure(s, root, { + withDefaultsFrom: '@vue-macros/jsx-macros/helpers', generateRestProps: (restPropsName, index, list) => { if (index === list.length - 1) { hasRestProp = true diff --git a/packages/jsx-macros/src/core/define-component/restructure.ts b/packages/jsx-macros/src/core/define-component/restructure.ts deleted file mode 100644 index 2b0cc6eae..000000000 --- a/packages/jsx-macros/src/core/define-component/restructure.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { - HELPER_PREFIX, - importHelperFn, - type MagicString, -} from '@vue-macros/common' -import { walkIdentifiers } from '@vue/compiler-core' -import { withDefaultsHelperId } from '../helper' -import type { FunctionalNode } from '..' -import type { Node } from '@babel/types' - -type Prop = { - path: string - name: string - value: string - defaultValue?: string - isRest?: boolean - isRequired?: boolean -} - -export function restructure( - s: MagicString, - node: FunctionalNode, - options?: { - withDefaultsFrom?: string - generateRestProps?: ( - restPropsName: string, - index: number, - list: Prop[], - ) => string | undefined - }, -): Prop[] { - let index = 0 - const propList: Prop[] = [] - for (const param of node.params) { - const path = `${HELPER_PREFIX}props${index++ || ''}` - const props = getProps(param, path, s) - if (props) { - const hasDefaultValue = props.some((i) => i.defaultValue) - s.overwrite(param.start!, param.end!, path) - propList.push( - ...(hasDefaultValue - ? props.map((i) => ({ - ...i, - path: i.path.replace(HELPER_PREFIX, `${HELPER_PREFIX}default_`), - })) - : props), - ) - } - } - - if (propList.length) { - const defaultValues: Record = {} - const rests = [] - for (const prop of propList) { - if (prop.defaultValue) { - const basePath = prop.path.split(/\.|\[/)[0] - ;(defaultValues[basePath] ??= []).push(prop) - } - if (prop.isRest) { - rests.push(prop) - } - } - for (const [path, values] of Object.entries(defaultValues)) { - const createPropsDefaultProxy = importHelperFn( - s, - 0, - 'createPropsDefaultProxy', - options?.withDefaultsFrom || withDefaultsHelperId, - ) - const resolvedPath = path.replace( - `${HELPER_PREFIX}default_`, - HELPER_PREFIX, - ) - const resolvedValues = values - .map( - (i) => `'${i.path.replace(path, '')}${i.value}': ${i.defaultValue}`, - ) - .join(', ') - prependFunctionalNode( - node, - s, - `\nconst ${path} = ${createPropsDefaultProxy}(${resolvedPath}, {${resolvedValues}})`, - ) - } - - for (const [index, rest] of rests.entries()) { - prependFunctionalNode( - node, - s, - options?.generateRestProps?.(rest.name, index, rests) ?? - `\nconst ${rest.name} = ${importHelperFn( - s, - 0, - 'createPropsRestProxy', - 'vue', - )}(${rest.path}, [${rest.value}])`, - ) - } - - walkIdentifiers( - node.body, - (id, parent) => { - const prop = propList.find((i) => i.name === id.name) - if (prop && !prop.isRest) { - s.overwrite( - id.start!, - id.end!, - `${ - parent?.type === 'ObjectProperty' && parent.shorthand - ? `${id.name}: ` - : '' - }${prop.path}${prop.value}`, - ) - } - }, - false, - ) - } - - return propList -} - -function getProps( - node: Node, - path: string = '', - s: MagicString, - props: Prop[] = [], -) { - const properties = - node.type === 'ObjectPattern' - ? node.properties - : node.type === 'ArrayPattern' - ? node.elements - : [] - if (!properties.length) return - - const propNames: string[] = [] - properties.forEach((prop, index) => { - if (prop?.type === 'Identifier') { - // { foo } - props.push({ name: prop.name, path, value: `[${index}]` }) - propNames.push(`'${prop.name}'`) - } else if ( - prop?.type === 'AssignmentPattern' && - prop.left.type === 'Identifier' - ) { - // [foo = 'foo'] - props.push({ - path, - name: prop.left.name, - value: `.${prop.left.name}`, - defaultValue: s.slice(prop.right.start!, prop.right.end!), - }) - propNames.push(`'${prop.left.name}'`) - } else if ( - prop?.type === 'ObjectProperty' && - prop.key.type === 'Identifier' - ) { - if ( - prop.value.type === 'AssignmentPattern' && - prop.value.left.type === 'Identifier' - ) { - // { foo: bar = 'foo' } - props.push({ - path, - name: prop.value.left.name, - value: `.${prop.key.name}`, - defaultValue: s.slice(prop.value.right.start!, prop.value.right.end!), - isRequired: prop.value.right.type === 'TSNonNullExpression', - }) - } else if (!getProps(prop.value, `${path}.${prop.key.name}`, s, props)) { - // { foo: bar } - props.push({ - path, - name: - prop.value.type === 'Identifier' ? prop.value.name : prop.key.name, - value: `.${prop.key.name}`, - }) - } - propNames.push(`'${prop.key.name}'`) - } else if ( - prop?.type === 'RestElement' && - prop.argument.type === 'Identifier' && - !prop.argument.name.startsWith(`${HELPER_PREFIX}props`) - ) { - // { ...rest } - props.push({ - path, - name: prop.argument.name, - value: propNames.join(', '), - isRest: true, - }) - } else if (prop) { - getProps(prop, `${path}[${index}]`, s, props) - } - }) - return props.length ? props : undefined -} - -export function prependFunctionalNode( - node: FunctionalNode, - s: MagicString, - result: string, -): void { - const isBlockStatement = node.body.type === 'BlockStatement' - const start = node.body.extra?.parenthesized - ? (node.body.extra.parenStart as number) - : node.body.start! - s.appendRight( - start + (isBlockStatement ? 1 : 0), - `${result};${!isBlockStatement ? 'return ' : ''}`, - ) - if (!isBlockStatement) { - s.appendLeft(start, '{') - s.appendRight(node.end!, '}') - } -} diff --git a/packages/jsx-macros/src/core/define-expose/vue.ts b/packages/jsx-macros/src/core/define-expose/vue.ts index 81105c230..df47f57f5 100644 --- a/packages/jsx-macros/src/core/define-expose/vue.ts +++ b/packages/jsx-macros/src/core/define-expose/vue.ts @@ -1,5 +1,4 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' -import { useExposeHelperId } from '../helper' import type { CallExpression } from '@babel/types' export function transformVueDefineExpose( @@ -9,7 +8,7 @@ export function transformVueDefineExpose( ): void { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useExpose', useExposeHelperId), + importHelperFn(s, 0, 'useExpose', '@vue-macros/jsx-macros/helpers'), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, diff --git a/packages/jsx-macros/src/core/helper/index.ts b/packages/jsx-macros/src/core/helper/index.ts index bdd5fc1ab..1940148df 100644 --- a/packages/jsx-macros/src/core/helper/index.ts +++ b/packages/jsx-macros/src/core/helper/index.ts @@ -2,11 +2,5 @@ import { VIRTUAL_ID_PREFIX } from '@vue-macros/common' export const helperPrefix: '/vue-macros/jsx-macros' = `${VIRTUAL_ID_PREFIX}/jsx-macros` -export const useExposeHelperId: '/vue-macros/jsx-macros/use-expose' = `${helperPrefix}/use-expose` -export { default as useExposeHelperCode } from './use-expose?raw' - export const useModelHelperId: '/vue-macros/jsx-macros/use-model' = `${helperPrefix}/use-model` export { default as useModelHelperCode } from './use-model?raw' - -export const withDefaultsHelperId: '/vue-macros/jsx-macros/with-defaults' = `${helperPrefix}/with-defaults` -export { default as withDefaultsCode } from './with-defaults?raw' diff --git a/packages/jsx-macros/src/core/helper/use-expose.ts b/packages/jsx-macros/src/core/helper/use-expose.ts index 6cb28ef94..bd21d5a28 100644 --- a/packages/jsx-macros/src/core/helper/use-expose.ts +++ b/packages/jsx-macros/src/core/helper/use-expose.ts @@ -1,4 +1,7 @@ -export function useExpose(i: any, exposed = {}): any { +export function useExpose>( + i: any, + exposed: T, +): T { if (i) { i.exposed = exposed if (i.vnode) i.vnode.shapeFlag = 4 diff --git a/packages/jsx-macros/src/core/helper/with-defaults.ts b/packages/jsx-macros/src/core/helper/with-defaults.ts deleted file mode 100644 index 0d805e762..000000000 --- a/packages/jsx-macros/src/core/helper/with-defaults.ts +++ /dev/null @@ -1,38 +0,0 @@ -function resolveDefaultProps(paths: Record): any { - const result: any = {} - - for (const path of Object.keys(paths)) { - const segments = path.split(/[?.[\]]/).filter(Boolean) - let current = result - - for (let i = 0; i < segments.length; i++) { - const segment = segments[i] - if (i === segments.length - 1) { - current[segment] = paths[path] - } else { - if (!current[segment]) { - current[segment] = Number.isNaN(Number(segments[i + 1])) ? {} : [] - } - current = current[segment] - } - } - } - - return result -} - -export function createPropsDefaultProxy(props: any, defaults: any): any { - const defaultProps = resolveDefaultProps(defaults) - const result: Record = {} - - for (const key of [ - ...new Set([...Object.keys(props), ...Object.keys(defaultProps)]), - ]) { - Object.defineProperty(result, key, { - enumerable: true, - get: () => (props[key] === undefined ? defaultProps[key] : props[key]), - }) - } - - return result -} diff --git a/packages/jsx-macros/src/core/index.ts b/packages/jsx-macros/src/core/index.ts index 0db27bbe1..3ea7e4459 100644 --- a/packages/jsx-macros/src/core/index.ts +++ b/packages/jsx-macros/src/core/index.ts @@ -7,7 +7,7 @@ import { walkAST, type CodeTransform, } from '@vue-macros/common' -import type { OptionsResolved } from '../api' +import type { OptionsResolved } from '..' import { transformDefineComponent } from './define-component' import { transformDefineExpose } from './define-expose' import { transformDefineModel } from './define-model' diff --git a/packages/jsx-macros/src/core/plugin.ts b/packages/jsx-macros/src/core/plugin.ts new file mode 100644 index 000000000..c06bdd6c3 --- /dev/null +++ b/packages/jsx-macros/src/core/plugin.ts @@ -0,0 +1,97 @@ +import { + createFilter, + detectVueVersion, + FilterFileType, + getFilterPattern, + normalizePath, + REGEX_NODE_MODULES, + REGEX_SETUP_SFC, + type BaseOptions, + type MarkRequired, +} from '@vue-macros/common' +import { generatePluginName } from '#macros' with { type: 'macro' } +import { helperPrefix, useModelHelperCode, useModelHelperId } from './helper' +import { transformStyle } from './style' +import { transformJsxMacros } from '.' +import type { UnpluginContextMeta, UnpluginFactory } from 'unplugin' + +export type Options = BaseOptions & { + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + defineComponent?: { alias: string[] } + defineModel?: { alias: string[] } + defineExpose?: { alias: string[] } + defineSlots?: { alias: string[] } + defineStyle?: { alias: string[] } +} +export type OptionsResolved = MarkRequired< + Options, + | 'include' + | 'version' + | 'lib' + | 'defineComponent' + | 'defineModel' + | 'defineExpose' + | 'defineSlots' + | 'defineStyle' +> + +function resolveOptions( + options: Options, + framework: UnpluginContextMeta['framework'], +): OptionsResolved { + const version = options.version || detectVueVersion() + const lib = options.lib || 'vue' + const include = getFilterPattern([FilterFileType.SRC_FILE], framework) + return { + include, + exclude: [REGEX_SETUP_SFC, REGEX_NODE_MODULES], + ...options, + version, + lib, + defineComponent: { + alias: options?.defineComponent?.alias ?? ['defineComponent'], + }, + defineModel: { alias: options?.defineModel?.alias ?? ['defineModel'] }, + defineSlots: { alias: options?.defineSlots?.alias ?? ['defineSlots'] }, + defineExpose: { alias: options?.defineExpose?.alias ?? ['defineExpose'] }, + defineStyle: { alias: options?.defineStyle?.alias ?? ['defineStyle'] }, + } +} + +const name = generatePluginName() + +export const plugin: UnpluginFactory = ( + userOptions: Options = {}, + meta = { framework: 'vite' }, +) => { + const { framework } = meta + const options = resolveOptions(userOptions, framework) + const filter = createFilter(options) + const importMap = new Map() + + return { + name, + enforce: 'pre', + + resolveId(id) { + if (normalizePath(id).startsWith(helperPrefix)) return id + }, + loadInclude(id) { + return normalizePath(id).startsWith(helperPrefix) + }, + load(_id) { + const id = normalizePath(_id) + if (id === useModelHelperId) return useModelHelperCode + else if (importMap.get(id)) return importMap.get(id) + }, + + transformInclude(id) { + if (importMap.get(id)) return true + return filter(id) + }, + transform(code, id) { + if (importMap.get(id)) return transformStyle(code, id, options) + return transformJsxMacros(code, id, importMap, options) + }, + } +} diff --git a/packages/jsx-macros/src/core/style.ts b/packages/jsx-macros/src/core/style.ts index 798624a16..e431b8636 100644 --- a/packages/jsx-macros/src/core/style.ts +++ b/packages/jsx-macros/src/core/style.ts @@ -1,5 +1,5 @@ import { compileStyleAsync } from 'vue/compiler-sfc' -import type { OptionsResolved } from '../api' +import type { OptionsResolved } from '..' export async function transformStyle( code: string, diff --git a/packages/jsx-macros/src/helpers.ts b/packages/jsx-macros/src/helpers.ts new file mode 100644 index 000000000..5df692ad3 --- /dev/null +++ b/packages/jsx-macros/src/helpers.ts @@ -0,0 +1,3 @@ +export { createPropsDefaultProxy } from '@vue-macros/jsx-directive/helpers' + +export { useExpose } from './core/helper/use-expose' diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index 046c8a81b..bee1f04dc 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -1,7 +1,7 @@ import { createUnplugin, type UnpluginInstance } from 'unplugin' -import unplugin, { type Options } from './api' +import { plugin, type Options, type OptionsResolved } from './core/plugin' -export type { Options } +export type { Options, OptionsResolved } -const plugin: UnpluginInstance = createUnplugin(unplugin) -export default plugin +const unplugin: UnpluginInstance = createUnplugin(plugin) +export default unplugin diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 0b125e42a..36be51cb8 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -2,7 +2,7 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " -import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "@vue-macros/jsx-macros/helpers"; import { useAttrs as __MACROS_useAttrs } from "vue"; import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' @@ -53,7 +53,7 @@ let __temp, __restore exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; +import { useExpose as __MACROS_useExpose } from "@vue-macros/jsx-macros/helpers"; import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export function Comp(__MACROS_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, diff --git a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap b/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap deleted file mode 100644 index 19ddadec8..000000000 --- a/packages/jsx-macros/tests/__snapshots__/restructure.spec.ts.snap +++ /dev/null @@ -1,37 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`transform > reconstruct 1`] = ` -"const App = (__MACROS_props, __MACROS_props1) => { - function onClick(__MACROS_props){ - return { foo: __MACROS_props.foo, baz: __MACROS_props1.baz.baz } - }; - return [ __MACROS_props[0][0][1], __MACROS_props[1].id.foo[0], __MACROS_props1.baz ] - }" -`; - -exports[`transform > reconstruct arrowFunctionExpression 1`] = ` -"const App = (__MACROS_props) => ( - <>{[__MACROS_props[0].root.foo]} - )" -`; - -exports[`transform > reconstruct default-prop 1`] = ` -" -import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props, __MACROS_props1){ -const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.foo': 'bar'}); -const __MACROS_default_props1 = __MACROS_createPropsDefaultProxy(__MACROS_props1, {'.foo': 'foo'}); -const rest = __MACROS_createPropsRestProxy(__MACROS_default_props, ['foo', 'baz']); - return <>{[__MACROS_default_props.foo, __MACROS_default_props.baz, rest, __MACROS_default_props1.foo]} - }" -`; - -exports[`transform > reconstruct rest-prop 1`] = ` -" -import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; -import { createPropsRestProxy as __MACROS_createPropsRestProxy } from "vue";function App(__MACROS_props){ -const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 1}); -const rest = __MACROS_createPropsRestProxy(__MACROS_default_props, ['foo', 'bar']); - return <>{[__MACROS_default_props.foo, __MACROS_default_props.bar, rest]} - }" -`; diff --git a/packages/jsx-macros/tests/restructure.spec.ts b/packages/jsx-macros/tests/restructure.spec.ts deleted file mode 100644 index 9eb23a086..000000000 --- a/packages/jsx-macros/tests/restructure.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { babelParse, walkAST } from '@vue-macros/common' -import { describe, expect, test } from 'vitest' -import { MagicString } from 'vue/compiler-sfc' -import { restructure } from '../src/api' -import type { Node } from '@babel/types' - -export function transformRestructure(code: string) { - const s = new MagicString(code) - const ast = babelParse(code, 'tsx') - walkAST(ast, { - enter(node) { - if ( - node.type === 'FunctionExpression' || - node.type === 'ArrowFunctionExpression' || - node.type === 'FunctionDeclaration' - ) { - restructure(s, node) - } - }, - }) - return s.toString() -} - -describe('transform', () => { - test('reconstruct', () => { - const code = transformRestructure( - `const App = ([[[,foo]], {id: {foo: [bar]}}], { baz }) => { - function onClick({ foo }){ - return { foo, baz: baz.baz } - }; - return [ foo, bar, baz ] - }`, - )! - expect(code).toMatchSnapshot() - }) - - test('reconstruct arrowFunctionExpression', () => { - const code = transformRestructure( - `const App = ([{root: {foo}}]) => ( - <>{[foo]} - )`, - )! - expect(code).toMatchSnapshot() - }) - - test('reconstruct default-prop', () => { - const code = transformRestructure( - `function App({foo: bar = 'bar', baz: qux, ...rest}, [foo = 'foo']){ - return <>{[bar, qux, rest, foo]} - }`, - )! - expect(code).toMatchSnapshot() - }) - - test('reconstruct rest-prop', () => { - const code = transformRestructure( - `function App({foo, bar = 1, ...rest}){ - return <>{[foo, bar, rest]} - }`, - )! - expect(code).toMatchSnapshot() - }) -}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c685a21cb..6205647eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -732,6 +732,9 @@ importers: '@vue-macros/common': specifier: workspace:* version: link:../common + '@vue-macros/jsx-directive': + specifier: workspace:* + version: link:../jsx-directive '@vue/compiler-core': specifier: 'catalog:' version: 3.5.13 From d87b478218cc78ab2600c81dea2f7d1ca4a90e19 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 3 Feb 2025 01:27:44 +0800 Subject: [PATCH 119/156] feat: import withDefaults from jsx-directive --- .../jsx-macros/src/core/define-component/index.ts | 3 ++- packages/jsx-macros/src/core/define-expose/vue.ts | 3 ++- packages/jsx-macros/src/core/helper/index.ts | 6 ++++++ packages/jsx-macros/src/core/plugin.ts | 14 ++++++++++++-- .../tests/__snapshots__/fixtures.test.ts.snap | 4 ++-- packages/jsx-macros/tsup.config.ts | 4 +++- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 0adfa172d..1eb95938a 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -2,6 +2,7 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { restructure } from '@vue-macros/jsx-directive/api' import { walkIdentifiers } from '@vue/compiler-core' import { importHelper } from '../common' +import { withDefaultsHelperId } from '../helper' import type { FunctionalNode, RootMapValue } from '..' import type { OptionsResolved } from '../..' import { transformAwait } from './await' @@ -26,7 +27,7 @@ export function transformDefineComponent( getWalkedIds(root, propsName).forEach((id) => (props[id] = null)) } else { const restructuredProps = restructure(s, root, { - withDefaultsFrom: '@vue-macros/jsx-macros/helpers', + withDefaultsFrom: withDefaultsHelperId, generateRestProps: (restPropsName, index, list) => { if (index === list.length - 1) { hasRestProp = true diff --git a/packages/jsx-macros/src/core/define-expose/vue.ts b/packages/jsx-macros/src/core/define-expose/vue.ts index df47f57f5..81105c230 100644 --- a/packages/jsx-macros/src/core/define-expose/vue.ts +++ b/packages/jsx-macros/src/core/define-expose/vue.ts @@ -1,4 +1,5 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' +import { useExposeHelperId } from '../helper' import type { CallExpression } from '@babel/types' export function transformVueDefineExpose( @@ -8,7 +9,7 @@ export function transformVueDefineExpose( ): void { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useExpose', '@vue-macros/jsx-macros/helpers'), + importHelperFn(s, 0, 'useExpose', useExposeHelperId), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, diff --git a/packages/jsx-macros/src/core/helper/index.ts b/packages/jsx-macros/src/core/helper/index.ts index 1940148df..1adf40707 100644 --- a/packages/jsx-macros/src/core/helper/index.ts +++ b/packages/jsx-macros/src/core/helper/index.ts @@ -2,5 +2,11 @@ import { VIRTUAL_ID_PREFIX } from '@vue-macros/common' export const helperPrefix: '/vue-macros/jsx-macros' = `${VIRTUAL_ID_PREFIX}/jsx-macros` +export const useExposeHelperId: '/vue-macros/jsx-macros/use-expose' = `${helperPrefix}/use-expose` +export { default as useExposeHelperCode } from './use-expose?raw' + export const useModelHelperId: '/vue-macros/jsx-macros/use-model' = `${helperPrefix}/use-model` export { default as useModelHelperCode } from './use-model?raw' + +export const withDefaultsHelperId: '/vue-macros/jsx-macros/with-defaults' = `${helperPrefix}/with-defaults` +export { withDefaultsHelperCode } from '@vue-macros/jsx-directive/api' diff --git a/packages/jsx-macros/src/core/plugin.ts b/packages/jsx-macros/src/core/plugin.ts index c06bdd6c3..2c52a0947 100644 --- a/packages/jsx-macros/src/core/plugin.ts +++ b/packages/jsx-macros/src/core/plugin.ts @@ -10,7 +10,15 @@ import { type MarkRequired, } from '@vue-macros/common' import { generatePluginName } from '#macros' with { type: 'macro' } -import { helperPrefix, useModelHelperCode, useModelHelperId } from './helper' +import { + helperPrefix, + useExposeHelperCode, + useExposeHelperId, + useModelHelperCode, + useModelHelperId, + withDefaultsHelperCode, + withDefaultsHelperId, +} from './helper' import { transformStyle } from './style' import { transformJsxMacros } from '.' import type { UnpluginContextMeta, UnpluginFactory } from 'unplugin' @@ -81,7 +89,9 @@ export const plugin: UnpluginFactory = ( }, load(_id) { const id = normalizePath(_id) - if (id === useModelHelperId) return useModelHelperCode + if (id === useExposeHelperId) return useExposeHelperCode + else if (id === useModelHelperId) return useModelHelperCode + else if (id === withDefaultsHelperId) return withDefaultsHelperCode else if (importMap.get(id)) return importMap.get(id) }, diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 36be51cb8..0b125e42a 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -2,7 +2,7 @@ exports[`fixtures > ./fixtures/define-component.tsx 1`] = ` " -import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "@vue-macros/jsx-macros/helpers"; +import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; import { useAttrs as __MACROS_useAttrs } from "vue"; import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' @@ -53,7 +53,7 @@ let __temp, __restore exports[`fixtures > ./fixtures/define-expose.tsx 1`] = ` " -import { useExpose as __MACROS_useExpose } from "@vue-macros/jsx-macros/helpers"; +import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export function Comp(__MACROS_props) { __MACROS_useExpose(__MACROS_getCurrentInstance(), { foo: 1, diff --git a/packages/jsx-macros/tsup.config.ts b/packages/jsx-macros/tsup.config.ts index 1605eae16..e5efb9683 100644 --- a/packages/jsx-macros/tsup.config.ts +++ b/packages/jsx-macros/tsup.config.ts @@ -1 +1,3 @@ -export { default } from '../../tsup.config.js' +import { config } from '../../tsup.config.js' + +export default config() From 882d13974d0bddf2b204441d4e59c2cd65cb07d9 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 3 Feb 2025 01:32:42 +0800 Subject: [PATCH 120/156] chore: remove helpers --- packages/jsx-macros/package.json | 9 --------- packages/jsx-macros/src/helpers.ts | 3 --- 2 files changed, 12 deletions(-) delete mode 100644 packages/jsx-macros/src/helpers.ts diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 914395d8c..50fb01a22 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -50,11 +50,6 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, - "./helpers": { - "dev": "./src/helpers.ts", - "require": "./dist/helpers.cjs", - "import": "./dist/helpers.js" - }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.cjs", @@ -105,10 +100,6 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, - "./helpers": { - "require": "./dist/helpers.cjs", - "import": "./dist/helpers.js" - }, "./rolldown": { "require": "./dist/rolldown.cjs", "import": "./dist/rolldown.js" diff --git a/packages/jsx-macros/src/helpers.ts b/packages/jsx-macros/src/helpers.ts deleted file mode 100644 index 5df692ad3..000000000 --- a/packages/jsx-macros/src/helpers.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { createPropsDefaultProxy } from '@vue-macros/jsx-directive/helpers' - -export { useExpose } from './core/helper/use-expose' From c7c68ec7a09d2aa1007aecfef4e0df472a8594ae Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 3 Feb 2025 01:42:00 +0800 Subject: [PATCH 121/156] fix: mono --- packages/jsx/package.json | 2 +- pnpm-lock.yaml | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/jsx/package.json b/packages/jsx/package.json index 27ae78ad2..17771193e 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -149,7 +149,7 @@ "@vue-macros/jsx-directive": "workspace:*", "@vue-macros/jsx-macros": "workspace:*", "@vue-macros/volar": "workspace:*", - "unplugin-combine": "^1.0.3" + "unplugin-combine": "^1.2.0" }, "devDependencies": { "csstype": "^3.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35213a513..00d791898 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -727,15 +727,15 @@ importers: specifier: workspace:* version: link:../volar unplugin-combine: - specifier: ^1.0.3 - version: 1.0.3(@rspack/core@1.1.5(@swc/helpers@0.5.15))(esbuild@0.24.0)(rolldown@0.15.0(@babel/runtime@7.26.0))(rollup@4.28.1)(vite@6.0.2(@types/node@22.10.1)(jiti@2.4.1)(less@4.2.1)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))(webpack@5.97.1(esbuild@0.24.0)) + specifier: ^1.2.0 + version: 1.2.0(@rspack/core@1.2.2(@swc/helpers@0.5.15))(esbuild@0.24.2)(rolldown@1.0.0-beta.3(@babel/runtime@7.26.7)(typescript@5.7.3))(rollup@4.32.0)(unplugin@2.1.2)(vite@6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(webpack@5.97.1(esbuild@0.24.2)) devDependencies: csstype: specifier: ^3.1.3 version: 3.1.3 vue: specifier: 'catalog:' - version: 3.5.13(typescript@5.6.3) + version: 3.5.13(typescript@5.7.3) packages/jsx-directive: dependencies: @@ -12916,6 +12916,16 @@ snapshots: vite: 6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) webpack: 5.97.1(esbuild@0.24.2) + unplugin-combine@1.2.0(@rspack/core@1.2.2(@swc/helpers@0.5.15))(esbuild@0.24.2)(rolldown@1.0.0-beta.3(@babel/runtime@7.26.7)(typescript@5.7.3))(rollup@4.32.0)(unplugin@2.1.2)(vite@6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(webpack@5.97.1(esbuild@0.24.2)): + optionalDependencies: + '@rspack/core': 1.2.2(@swc/helpers@0.5.15) + esbuild: 0.24.2 + rolldown: 1.0.0-beta.3(@babel/runtime@7.26.7)(typescript@5.7.3) + rollup: 4.32.0 + unplugin: 2.1.2 + vite: 6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + webpack: 5.97.1(esbuild@0.24.2) + unplugin-isolated-decl@0.10.5(oxc-transform@0.48.1)(rollup@4.32.0)(typescript@5.7.3): dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.32.0) From 73280eb9bf26c14064a04ec5b13705766e9b03a0 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 3 Feb 2025 01:50:15 +0800 Subject: [PATCH 122/156] fix: typecheck --- packages/volar/src/jsx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/volar/src/jsx.ts b/packages/volar/src/jsx.ts index c03095234..c32b87d09 100644 --- a/packages/volar/src/jsx.ts +++ b/packages/volar/src/jsx.ts @@ -19,7 +19,7 @@ type JSXOptions = { const plugin: PluginReturn = createPlugin( (ctx, userOptions) => Object.entries(jsxPlugins).flatMap(([name, plugin]) => { - const options = userOptions?.[name as keyof JSXOptions] ?? {} + const options = userOptions?.[name as keyof JSXOptions] ?? ({} as any) if (!options) return [] return plugin(options === true ? {} : options)(ctx) }), From a2b17788d27b804e2c74bc9aaac86a7c4f28c34b Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 3 Feb 2025 02:13:34 +0800 Subject: [PATCH 123/156] feat: expose raw --- packages/jsx-macros/package.json | 9 +++++++++ packages/jsx-macros/src/raw.ts | 3 +++ 2 files changed, 12 insertions(+) create mode 100644 packages/jsx-macros/src/raw.ts diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 50fb01a22..777b5b3fc 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -50,6 +50,11 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, + "./raw": { + "dev": "./src/raw.ts", + "require": "./dist/raw.cjs", + "import": "./dist/raw.js" + }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.cjs", @@ -100,6 +105,10 @@ "require": "./dist/esbuild.cjs", "import": "./dist/esbuild.js" }, + "./raw": { + "require": "./dist/raw.cjs", + "import": "./dist/raw.js" + }, "./rolldown": { "require": "./dist/rolldown.cjs", "import": "./dist/rolldown.js" diff --git a/packages/jsx-macros/src/raw.ts b/packages/jsx-macros/src/raw.ts new file mode 100644 index 000000000..f0df9423f --- /dev/null +++ b/packages/jsx-macros/src/raw.ts @@ -0,0 +1,3 @@ +import { plugin } from './core/plugin' + +export default plugin From dda3750e3cb0deb6a2161311d0e4594d552e9a75 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 24 Feb 2025 19:50:05 +0800 Subject: [PATCH 124/156] feat(volar): add missing type --- packages/volar/src/jsx-macros/global-types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index ed3a51e2d..9f8ffd8c3 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -11,5 +11,7 @@ declare function ${options.defineExpose.alias[0]}(...args: ${HELPER_PREFIX}StyleArgs): T; scss: (...args: ${HELPER_PREFIX}StyleArgs)=> T; sass: (...args: ${HELPER_PREFIX}StyleArgs)=> T; stylus: (...args: ${HELPER_PREFIX}StyleArgs)=> T; less: (...args: ${HELPER_PREFIX}StyleArgs)=> T; postcss: (...args: ${HELPER_PREFIX}StyleArgs)=> T }; type ${HELPER_PREFIX}StyleArgs = [style: string, options?: { scoped?: boolean }]; type ${HELPER_PREFIX}PrettifyLocal = { [K in keyof T]: T[K]; } & {}; +type __VLS_IsAny = 0 extends 1 & T ? true : false; +type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; ` } From ae50b56be08f225be590e2c6e4e2669dbbdbe22e Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 26 Feb 2025 08:59:44 +0800 Subject: [PATCH 125/156] feat: use vue instead of vue/vapor --- .github/workflows/release-pr.yml | 2 +- packages/jsx-macros/src/core/define-expose/index.ts | 2 +- packages/jsx-macros/src/core/define-expose/vue.ts | 3 +-- packages/jsx-macros/src/core/define-slots.ts | 2 +- packages/jsx-macros/src/core/helper/use-model.ts | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index bbb732aa9..c03fb160a 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -31,4 +31,4 @@ jobs: run: pnpm build - name: Publish - run: pnpm dlx pkg-pr-new@0.0 publish --compact --pnpm './packages/*' + run: pnpm dlx pkg-pr-new@0.0 publish --pnpm './packages/*' diff --git a/packages/jsx-macros/src/core/define-expose/index.ts b/packages/jsx-macros/src/core/define-expose/index.ts index 812bb85fa..30d4544e8 100644 --- a/packages/jsx-macros/src/core/define-expose/index.ts +++ b/packages/jsx-macros/src/core/define-expose/index.ts @@ -16,7 +16,7 @@ export function transformDefineExpose( version: number, ): void { if (lib.includes('vue')) { - transformVueDefineExpose(node, s, lib) + transformVueDefineExpose(node, s) } else if (lib.includes('react')) { transformReactDefineExpose(node, propsName, root, s, lib, version) } diff --git a/packages/jsx-macros/src/core/define-expose/vue.ts b/packages/jsx-macros/src/core/define-expose/vue.ts index 81105c230..792cdfa70 100644 --- a/packages/jsx-macros/src/core/define-expose/vue.ts +++ b/packages/jsx-macros/src/core/define-expose/vue.ts @@ -5,7 +5,6 @@ import type { CallExpression } from '@babel/types' export function transformVueDefineExpose( node: CallExpression, s: MagicStringAST, - lib: string, ): void { s.overwriteNode( node.callee, @@ -13,6 +12,6 @@ export function transformVueDefineExpose( ) s.appendRight( node.arguments[0]?.start || node.end! - 1, - `${importHelperFn(s, 0, 'getCurrentInstance', lib)}(), `, + `${importHelperFn(s, 0, 'getCurrentInstance', 'vue')}(), `, ) } diff --git a/packages/jsx-macros/src/core/define-slots.ts b/packages/jsx-macros/src/core/define-slots.ts index aa5a2d149..87caf8966 100644 --- a/packages/jsx-macros/src/core/define-slots.ts +++ b/packages/jsx-macros/src/core/define-slots.ts @@ -15,7 +15,7 @@ export function transformDefineSlots( `Object.assign`, ) const slots = lib.includes('vue') - ? `${importHelperFn(s, 0, 'getCurrentInstance', lib)}()?.slots` + ? `${importHelperFn(s, 0, 'getCurrentInstance', 'vue')}()?.slots` : `${propsName}.vSlots` s.appendLeft(node.end! - 1, `${node.arguments[0] ? ',' : '{}, '}${slots}`) } diff --git a/packages/jsx-macros/src/core/helper/use-model.ts b/packages/jsx-macros/src/core/helper/use-model.ts index 46b548fb3..37402a9f4 100644 --- a/packages/jsx-macros/src/core/helper/use-model.ts +++ b/packages/jsx-macros/src/core/helper/use-model.ts @@ -16,7 +16,7 @@ export function useModel( options: DefineModelOptions = {}, ): any { const res = customRef((track, trigger) => { - let localValue: any = options?.default + let localValue: any = options && options.default let prevEmittedValue: any watchSyncEffect(() => { From 70d289719e08b27daf40a62f6fa2d1233e7be340 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 26 Feb 2025 17:04:09 +0800 Subject: [PATCH 126/156] feat: use currentInstance instead of getCurrentInstance for vapor mode --- .../src/core/define-expose/index.ts | 2 +- .../jsx-macros/src/core/define-expose/vue.ts | 5 +- packages/jsx-macros/src/core/define-slots.ts | 2 +- .../tests/__snapshots__/fixtures.test.ts.snap | 145 +++++++++++++++++- packages/jsx-macros/tests/fixtures.test.ts | 16 ++ 5 files changed, 164 insertions(+), 6 deletions(-) diff --git a/packages/jsx-macros/src/core/define-expose/index.ts b/packages/jsx-macros/src/core/define-expose/index.ts index 30d4544e8..812bb85fa 100644 --- a/packages/jsx-macros/src/core/define-expose/index.ts +++ b/packages/jsx-macros/src/core/define-expose/index.ts @@ -16,7 +16,7 @@ export function transformDefineExpose( version: number, ): void { if (lib.includes('vue')) { - transformVueDefineExpose(node, s) + transformVueDefineExpose(node, s, lib) } else if (lib.includes('react')) { transformReactDefineExpose(node, propsName, root, s, lib, version) } diff --git a/packages/jsx-macros/src/core/define-expose/vue.ts b/packages/jsx-macros/src/core/define-expose/vue.ts index 792cdfa70..7ef49e5f1 100644 --- a/packages/jsx-macros/src/core/define-expose/vue.ts +++ b/packages/jsx-macros/src/core/define-expose/vue.ts @@ -5,6 +5,7 @@ import type { CallExpression } from '@babel/types' export function transformVueDefineExpose( node: CallExpression, s: MagicStringAST, + lib: string, ): void { s.overwriteNode( node.callee, @@ -12,6 +13,8 @@ export function transformVueDefineExpose( ) s.appendRight( node.arguments[0]?.start || node.end! - 1, - `${importHelperFn(s, 0, 'getCurrentInstance', 'vue')}(), `, + lib.includes('vapor') + ? `${importHelperFn(s, 0, 'currentInstance', 'vue')}, ` + : `${importHelperFn(s, 0, 'getCurrentInstance', 'vue')}(), `, ) } diff --git a/packages/jsx-macros/src/core/define-slots.ts b/packages/jsx-macros/src/core/define-slots.ts index 87caf8966..15e72fd39 100644 --- a/packages/jsx-macros/src/core/define-slots.ts +++ b/packages/jsx-macros/src/core/define-slots.ts @@ -15,7 +15,7 @@ export function transformDefineSlots( `Object.assign`, ) const slots = lib.includes('vue') - ? `${importHelperFn(s, 0, 'getCurrentInstance', 'vue')}()?.slots` + ? `${importHelperFn(s, 0, 'useSlots', 'vue')}()` : `${propsName}.vSlots` s.appendLeft(node.end! - 1, `${node.arguments[0] ? ',' : '{}, '}${slots}`) } diff --git a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap index 0b125e42a..a1edd9d61 100644 --- a/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx-macros/tests/__snapshots__/fixtures.test.ts.snap @@ -97,17 +97,17 @@ export default function (__MACROS_props) { exports[`fixtures > ./fixtures/define-slots.tsx 1`] = ` " -import { getCurrentInstance as __MACROS_getCurrentInstance } from "vue";export const Comp = (__MACROS_props) => { +import { useSlots as __MACROS_useSlots } from "vue";export const Comp = (__MACROS_props) => { const slots = Object.assign<{ default: () => any - }>({}, __MACROS_getCurrentInstance()?.slots) + }>({}, __MACROS_useSlots()) return
{slots.default?.()}
} export default function (__MACROS_props) { const slots = Object.assign({ default: () =>
default
, - },__MACROS_getCurrentInstance()?.slots) + },__MACROS_useSlots()) return
{slots.default?.()}
} " @@ -189,3 +189,142 @@ export const Comp2 = ({ foo, ...__MACROS_props }: any) => { } " `; + +exports[`vue/vapor fixtures > ./fixtures/define-component.tsx 1`] = ` +" +import { createPropsDefaultProxy as __MACROS_createPropsDefaultProxy } from "/vue-macros/jsx-macros/with-defaults"; +import { useAttrs as __MACROS_useAttrs } from "vue"; +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model"; +import { withAsyncContext as __MACROS_withAsyncContext } from "vue";import { defineComponent, nextTick } from 'vue' + +const Comp = defineComponent( + (__MACROS_props) => { +const __MACROS_default_props = __MACROS_createPropsDefaultProxy(__MACROS_props, {'.bar': 'bar'!});const attrs = __MACROS_useAttrs(); + const foo = $( + __MACROS_useModel(__MACROS_props, 'foo', { + validator: (value) => { + return value === 'foo' + }, + type: String, + })!, + ) + return
{[foo, __MACROS_default_props.bar, attrs.baz]}
+ }, + {props: { 'bar': { required: true }, 'foo': { required: true, validator: (value) => { + return value === 'foo' + }, type: String }, 'onUpdate:foo': null, 'fooModifiers': null },inheritAttrs: false, name: 'Comp' }, +) + +const Comp1 = defineComponent((props: { bar: 'bar'; 'onUpdate:bar': any }) => { + const foo = __MACROS_useModel(props, 'foo') + return
{[foo.value, props['bar'], props['onUpdate:bar']]}
+}, { props: { 'bar': null, 'onUpdate:bar': null, 'foo': null, 'onUpdate:foo': null, 'fooModifiers': null } }) + +const Comp2 = defineComponent(async (__MACROS_props) => { +let __temp, __restore + + ;( + ([__temp,__restore] = __MACROS_withAsyncContext(() => nextTick())), + await __temp, + __restore() +) + let foo = ( + ([__temp,__restore] = __MACROS_withAsyncContext(() => new Promise((resolve) => { + setTimeout(() => resolve('foo'), 1000) + }))), + __temp = await __temp, + __restore(), + __temp +) + return () =>
{foo}
+}) +" +`; + +exports[`vue/vapor fixtures > ./fixtures/define-expose.tsx 1`] = ` +" +import { useExpose as __MACROS_useExpose } from "/vue-macros/jsx-macros/use-expose"; +import { currentInstance as __MACROS_currentInstance } from "vue";export function Comp(__MACROS_props) { + __MACROS_useExpose(__MACROS_currentInstance, { + foo: 1, + }) + return
+} + +export const Comp1 = function (props: any) { + __MACROS_useExpose(__MACROS_currentInstance, { + foo: props.foo, + }) + return
+} + +export const Comp2 = ({ foo, ...__MACROS_props }: any) => { + __MACROS_useExpose(__MACROS_currentInstance, { + foo, + }) + return
+} +" +`; + +exports[`vue/vapor fixtures > ./fixtures/define-model.tsx 1`] = ` +" +import { useModel as __MACROS_useModel } from "/vue-macros/jsx-macros/use-model";export const Comp = ({ bar, ...__MACROS_props }: { bar: string }) => { + const foo = __MACROS_useModel(__MACROS_props, 'foo', { default: bar }) + return
{foo.value}
+} + +export default function (__MACROS_props) { + const modelValue = $(__MACROS_useModel(__MACROS_props, 'modelValue',)!) + return ( + + {modelValue} + + ) +} +" +`; + +exports[`vue/vapor fixtures > ./fixtures/define-slots.tsx 1`] = ` +" +import { useSlots as __MACROS_useSlots } from "vue";export const Comp = (__MACROS_props) => { + const slots = Object.assign<{ + default: () => any + }>({}, __MACROS_useSlots()) + return
{slots.default?.()}
+} + +export default function (__MACROS_props) { + const slots = Object.assign({ + default: () =>
default
, + },__MACROS_useSlots()) + return
{slots.default?.()}
+} +" +`; + +exports[`vue/vapor fixtures > ./fixtures/define-style.tsx 1`] = ` +"import "/vue-macros/jsx-macros/define-style/0?scopeId=4e9d5cd0&scoped=true&lang.css";import style1 from "/vue-macros/jsx-macros/define-style/1?scopeId=426a859d&scoped=true&lang.module.scss";import "/vue-macros/jsx-macros/define-style/2?scopeId=63a7910c&scoped=false&lang.scss";import { defineComponent, ref } from 'vue' + +export const Comp = (__MACROS_props) => { + const color = ref('red') + + return
foo
+} + +export default defineComponent((__MACROS_props) => { + const color = ref('red') + const styles = style1 + return () => ( + <> +
foo
+
+ bar +
+ + ) +}) + + +" +`; diff --git a/packages/jsx-macros/tests/fixtures.test.ts b/packages/jsx-macros/tests/fixtures.test.ts index 00a1276f6..3be1f155a 100644 --- a/packages/jsx-macros/tests/fixtures.test.ts +++ b/packages/jsx-macros/tests/fixtures.test.ts @@ -26,6 +26,22 @@ describe('fixtures', async () => { ) }) +describe('vue/vapor fixtures', async () => { + await testFixtures( + import.meta.glob('./fixtures/**/*.tsx', { + eager: true, + as: 'raw', + }), + (args, id, code) => + transformJsxMacros(code, id, new Map(), { + lib: 'vue/vapor', + include: ['*.tsx'], + version: 3.5, + ...options, + })?.code, + ) +}) + describe('react fixtures', async () => { await testFixtures( import.meta.glob('./fixtures/**/define-expose.tsx', { From 1e6370104f82b5e8396253cd5d530ae06b36fd15 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 26 Feb 2025 22:20:56 +0800 Subject: [PATCH 127/156] feat: add defineVaporComponent alias --- packages/jsx-macros/src/core/plugin.ts | 7 ++++++- packages/volar/src/jsx-macros.ts | 7 ++++++- packages/volar/src/jsx-macros/global-types.ts | 6 +++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/jsx-macros/src/core/plugin.ts b/packages/jsx-macros/src/core/plugin.ts index 2c52a0947..ffc0d6ce5 100644 --- a/packages/jsx-macros/src/core/plugin.ts +++ b/packages/jsx-macros/src/core/plugin.ts @@ -57,7 +57,12 @@ function resolveOptions( version, lib, defineComponent: { - alias: options?.defineComponent?.alias ?? ['defineComponent'], + alias: + options?.defineComponent?.alias ?? + [ + 'defineComponent', + lib === 'vue/vapor' ? 'defineVaporComponent' : '', + ].filter(Boolean), }, defineModel: { alias: options?.defineModel?.alias ?? ['defineModel'] }, defineSlots: { alias: options?.defineSlots?.alias ?? ['defineSlots'] }, diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index fec774dd0..6ed9142ea 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -21,7 +21,12 @@ const plugin: PluginReturn = const lib = userOptions.lib ?? 'vue' const macros = { defineComponent: { - alias: userOptions.defineComponent?.alias ?? ['defineComponent'], + alias: + userOptions.defineComponent?.alias ?? + [ + 'defineComponent', + lib === 'vue/vapor' ? 'defineVaporComponent' : '', + ].filter(Boolean), }, defineModel: { alias: userOptions.defineModel?.alias ?? ['defineModel'], diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index 9f8ffd8c3..505ade07e 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -2,9 +2,13 @@ import { HELPER_PREFIX } from '@vue-macros/common' import type { TransformOptions } from '.' export function getGlobalTypes(options: TransformOptions): string { + const defineComponent = options.defineComponent.alias.map( + (alias) => + `declare function ${HELPER_PREFIX}${alias} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T;\n`, + ) return ` const { defineModel${options.defineModel.alias[0] !== 'defineModel' ? `: ${options.defineModel.alias[0]}` : ''} } = await import('vue') -declare function ${HELPER_PREFIX}${options.defineComponent.alias[0]} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T; +${defineComponent} declare function ${options.defineSlots.alias[0]}>(): Partial; declare function ${options.defineSlots.alias[0]}>(slots: T): T; declare function ${options.defineExpose.alias[0]} = Record>(exposed?: Exposed): Exposed; From 36daec144f759062ec6c988bc715758e02022b69 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 10:15:00 +0800 Subject: [PATCH 128/156] fix: global-types --- packages/volar/src/jsx-macros/global-types.ts | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index 505ade07e..d3fbe095f 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -2,17 +2,41 @@ import { HELPER_PREFIX } from '@vue-macros/common' import type { TransformOptions } from '.' export function getGlobalTypes(options: TransformOptions): string { - const defineComponent = options.defineComponent.alias.map( - (alias) => - `declare function ${HELPER_PREFIX}${alias} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T;\n`, - ) + const defineComponent = options.defineComponent.alias + .map( + (alias) => + `declare function ${HELPER_PREFIX}${alias} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T;\n`, + ) + .join('') + const defineSlots = options.defineSlots.alias + .flatMap((alias) => [ + `declare function ${alias} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T;\n`, + `declare function ${alias}>(slots: T): T;\n`, + ]) + .join('') + const defineExpose = options.defineExpose.alias + .map( + (alias) => + `declare function ${alias} = Record>(exposed?: Exposed): Exposed;`, + ) + .join('') + const defineStyle = options.defineStyle.alias + .map( + (alias) => + `declare const ${alias}: { (...args: ${HELPER_PREFIX}StyleArgs): T; scss: (...args: ${HELPER_PREFIX}StyleArgs)=> T; sass: (...args: ${HELPER_PREFIX}StyleArgs)=> T; stylus: (...args: ${HELPER_PREFIX}StyleArgs)=> T; less: (...args: ${HELPER_PREFIX}StyleArgs)=> T; postcss: (...args: ${HELPER_PREFIX}StyleArgs)=> T };\n`, + ) + .join('') + const defineModel = options.defineModel.alias + .map((alias) => + alias === 'defineModel' ? 'defineModel' : `defineModel: ${alias}`, + ) + .join(', ') return ` -const { defineModel${options.defineModel.alias[0] !== 'defineModel' ? `: ${options.defineModel.alias[0]}` : ''} } = await import('vue') +const { ${defineModel} } = await import('vue') ${defineComponent} -declare function ${options.defineSlots.alias[0]}>(): Partial; -declare function ${options.defineSlots.alias[0]}>(slots: T): T; -declare function ${options.defineExpose.alias[0]} = Record>(exposed?: Exposed): Exposed; -declare const ${options.defineStyle.alias[0]}: { (...args: ${HELPER_PREFIX}StyleArgs): T; scss: (...args: ${HELPER_PREFIX}StyleArgs)=> T; sass: (...args: ${HELPER_PREFIX}StyleArgs)=> T; stylus: (...args: ${HELPER_PREFIX}StyleArgs)=> T; less: (...args: ${HELPER_PREFIX}StyleArgs)=> T; postcss: (...args: ${HELPER_PREFIX}StyleArgs)=> T }; +${defineSlots} +${defineExpose} +${defineStyle} type ${HELPER_PREFIX}StyleArgs = [style: string, options?: { scoped?: boolean }]; type ${HELPER_PREFIX}PrettifyLocal = { [K in keyof T]: T[K]; } & {}; type __VLS_IsAny = 0 extends 1 & T ? true : false; From 8081d02e198b950f3ce668446ddf1de1dd879843 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 10:35:36 +0800 Subject: [PATCH 129/156] fix: mono --- packages/jsx-macros/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 777b5b3fc..3a4650637 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,7 +1,7 @@ { "name": "@vue-macros/jsx-macros", "version": "0.0.0", - "packageManager": "pnpm@10.0.0", + "packageManager": "pnpm@10.4.1", "description": "jsxMacros feature from Vue Macros.", "type": "module", "keywords": [ From 7c5fb91e56b11577f5a2c9e2b330d18faba29441 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 10:43:35 +0800 Subject: [PATCH 130/156] fix: test --- packages/jsx/package.json | 2 +- .../jsx/tests/__snapshots__/fixtures.test.ts.snap | 4 ++-- packages/jsx/tests/fixtures.test.ts | 15 ++------------- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/packages/jsx/package.json b/packages/jsx/package.json index 17771193e..f6f1e1c08 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -1,7 +1,7 @@ { "name": "@vue-macros/jsx", "version": "0.0.1", - "packageManager": "pnpm@10.0.0", + "packageManager": "pnpm@10.4.1", "description": "jsx feature from Vue Macros.", "type": "module", "keywords": [ diff --git a/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap b/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap index 469e2fdc3..a39a39aa3 100644 --- a/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap +++ b/packages/jsx/tests/__snapshots__/fixtures.test.ts.snap @@ -2,11 +2,11 @@ exports[`fixtures > tests/fixtures/index.tsx 1`] = ` "// index.js -import { createVNode } from 'vue'; +import { createVNode, Fragment } from 'vue'; var index = () => { let foo = 1; - return foo === 1 ? createVNode("div", null, [foo]) : null; + return createVNode(Fragment, null, [foo === 1 ? createVNode("div", null, [foo]) : null]); }; export { index as default }; diff --git a/packages/jsx/tests/fixtures.test.ts b/packages/jsx/tests/fixtures.test.ts index cc94672ad..8f8f6cc2c 100644 --- a/packages/jsx/tests/fixtures.test.ts +++ b/packages/jsx/tests/fixtures.test.ts @@ -1,10 +1,5 @@ import { resolve } from 'node:path' -import { - rollupBuild, - RollupEsbuildPlugin, - RollupVueJsx, - testFixtures, -} from '@vue-macros/test-utils' +import { rollupBuild, RollupVueJsx, testFixtures } from '@vue-macros/test-utils' import { describe } from 'vitest' import VueJsxMacros from '../src/rollup' @@ -12,13 +7,7 @@ describe('fixtures', async () => { await testFixtures( ['tests/fixtures/**/*'], (_, id) => { - return rollupBuild(id, [ - VueJsxMacros(), - RollupVueJsx(), - RollupEsbuildPlugin({ - target: 'esnext', - }), - ]) + return rollupBuild(id, [VueJsxMacros(), RollupVueJsx()]) }, { cwd: resolve(__dirname, '..'), From fd47f4106c2f39a880e67c5fd4d777d3957abad7 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 10:51:47 +0800 Subject: [PATCH 131/156] fix: typo --- packages/volar/src/jsx-macros/global-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index d3fbe095f..9af7f5e74 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -10,7 +10,7 @@ export function getGlobalTypes(options: TransformOptions): string { .join('') const defineSlots = options.defineSlots.alias .flatMap((alias) => [ - `declare function ${alias} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T;\n`, + `declare function ${alias}>(): Partial;`, `declare function ${alias}>(slots: T): T;\n`, ]) .join('') From 5f9c92d42e4939c403def94da288ea2423709295 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 11:03:57 +0800 Subject: [PATCH 132/156] chore: add solid for lib --- docs/macros/jsx-macros.md | 2 +- docs/zh-CN/macros/jsx-macros.md | 2 +- packages/jsx-macros/src/core/plugin.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md index ef2929d05..73f2580df 100644 --- a/docs/macros/jsx-macros.md +++ b/docs/macros/jsx-macros.md @@ -19,7 +19,7 @@ interface Options { /** * @default 'vue' */ - lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | string } ``` diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md index 2e5001136..d95a8d469 100644 --- a/docs/zh-CN/macros/jsx-macros.md +++ b/docs/zh-CN/macros/jsx-macros.md @@ -19,7 +19,7 @@ interface Options { /** * @default 'vue' */ - lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | string } ``` diff --git a/packages/jsx-macros/src/core/plugin.ts b/packages/jsx-macros/src/core/plugin.ts index ffc0d6ce5..affaa9043 100644 --- a/packages/jsx-macros/src/core/plugin.ts +++ b/packages/jsx-macros/src/core/plugin.ts @@ -24,7 +24,7 @@ import { transformJsxMacros } from '.' import type { UnpluginContextMeta, UnpluginFactory } from 'unplugin' export type Options = BaseOptions & { - lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | (string & {}) defineComponent?: { alias: string[] } defineModel?: { alias: string[] } defineExpose?: { alias: string[] } From db6f929d1f5a02e07eec1412cd1c1a96e12c29ec Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 11:09:50 +0800 Subject: [PATCH 133/156] feat: add lib option --- packages/jsx/src/index.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index f8899d4f0..d20935c3d 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -10,13 +10,20 @@ import { export { defineConfig, resolveOptions, type Options } from '@vue-macros/config' -export type JSXOptions = Pick +export type JSXOptions = { + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | (string & {}) +} & Pick const name = generatePluginName() const plugin: UnpluginCombineInstance = createCombinePlugin((userOptions = {}, meta) => { userOptions.jsxMacros ??= true + userOptions.lib ??= 'vue' const options = resolveOptions(userOptions) + if (userOptions.lib) { + options.jsxDirective && (options.jsxDirective.lib ??= userOptions.lib) + options.jsxMacros && (options.jsxMacros.lib ??= userOptions.lib) + } const framework = meta.framework! From 1fc3e6a4b8a040a9fb0374898047c911bacdb9dd Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Thu, 27 Feb 2025 23:51:36 +0800 Subject: [PATCH 134/156] feat: add raw plugin --- eslint.config.ts | 1 + packages/jsx/package.json | 10 ++++++++++ packages/jsx/src/index.ts | 17 ++-------------- packages/jsx/src/options.ts | 38 ++++++++++++++++++++++++++++++++++++ packages/jsx/src/raw.ts | 25 ++++++++++++++++++++++++ packages/jsx/src/volar.ts | 26 ++++++++++++++++++++++-- packages/macros/src/volar.ts | 1 - packages/volar/package.json | 11 +---------- packages/volar/src/jsx.ts | 28 -------------------------- pnpm-lock.yaml | 8 +++++++- pnpm-workspace.yaml | 1 + 11 files changed, 109 insertions(+), 57 deletions(-) create mode 100644 packages/jsx/src/options.ts create mode 100644 packages/jsx/src/raw.ts delete mode 100644 packages/volar/src/jsx.ts diff --git a/eslint.config.ts b/eslint.config.ts index 7d6d4788d..c4ccdfe40 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -38,6 +38,7 @@ export default sxzz([ 'playground/vue3/**', 'packages/{volar,eslint-config}/**', '**/raw.ts', + '**/volar.ts', ], rules: { 'import/no-default-export': 'off', diff --git a/packages/jsx/package.json b/packages/jsx/package.json index f6f1e1c08..b5e5236d7 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -46,6 +46,11 @@ "require": "./dist/jsx-runtime.cjs", "import": "./dist/jsx-runtime.js" }, + "./raw": { + "dev": "./src/raw.ts", + "require": "./dist/raw.cjs", + "import": "./dist/raw.js" + }, "./rolldown": { "dev": "./src/rolldown.ts", "require": "./dist/rolldown.cjs", @@ -106,6 +111,10 @@ "require": "./dist/jsx-runtime.cjs", "import": "./dist/jsx-runtime.js" }, + "./raw": { + "require": "./dist/raw.cjs", + "import": "./dist/raw.js" + }, "./rolldown": { "require": "./dist/rolldown.cjs", "import": "./dist/rolldown.js" @@ -149,6 +158,7 @@ "@vue-macros/jsx-directive": "workspace:*", "@vue-macros/jsx-macros": "workspace:*", "@vue-macros/volar": "workspace:*", + "ts-macro": "catalog:", "unplugin-combine": "^1.2.0" }, "devDependencies": { diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index d20935c3d..c5b10d2da 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -1,4 +1,3 @@ -import { resolveOptions, type Options } from '@vue-macros/config' import VueJsxDirective from '@vue-macros/jsx-directive' import VueJsxMacros from '@vue-macros/jsx-macros' @@ -7,26 +6,14 @@ import { createCombinePlugin, type UnpluginCombineInstance, } from 'unplugin-combine' - -export { defineConfig, resolveOptions, type Options } from '@vue-macros/config' - -export type JSXOptions = { - lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | (string & {}) -} & Pick +import { resolveJSXOptions, type JSXOptions } from './options' const name = generatePluginName() const plugin: UnpluginCombineInstance = createCombinePlugin((userOptions = {}, meta) => { userOptions.jsxMacros ??= true - userOptions.lib ??= 'vue' - const options = resolveOptions(userOptions) - if (userOptions.lib) { - options.jsxDirective && (options.jsxDirective.lib ??= userOptions.lib) - options.jsxMacros && (options.jsxMacros.lib ??= userOptions.lib) - } - + const options = resolveJSXOptions(userOptions) const framework = meta.framework! - const plugins = [ options.jsxDirective ? VueJsxDirective[framework](options.jsxDirective) diff --git a/packages/jsx/src/options.ts b/packages/jsx/src/options.ts new file mode 100644 index 000000000..64fb5bccc --- /dev/null +++ b/packages/jsx/src/options.ts @@ -0,0 +1,38 @@ +import type { FilterOptions } from '@vue-macros/common' +import type { Options as OptionsJsxDirective } from '@vue-macros/jsx-directive' +import type { Options as OptionsJsxMacros } from '@vue-macros/jsx-macros' + +export type JSXOptions = { + lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | (string & {}) + jsxRef?: ResolvedJSXOptions['jsxRef'] | boolean + jsxMacros?: ResolvedJSXOptions['jsxMacros'] | boolean + jsxDirective?: ResolvedJSXOptions['jsxDirective'] | boolean +} + +export type ResolvedJSXOptions = { + jsxRef?: FilterOptions & { alias?: string[] } + jsxMacros?: OptionsJsxMacros + jsxDirective?: OptionsJsxDirective +} + +export function resolveJSXOptions( + options: JSXOptions = {}, +): ResolvedJSXOptions { + const resolveOptions: ResolvedJSXOptions = {} + if (options.jsxDirective !== false) + resolveOptions.jsxDirective = + options.jsxDirective === true ? {} : (resolveOptions.jsxDirective ?? {}) + if (options.jsxMacros !== false) + resolveOptions.jsxMacros = + options.jsxMacros === true ? {} : (resolveOptions.jsxMacros ?? {}) + if (options.jsxRef !== false) + resolveOptions.jsxRef = + options.jsxRef === true ? {} : (resolveOptions.jsxRef ?? {}) + + if (options.lib) { + resolveOptions.jsxDirective && + (resolveOptions.jsxDirective.lib ??= options.lib) + resolveOptions.jsxMacros && (resolveOptions.jsxMacros.lib ??= options.lib) + } + return resolveOptions +} diff --git a/packages/jsx/src/raw.ts b/packages/jsx/src/raw.ts new file mode 100644 index 000000000..22c9599cb --- /dev/null +++ b/packages/jsx/src/raw.ts @@ -0,0 +1,25 @@ +import VueJsxDirective from '@vue-macros/jsx-directive/raw' +import VueJsxMacros from '@vue-macros/jsx-macros/raw' + +import { resolveJSXOptions, type JSXOptions } from './options' +import type { UnpluginFactory } from 'unplugin' + +export { defineConfig, resolveOptions, type Options } from '@vue-macros/config' + +const plugin: UnpluginFactory = ( + userOptions = {}, + meta, +) => { + const options = resolveJSXOptions(userOptions) + + return [ + options.jsxDirective + ? VueJsxDirective(options.jsxDirective, meta) + : undefined, + options.jsxMacros ? VueJsxMacros(options.jsxMacros, meta) : undefined, + ] + .flatMap((plugin) => plugin) + .filter((plugin) => !!plugin) +} + +export default plugin diff --git a/packages/jsx/src/volar.ts b/packages/jsx/src/volar.ts index 01218877d..7d54e2b4a 100644 --- a/packages/jsx/src/volar.ts +++ b/packages/jsx/src/volar.ts @@ -1,2 +1,24 @@ -// eslint-disable-next-line import/no-default-export -export { default } from '@vue-macros/volar/jsx' +import jsxDirective from '@vue-macros/volar/jsx-directive' +import jsxMacros from '@vue-macros/volar/jsx-macros' +import jsxRef from '@vue-macros/volar/jsx-ref' +import { createPlugin, type PluginReturn } from 'ts-macro' +import { resolveJSXOptions, type JSXOptions } from './options' + +const jsxPlugins = { + jsxDirective, + jsxMacros, + jsxRef, +} + +const plugin: PluginReturn = createPlugin( + (ctx, userOptions) => { + const options = resolveJSXOptions(userOptions) + return Object.entries(jsxPlugins).flatMap(([name, plugin]) => { + const subOptions = options[name as keyof typeof options] + if (!subOptions) return [] + return plugin(subOptions)(ctx) + }) + }, +) + +export default plugin diff --git a/packages/macros/src/volar.ts b/packages/macros/src/volar.ts index 2db3a7fb7..9dafe6cd6 100644 --- a/packages/macros/src/volar.ts +++ b/packages/macros/src/volar.ts @@ -1,2 +1 @@ -// eslint-disable-next-line import/no-default-export export { default } from '@vue-macros/volar' diff --git a/packages/volar/package.json b/packages/volar/package.json index 25663f4ab..616dcbc2a 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -102,11 +102,6 @@ "require": "./dist/export-render.js", "import": "./dist/export-render.mjs" }, - "./jsx": { - "dev": "./src/jsx.ts", - "require": "./dist/jsx.js", - "import": "./dist/jsx.mjs" - }, "./jsx-directive": { "dev": "./src/jsx-directive.ts", "require": "./dist/jsx-directive.js", @@ -229,10 +224,6 @@ "require": "./dist/export-render.js", "import": "./dist/export-render.mjs" }, - "./jsx": { - "require": "./dist/jsx.js", - "import": "./dist/jsx.mjs" - }, "./jsx-directive": { "require": "./dist/jsx-directive.js", "import": "./dist/jsx-directive.mjs" @@ -300,7 +291,7 @@ "@vue/compiler-dom": "catalog:", "@vue/language-core": "catalog:", "muggle-string": "^0.4.1", - "ts-macro": "^0.1.17" + "ts-macro": "catalog:" }, "devDependencies": { "typescript": "catalog:", diff --git a/packages/volar/src/jsx.ts b/packages/volar/src/jsx.ts deleted file mode 100644 index c32b87d09..000000000 --- a/packages/volar/src/jsx.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { createPlugin, type PluginReturn } from 'ts-macro' -import jsxDirective from './jsx-directive' -import jsxMacros from './jsx-macros' -import jsxRef from './jsx-ref' -import type { Options } from '@vue-macros/config' - -const jsxPlugins = { - jsxDirective, - jsxMacros, - jsxRef, -} - -type JSXOptions = { - jsxDirective?: Options['jsxDirective'] - jsxMacros?: Options['jsxMacros'] - jsxRef?: Options['jsxRef'] -} - -const plugin: PluginReturn = createPlugin( - (ctx, userOptions) => - Object.entries(jsxPlugins).flatMap(([name, plugin]) => { - const options = userOptions?.[name as keyof JSXOptions] ?? ({} as any) - if (!options) return [] - return plugin(options === true ? {} : options)(ctx) - }), -) - -export default plugin diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bafa63e8..5067cbfa5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ catalogs: rollup: specifier: ^4.34.8 version: 4.34.8 + ts-macro: + specifier: ^0.1.17 + version: 0.1.17 typescript: specifier: ^5.7.3 version: 5.7.3 @@ -734,6 +737,9 @@ importers: '@vue-macros/volar': specifier: workspace:* version: link:../volar + ts-macro: + specifier: 'catalog:' + version: 0.1.17(rollup@4.34.8)(typescript@5.7.3) unplugin-combine: specifier: ^1.2.0 version: 1.2.0(@rspack/core@1.2.5(@swc/helpers@0.5.15))(esbuild@0.25.0)(rolldown@1.0.0-beta.3(@babel/runtime@7.26.9)(typescript@5.7.3))(rollup@4.34.8)(unplugin@2.2.0)(vite@6.1.1(@types/node@22.13.4)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(webpack@5.98.0(esbuild@0.25.0)) @@ -1097,7 +1103,7 @@ importers: specifier: ^0.4.1 version: 0.4.1 ts-macro: - specifier: ^0.1.17 + specifier: 'catalog:' version: 0.1.17(rollup@4.34.8)(typescript@5.7.3) devDependencies: typescript: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 20dbac604..10543e13f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -60,6 +60,7 @@ catalog: vite: ^6.1.1 vite-plugin-stylex: ^0.13.0 vitepress: ^2.0.0-alpha.2 + ts-macro: ^0.1.17 packages: - packages/* From 6134e03a1d532e3d0d18e174351e22207e120761 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 08:37:28 +0800 Subject: [PATCH 135/156] fix: lint --- pnpm-workspace.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 10543e13f..69208c4a2 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -53,6 +53,8 @@ catalog: magic-string: ^0.30.17 prettier: ^3.5.1 rollup: ^4.34.8 + ts-macro: ^0.1.17 + typescript: ^5.7.3 unplugin: ^1.16.1 unplugin-oxc: ^0.2.4 @@ -60,8 +62,6 @@ catalog: vite: ^6.1.1 vite-plugin-stylex: ^0.13.0 vitepress: ^2.0.0-alpha.2 - ts-macro: ^0.1.17 - packages: - packages/* - playground/* From 273629ae3d13715c59853a2b9dbb3a384ba2a100 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 08:52:03 +0800 Subject: [PATCH 136/156] refactor: remove jsx prefix for options --- packages/jsx/src/index.ts | 13 +++++-------- packages/jsx/src/options.ts | 34 ++++++++++++++++------------------ packages/jsx/src/raw.ts | 10 ++++------ 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index c5b10d2da..a64fd42b1 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -1,5 +1,5 @@ -import VueJsxDirective from '@vue-macros/jsx-directive' -import VueJsxMacros from '@vue-macros/jsx-macros' +import jsxDirective from '@vue-macros/jsx-directive' +import jsxMacros from '@vue-macros/jsx-macros' import { generatePluginName } from '#macros' with { type: 'macro' } import { @@ -11,16 +11,13 @@ import { resolveJSXOptions, type JSXOptions } from './options' const name = generatePluginName() const plugin: UnpluginCombineInstance = createCombinePlugin((userOptions = {}, meta) => { - userOptions.jsxMacros ??= true const options = resolveJSXOptions(userOptions) const framework = meta.framework! const plugins = [ - options.jsxDirective - ? VueJsxDirective[framework](options.jsxDirective) - : undefined, - options.jsxMacros - ? VueJsxMacros[framework](options.jsxMacros) + options.directive + ? jsxDirective[framework](options.directive) : undefined, + options.macros ? jsxMacros[framework](options.macros) : undefined, ].filter((plugin) => !!plugin) return { diff --git a/packages/jsx/src/options.ts b/packages/jsx/src/options.ts index 64fb5bccc..dc08eee67 100644 --- a/packages/jsx/src/options.ts +++ b/packages/jsx/src/options.ts @@ -4,35 +4,33 @@ import type { Options as OptionsJsxMacros } from '@vue-macros/jsx-macros' export type JSXOptions = { lib?: 'vue' | 'vue/vapor' | 'react' | 'preact' | 'solid' | (string & {}) - jsxRef?: ResolvedJSXOptions['jsxRef'] | boolean - jsxMacros?: ResolvedJSXOptions['jsxMacros'] | boolean - jsxDirective?: ResolvedJSXOptions['jsxDirective'] | boolean + ref?: ResolvedJSXOptions['ref'] | boolean + macros?: ResolvedJSXOptions['macros'] | boolean + directive?: ResolvedJSXOptions['directive'] | boolean } export type ResolvedJSXOptions = { - jsxRef?: FilterOptions & { alias?: string[] } - jsxMacros?: OptionsJsxMacros - jsxDirective?: OptionsJsxDirective + ref?: FilterOptions & { alias?: string[] } + macros?: OptionsJsxMacros + directive?: OptionsJsxDirective } export function resolveJSXOptions( options: JSXOptions = {}, ): ResolvedJSXOptions { const resolveOptions: ResolvedJSXOptions = {} - if (options.jsxDirective !== false) - resolveOptions.jsxDirective = - options.jsxDirective === true ? {} : (resolveOptions.jsxDirective ?? {}) - if (options.jsxMacros !== false) - resolveOptions.jsxMacros = - options.jsxMacros === true ? {} : (resolveOptions.jsxMacros ?? {}) - if (options.jsxRef !== false) - resolveOptions.jsxRef = - options.jsxRef === true ? {} : (resolveOptions.jsxRef ?? {}) + if (options.directive !== false) + resolveOptions.directive = + options.directive === true ? {} : (resolveOptions.directive ?? {}) + if (options.macros !== false) + resolveOptions.macros = + options.macros === true ? {} : (resolveOptions.macros ?? {}) + if (options.ref !== false) + resolveOptions.ref = options.ref === true ? {} : (resolveOptions.ref ?? {}) if (options.lib) { - resolveOptions.jsxDirective && - (resolveOptions.jsxDirective.lib ??= options.lib) - resolveOptions.jsxMacros && (resolveOptions.jsxMacros.lib ??= options.lib) + resolveOptions.directive && (resolveOptions.directive.lib ??= options.lib) + resolveOptions.macros && (resolveOptions.macros.lib ??= options.lib) } return resolveOptions } diff --git a/packages/jsx/src/raw.ts b/packages/jsx/src/raw.ts index 22c9599cb..3b75ade99 100644 --- a/packages/jsx/src/raw.ts +++ b/packages/jsx/src/raw.ts @@ -1,5 +1,5 @@ -import VueJsxDirective from '@vue-macros/jsx-directive/raw' -import VueJsxMacros from '@vue-macros/jsx-macros/raw' +import jsxDirective from '@vue-macros/jsx-directive/raw' +import jsxMacros from '@vue-macros/jsx-macros/raw' import { resolveJSXOptions, type JSXOptions } from './options' import type { UnpluginFactory } from 'unplugin' @@ -13,10 +13,8 @@ const plugin: UnpluginFactory = ( const options = resolveJSXOptions(userOptions) return [ - options.jsxDirective - ? VueJsxDirective(options.jsxDirective, meta) - : undefined, - options.jsxMacros ? VueJsxMacros(options.jsxMacros, meta) : undefined, + options.directive ? jsxDirective(options.directive, meta) : undefined, + options.macros ? jsxMacros(options.macros, meta) : undefined, ] .flatMap((plugin) => plugin) .filter((plugin) => !!plugin) From 59fa7d7519a61935c6ee990f509d2af7d7b58a63 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 08:59:48 +0800 Subject: [PATCH 137/156] fix: typecheck --- packages/jsx/package.json | 2 +- pnpm-lock.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jsx/package.json b/packages/jsx/package.json index b5e5236d7..58e9589ca 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -154,7 +154,7 @@ "vue": "^2.7.0 || ^3.2.25" }, "dependencies": { - "@vue-macros/config": "workspace:*", + "@vue-macros/common": "workspace:*", "@vue-macros/jsx-directive": "workspace:*", "@vue-macros/jsx-macros": "workspace:*", "@vue-macros/volar": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5067cbfa5..d707472a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -725,9 +725,9 @@ importers: packages/jsx: dependencies: - '@vue-macros/config': + '@vue-macros/common': specifier: workspace:* - version: link:../config + version: link:../common '@vue-macros/jsx-directive': specifier: workspace:* version: link:../jsx-directive From 97418fc9f0a8944cabbb3955ca2ba6990cc0dd7c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 10:20:31 +0800 Subject: [PATCH 138/156] fix: mono --- packages/jsx/src/{ => core}/options.ts | 0 packages/jsx/src/index.ts | 17 +++++++++-------- packages/jsx/src/raw.ts | 17 ++++++++--------- packages/jsx/src/volar.ts | 20 +++++++++----------- 4 files changed, 26 insertions(+), 28 deletions(-) rename packages/jsx/src/{ => core}/options.ts (100%) diff --git a/packages/jsx/src/options.ts b/packages/jsx/src/core/options.ts similarity index 100% rename from packages/jsx/src/options.ts rename to packages/jsx/src/core/options.ts diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index a64fd42b1..5e177d86b 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -6,19 +6,20 @@ import { createCombinePlugin, type UnpluginCombineInstance, } from 'unplugin-combine' -import { resolveJSXOptions, type JSXOptions } from './options' +import { resolveJSXOptions, type JSXOptions } from './core/options' + +const jsxPlugins = [ + ['directive', jsxDirective], + ['macros', jsxMacros], +] as const const name = generatePluginName() const plugin: UnpluginCombineInstance = createCombinePlugin((userOptions = {}, meta) => { const options = resolveJSXOptions(userOptions) - const framework = meta.framework! - const plugins = [ - options.directive - ? jsxDirective[framework](options.directive) - : undefined, - options.macros ? jsxMacros[framework](options.macros) : undefined, - ].filter((plugin) => !!plugin) + const plugins = jsxPlugins.flatMap(([name, plugin]) => + options[name] ? plugin[meta.framework!](options[name]) : [], + ) return { name, diff --git a/packages/jsx/src/raw.ts b/packages/jsx/src/raw.ts index 3b75ade99..f7e22dce0 100644 --- a/packages/jsx/src/raw.ts +++ b/packages/jsx/src/raw.ts @@ -1,23 +1,22 @@ import jsxDirective from '@vue-macros/jsx-directive/raw' import jsxMacros from '@vue-macros/jsx-macros/raw' -import { resolveJSXOptions, type JSXOptions } from './options' +import { resolveJSXOptions, type JSXOptions } from './core/options' import type { UnpluginFactory } from 'unplugin' -export { defineConfig, resolveOptions, type Options } from '@vue-macros/config' +const jsxPlugins = [ + ['directive', jsxDirective], + ['macros', jsxMacros], +] as const const plugin: UnpluginFactory = ( userOptions = {}, meta, ) => { const options = resolveJSXOptions(userOptions) - - return [ - options.directive ? jsxDirective(options.directive, meta) : undefined, - options.macros ? jsxMacros(options.macros, meta) : undefined, - ] - .flatMap((plugin) => plugin) - .filter((plugin) => !!plugin) + return jsxPlugins.flatMap(([name, plugin]) => + options[name] ? plugin(options[name], meta) : [], + ) } export default plugin diff --git a/packages/jsx/src/volar.ts b/packages/jsx/src/volar.ts index 7d54e2b4a..a8858de86 100644 --- a/packages/jsx/src/volar.ts +++ b/packages/jsx/src/volar.ts @@ -2,22 +2,20 @@ import jsxDirective from '@vue-macros/volar/jsx-directive' import jsxMacros from '@vue-macros/volar/jsx-macros' import jsxRef from '@vue-macros/volar/jsx-ref' import { createPlugin, type PluginReturn } from 'ts-macro' -import { resolveJSXOptions, type JSXOptions } from './options' +import { resolveJSXOptions, type JSXOptions } from './core/options' -const jsxPlugins = { - jsxDirective, - jsxMacros, - jsxRef, -} +const jsxPlugins = [ + ['directive', jsxDirective], + ['macros', jsxMacros], + ['ref', jsxRef], +] as const const plugin: PluginReturn = createPlugin( (ctx, userOptions) => { const options = resolveJSXOptions(userOptions) - return Object.entries(jsxPlugins).flatMap(([name, plugin]) => { - const subOptions = options[name as keyof typeof options] - if (!subOptions) return [] - return plugin(subOptions)(ctx) - }) + return jsxPlugins.flatMap(([name, plugin]) => + options[name] ? plugin(options[name])(ctx) : [], + ) }, ) From 59ee1c6d10df0f815e8c1fef0a850e861096a095 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 13:53:09 +0800 Subject: [PATCH 139/156] feat: prevent auto import defineComponent --- packages/jsx-macros/src/core/common.ts | 52 ------------------- .../src/core/define-component/index.ts | 10 +++- .../volar/src/jsx-macros/define-component.ts | 38 ++++++++++++++ packages/volar/src/jsx-macros/global-types.ts | 17 +++--- packages/volar/src/jsx-macros/index.ts | 9 +--- .../vue3/src/examples/jsx-macros/comp.tsx | 2 +- .../vue3/src/examples/jsx-macros/index.tsx | 2 +- 7 files changed, 59 insertions(+), 71 deletions(-) delete mode 100644 packages/jsx-macros/src/core/common.ts create mode 100644 packages/volar/src/jsx-macros/define-component.ts diff --git a/packages/jsx-macros/src/core/common.ts b/packages/jsx-macros/src/core/common.ts deleted file mode 100644 index 5c783a92d..000000000 --- a/packages/jsx-macros/src/core/common.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { Program } from '@babel/types' -import type { MagicString } from 'vue/compiler-sfc' - -const importedMap = new WeakMap>() -export function importHelper({ - s, - ast, - local, - as = local, - isDefault, - from = 'vue', - offset = 0, -}: { - s: MagicString - ast: Program - local: string - as?: string - isDefault?: boolean - from?: string - offset?: number -}): string { - let hasBeenImported = false - ast.body.forEach((node) => { - if (node.type === 'ImportDeclaration' && node.source.value === from) { - for (const specifier of node.specifiers) { - if (specifier.local.name === as) { - hasBeenImported = true - break - } - } - } - }) - if (hasBeenImported) return as - - const imported = isDefault ? 'default' : local - const cacheKey = `${from}@${imported}` - if (!importedMap.get(s)?.has(cacheKey)) { - s.appendLeft( - offset, - `\nimport ${ - isDefault ? as : `{ ${imported}${as !== local ? ` as ${as}` : ''} }` - } from ${JSON.stringify(from)};`, - ) - if (!importedMap.has(s)) { - importedMap.set(s, new Set([cacheKey])) - } else { - importedMap.get(s)!.add(cacheKey) - } - } - - return as -} diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 1eb95938a..f985f4b8c 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,7 +1,6 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { restructure } from '@vue-macros/jsx-directive/api' import { walkIdentifiers } from '@vue/compiler-core' -import { importHelper } from '../common' import { withDefaultsHelperId } from '../helper' import type { FunctionalNode, RootMapValue } from '..' import type { OptionsResolved } from '../..' @@ -18,7 +17,14 @@ export function transformDefineComponent( options: OptionsResolved, ): void { if (!map.defineComponent) return - importHelper({ s, ast, local: options.defineComponent.alias[0] }) + + const defineComponentName = s.sliceNode(map.defineComponent.callee) + if ( + defineComponentName && + !['defineComponent', 'defineVaporComponent'].includes(defineComponentName) + ) { + importHelperFn(s, 0, 'defineComponent', 'vue', false, defineComponentName) + } let hasRestProp = false const props: Record = {} diff --git a/packages/volar/src/jsx-macros/define-component.ts b/packages/volar/src/jsx-macros/define-component.ts new file mode 100644 index 000000000..c8f2c2609 --- /dev/null +++ b/packages/volar/src/jsx-macros/define-component.ts @@ -0,0 +1,38 @@ +import { replaceSourceRange } from 'muggle-string' +import { allCodeFeatures } from 'ts-macro' +import { getStart, getText } from '../common' +import type { TransformOptions } from '.' + +export function transformDefineComponent( + node: import('typescript').CallExpression, + options: TransformOptions, +): void { + const { codes, source } = options + + replaceSourceRange(codes, source, node.arguments[0].end, node.end - 1) + + const componentOptions = node.arguments[1] + replaceSourceRange( + codes, + source, + getStart(node, options), + node.expression.end + 1, + '(', + [ + getText(node.expression, options), + source, + getStart(node, options), + allCodeFeatures, + ], + '(() => ({}) as any, ', + componentOptions + ? [ + getText(componentOptions, options), + source, + getStart(componentOptions, options), + allCodeFeatures, + ] + : '', + '), ', + ) +} diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index 9af7f5e74..ffabb1a76 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -2,12 +2,6 @@ import { HELPER_PREFIX } from '@vue-macros/common' import type { TransformOptions } from '.' export function getGlobalTypes(options: TransformOptions): string { - const defineComponent = options.defineComponent.alias - .map( - (alias) => - `declare function ${HELPER_PREFIX}${alias} any)>(setup: T, options?: Pick & { props?: import('vue').ComponentObjectPropsOptions }): T;\n`, - ) - .join('') const defineSlots = options.defineSlots.alias .flatMap((alias) => [ `declare function ${alias}>(): Partial;`, @@ -31,9 +25,16 @@ export function getGlobalTypes(options: TransformOptions): string { alias === 'defineModel' ? 'defineModel' : `defineModel: ${alias}`, ) .join(', ') + const defineComponent = options.defineComponent.alias + .map((alias) => + ['defineComponent', 'defineVaporComponent'].includes(alias) + ? '' + : `defineComponent: ${alias}`, + ) + .filter(Boolean) + .join(', ') return ` -const { ${defineModel} } = await import('vue') -${defineComponent} +const { ${defineModel}, ${defineComponent} } = await import('vue') ${defineSlots} ${defineExpose} ${defineStyle} diff --git a/packages/volar/src/jsx-macros/index.ts b/packages/volar/src/jsx-macros/index.ts index 726dba52b..379e60bdf 100644 --- a/packages/volar/src/jsx-macros/index.ts +++ b/packages/volar/src/jsx-macros/index.ts @@ -6,6 +6,7 @@ import { import { toValidAssetId } from '@vue/compiler-dom' import { replaceSourceRange } from 'muggle-string' import { getStart, getText } from '../common' +import { transformDefineComponent } from './define-component' import type { OptionsResolved } from '@vue-macros/config' import type { TsmVirtualCode } from 'ts-macro' @@ -155,13 +156,7 @@ export function getRootMap(options: TransformOptions): RootMap { if (!rootMap.has(root)) rootMap.set(root, {}) if (!rootMap.get(root)!.defineComponent) { rootMap.get(root)!.defineComponent = true - replaceSourceRange( - codes, - source, - getStart(parents[2], options), - getStart(parents[2], options), - HELPER_PREFIX, - ) + transformDefineComponent(parents[2], options) } } diff --git a/playground/vue3/src/examples/jsx-macros/comp.tsx b/playground/vue3/src/examples/jsx-macros/comp.tsx index 44ab6afb6..4ca8abe40 100644 --- a/playground/vue3/src/examples/jsx-macros/comp.tsx +++ b/playground/vue3/src/examples/jsx-macros/comp.tsx @@ -1,4 +1,4 @@ -import { ref, watch } from 'vue' +import { defineComponent, ref, watch } from 'vue' export const Comp = defineComponent(function ({ foo }: { foo: T }) { const slots = defineSlots({ diff --git a/playground/vue3/src/examples/jsx-macros/index.tsx b/playground/vue3/src/examples/jsx-macros/index.tsx index 42e2e0c5e..2ad5fe9ef 100644 --- a/playground/vue3/src/examples/jsx-macros/index.tsx +++ b/playground/vue3/src/examples/jsx-macros/index.tsx @@ -1,6 +1,6 @@ import { expectTypeOf } from 'expect-type' import { useRef } from 'unplugin-vue-macros/runtime' -import { ref } from 'vue' +import { defineComponent, ref } from 'vue' import { Comp } from './comp' export default defineComponent(() => { From 22e745cd62303bb043928e30afd2b287c78e9cc8 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 14:10:13 +0800 Subject: [PATCH 140/156] fix: unshift global-type --- packages/volar/src/jsx-macros.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index 6ed9142ea..cf6e8f4d8 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -57,7 +57,7 @@ const plugin: PluginReturn = const rootMap = getRootMap(options) if (rootMap.size) { transformJsxMacros(rootMap, options) - codes.push(getGlobalTypes(options)) + codes.unshift(getGlobalTypes(options)) } }, } From 08fc3c71f25d141f3215d829e33ae750b45fc222 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 28 Feb 2025 14:11:03 +0800 Subject: [PATCH 141/156] fix: typo --- packages/jsx/src/core/options.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jsx/src/core/options.ts b/packages/jsx/src/core/options.ts index dc08eee67..163055b89 100644 --- a/packages/jsx/src/core/options.ts +++ b/packages/jsx/src/core/options.ts @@ -21,12 +21,12 @@ export function resolveJSXOptions( const resolveOptions: ResolvedJSXOptions = {} if (options.directive !== false) resolveOptions.directive = - options.directive === true ? {} : (resolveOptions.directive ?? {}) + options.directive === true ? {} : (options.directive ?? {}) if (options.macros !== false) resolveOptions.macros = - options.macros === true ? {} : (resolveOptions.macros ?? {}) + options.macros === true ? {} : (options.macros ?? {}) if (options.ref !== false) - resolveOptions.ref = options.ref === true ? {} : (resolveOptions.ref ?? {}) + resolveOptions.ref = options.ref === true ? {} : (options.ref ?? {}) if (options.lib) { resolveOptions.directive && (resolveOptions.directive.lib ??= options.lib) From 78481c8b9525fcf8e1089865ed6e0501458253dc Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 15:41:47 +0800 Subject: [PATCH 142/156] chore: use compiler-dom instead of compiler-core --- packages/jsx-macros/package.json | 2 +- packages/jsx-macros/src/core/define-component/await.ts | 2 +- packages/jsx-macros/src/core/define-component/index.ts | 2 +- pnpm-lock.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 3a4650637..973f76c03 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -142,7 +142,7 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue-macros/jsx-directive": "workspace:*", - "@vue/compiler-core": "catalog:", + "@vue/compiler-dom": "catalog:", "hash-sum": "^2.0.0", "unplugin": "catalog:" }, diff --git a/packages/jsx-macros/src/core/define-component/await.ts b/packages/jsx-macros/src/core/define-component/await.ts index f9f1dcd78..584e768ea 100644 --- a/packages/jsx-macros/src/core/define-component/await.ts +++ b/packages/jsx-macros/src/core/define-component/await.ts @@ -5,7 +5,7 @@ import { walkAST, type MagicStringAST, } from '@vue-macros/common' -import { isFunctionType } from '@vue/compiler-core' +import { isFunctionType } from '@vue/compiler-dom' import type { FunctionalNode } from '..' import type { AwaitExpression, Node, Statement } from '@babel/types' diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index f985f4b8c..e5e8b9a8d 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -1,6 +1,6 @@ import { importHelperFn, type MagicStringAST } from '@vue-macros/common' import { restructure } from '@vue-macros/jsx-directive/api' -import { walkIdentifiers } from '@vue/compiler-core' +import { walkIdentifiers } from '@vue/compiler-dom' import { withDefaultsHelperId } from '../helper' import type { FunctionalNode, RootMapValue } from '..' import type { OptionsResolved } from '../..' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83cc63ed6..e05ab5595 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -743,7 +743,7 @@ importers: '@vue-macros/jsx-directive': specifier: workspace:* version: link:../jsx-directive - '@vue/compiler-core': + '@vue/compiler-dom': specifier: 'catalog:' version: 3.5.13 hash-sum: From ca7221adf079a0ab1aa0ef6fd4a4d57e340e1d2f Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 15:50:47 +0800 Subject: [PATCH 143/156] fix: build --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e87b88ef0..6f3d5e68e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -756,7 +756,7 @@ importers: version: 1.0.2 vue: specifier: 'catalog:' - version: 3.5.13(typescript@5.7.3) + version: 3.5.13(typescript@5.8.2) packages/macros: dependencies: From 64d3a5e2b73dd1dc50e12772358ee405556bb9ce Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 15:52:29 +0800 Subject: [PATCH 144/156] fix: mono --- packages/jsx-macros/package.json | 81 +++++++++----------------------- 1 file changed, 23 insertions(+), 58 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 973f76c03..f5b9a7efa 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,6 +1,6 @@ { "name": "@vue-macros/jsx-macros", - "version": "0.0.0", + "version": "3.0.0-beta.2", "packageManager": "pnpm@10.4.1", "description": "jsxMacros feature from Vue Macros.", "type": "module", @@ -31,54 +31,45 @@ "files": [ "dist" ], - "main": "dist/index.cjs", + "main": "dist/index.js", "module": "dist/index.js", "types": "dist/index.d.ts", "exports": { ".": { "dev": "./src/index.ts", - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "default": "./dist/index.js" }, "./api": { "dev": "./src/api.ts", - "require": "./dist/api.cjs", - "import": "./dist/api.js" + "default": "./dist/api.js" }, "./esbuild": { "dev": "./src/esbuild.ts", - "require": "./dist/esbuild.cjs", - "import": "./dist/esbuild.js" + "default": "./dist/esbuild.js" }, "./raw": { "dev": "./src/raw.ts", - "require": "./dist/raw.cjs", - "import": "./dist/raw.js" + "default": "./dist/raw.js" }, "./rolldown": { "dev": "./src/rolldown.ts", - "require": "./dist/rolldown.cjs", - "import": "./dist/rolldown.js" + "default": "./dist/rolldown.js" }, "./rollup": { "dev": "./src/rollup.ts", - "require": "./dist/rollup.cjs", - "import": "./dist/rollup.js" + "default": "./dist/rollup.js" }, "./rspack": { "dev": "./src/rspack.ts", - "require": "./dist/rspack.cjs", - "import": "./dist/rspack.js" + "default": "./dist/rspack.js" }, "./vite": { "dev": "./src/vite.ts", - "require": "./dist/vite.cjs", - "import": "./dist/vite.js" + "default": "./dist/vite.js" }, "./webpack": { "dev": "./src/webpack.ts", - "require": "./dist/webpack.cjs", - "import": "./dist/webpack.js" + "default": "./dist/webpack.js" }, "./*": "./*" }, @@ -93,44 +84,18 @@ "publishConfig": { "access": "public", "exports": { - ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" - }, - "./api": { - "require": "./dist/api.cjs", - "import": "./dist/api.js" - }, - "./esbuild": { - "require": "./dist/esbuild.cjs", - "import": "./dist/esbuild.js" - }, - "./raw": { - "require": "./dist/raw.cjs", - "import": "./dist/raw.js" - }, - "./rolldown": { - "require": "./dist/rolldown.cjs", - "import": "./dist/rolldown.js" - }, - "./rollup": { - "require": "./dist/rollup.cjs", - "import": "./dist/rollup.js" - }, - "./rspack": { - "require": "./dist/rspack.cjs", - "import": "./dist/rspack.js" - }, - "./vite": { - "require": "./dist/vite.cjs", - "import": "./dist/vite.js" - }, - "./webpack": { - "require": "./dist/webpack.cjs", - "import": "./dist/webpack.js" - }, + ".": "./dist/index.js", + "./api": "./dist/api.js", + "./esbuild": "./dist/esbuild.js", + "./raw": "./dist/raw.js", + "./rolldown": "./dist/rolldown.js", + "./rollup": "./dist/rollup.js", + "./rspack": "./dist/rspack.js", + "./vite": "./dist/vite.js", + "./webpack": "./dist/webpack.js", "./*": "./*" - } + }, + "tag": "next" }, "scripts": { "build": "tsup", @@ -151,6 +116,6 @@ "vue": "catalog:" }, "engines": { - "node": ">=16.14.0" + "node": ">=20.18.0" } } From e6d92de8ec526a5338c1c2d9fcad7ae5852bf8d2 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 17:39:03 +0800 Subject: [PATCH 145/156] fix: typecheck --- packages/jsx-macros/src/index.ts | 3 ++- packages/volar/src/jsx-macros/define-style.ts | 5 ++--- playground/vue3/src/examples/jsx-macros/index.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index bee1f04dc..fe4fb1a10 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -3,5 +3,6 @@ import { plugin, type Options, type OptionsResolved } from './core/plugin' export type { Options, OptionsResolved } -const unplugin: UnpluginInstance = createUnplugin(plugin) +const unplugin: UnpluginInstance = + createUnplugin(plugin) export default unplugin diff --git a/packages/volar/src/jsx-macros/define-style.ts b/packages/volar/src/jsx-macros/define-style.ts index 33001ae68..e441d702f 100644 --- a/packages/volar/src/jsx-macros/define-style.ts +++ b/packages/volar/src/jsx-macros/define-style.ts @@ -1,5 +1,5 @@ import { HELPER_PREFIX } from '@vue-macros/common' -import { generateCssClassProperty } from '@vue/language-core/lib/codegen/script/template.js' +import { generateClassProperty } from '@vue/language-core/lib/codegen/style/classProperty.js' import { parseCssClassNames } from '@vue/language-core/lib/utils/parseCssClassNames.js' import { replaceSourceRange } from 'muggle-string' import { getStart, getText } from '../common' @@ -39,12 +39,11 @@ export function transformDefineStyle( function* generateCssClassesType(css: string, offset: number, index: number) { for (const className of [...parseCssClassNames(css)]) { - yield* generateCssClassProperty( + yield* generateClassProperty( index, className.text, className.offset + offset, 'string', - false, ) } } diff --git a/playground/vue3/src/examples/jsx-macros/index.tsx b/playground/vue3/src/examples/jsx-macros/index.tsx index 2ad5fe9ef..c00e98a59 100644 --- a/playground/vue3/src/examples/jsx-macros/index.tsx +++ b/playground/vue3/src/examples/jsx-macros/index.tsx @@ -1,6 +1,6 @@ import { expectTypeOf } from 'expect-type' -import { useRef } from 'unplugin-vue-macros/runtime' import { defineComponent, ref } from 'vue' +import { useRef } from 'vue-macros/runtime' import { Comp } from './comp' export default defineComponent(() => { From ab25f17d3c0b97fdcbede7dca1ef5892a67b450c Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 18:03:43 +0800 Subject: [PATCH 146/156] chore: update pnpm-lock --- packages/jsx-macros/src/index.ts | 3 +- pnpm-lock.yaml | 89 +++++++++++++------------------- 2 files changed, 36 insertions(+), 56 deletions(-) diff --git a/packages/jsx-macros/src/index.ts b/packages/jsx-macros/src/index.ts index fe4fb1a10..bee1f04dc 100644 --- a/packages/jsx-macros/src/index.ts +++ b/packages/jsx-macros/src/index.ts @@ -3,6 +3,5 @@ import { plugin, type Options, type OptionsResolved } from './core/plugin' export type { Options, OptionsResolved } -const unplugin: UnpluginInstance = - createUnplugin(plugin) +const unplugin: UnpluginInstance = createUnplugin(plugin) export default unplugin diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f3d5e68e..b817ae904 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -107,7 +107,7 @@ catalogs: version: 0.13.0 vitepress: specifier: ^2.0.0-alpha.2 - version: 2.0.0-alpha.2 + version: 2.0.0-alpha.3 vitest: specifier: ^3.0.7 version: 3.0.7 @@ -282,16 +282,16 @@ importers: version: 1.2.5 '@nolebase/vitepress-plugin-enhanced-mark': specifier: 'catalog:' - version: 2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@nolebase/vitepress-plugin-enhanced-readabilities': specifier: 'catalog:' - version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@nolebase/vitepress-plugin-git-changelog': specifier: 'catalog:' - version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@nolebase/vitepress-plugin-highlight-targeted-heading': specifier: 'catalog:' - version: 2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@shikijs/vitepress-twoslash': specifier: 'catalog:' version: 3.1.0(@nuxt/kit@3.15.4(magicast@0.3.5))(typescript@5.8.2) @@ -309,7 +309,7 @@ importers: version: 7.7.2(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.34.9)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2)) vitepress: specifier: 'catalog:' - version: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + version: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) vitepress-plugin-group-icons: specifier: ^1.3.6 version: 1.3.6 @@ -749,7 +749,7 @@ importers: version: 2.0.0 unplugin: specifier: 'catalog:' - version: 1.16.1 + version: 2.2.0 devDependencies: '@types/hash-sum': specifier: ^1.0.2 @@ -1155,7 +1155,7 @@ importers: version: 4.34.9 type-fest: specifier: ^4.36.0 - version: 4.36.0 + version: 4.37.0 typescript: specifier: 'catalog:' version: 5.8.2 @@ -3006,18 +3006,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/linkify-it@5.0.0': - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - - '@types/markdown-it@14.1.2': - resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - '@types/mdurl@2.0.0': - resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -4263,8 +4254,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.111: - resolution: {integrity: sha512-vJyJlO95wQRAw6K2ZGF/8nol7AcbCOnp8S6H91mwOOBbXoS9seDBYxCTPYAFsvXLxl3lc0jLXXe9GLxC4nXVog==} + electron-to-chromium@1.5.112: + resolution: {integrity: sha512-oen93kVyqSb3l+ziUgzIOlWt/oOuy4zRmpwestMn4rhFWAoFJeFuCVte9F2fASjeZZo7l/Cif9TiyrdW4CwEMA==} emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -6973,8 +6964,8 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@4.36.0: - resolution: {integrity: sha512-3T/PUdKTCnkUmhQU6FFJEHsLwadsRegktX3TNHk+2JJB9HlA8gp1/VXblXVDI93kSnXF2rdPx0GMbHtJIV2LPg==} + type-fest@4.37.0: + resolution: {integrity: sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==} engines: {node: '>=16'} typescript-eslint@8.26.0: @@ -7436,8 +7427,8 @@ packages: vitepress-plugin-group-icons@1.3.6: resolution: {integrity: sha512-MzUAuMZ43f51dfBKYowW7yv/A2DxIjtN50d8Dcj31nU9RB6GuYBJ48E/Ze88U0bEn4wlnrjMXFh2j2e0rYmGug==} - vitepress@2.0.0-alpha.2: - resolution: {integrity: sha512-w+1WCkd8ko8lDUh61OWo4dj5Y4VHYJvwmJ9/iOXoVlzxOfO5Hoio2H3OMOgNlCzq0E0rTp9UR5GPU120AnH2dg==} + vitepress@2.0.0-alpha.3: + resolution: {integrity: sha512-vTsaF2pcVp4krxgEbT96RWiVanyHCxr0BvCaidS2Han0rkM3BDh2nnjJ7iaxtgCoFhsHxMCxwx/xN9UfYVbBew==} hasBin: true peerDependencies: markdown-it-mathjax3: ^4 @@ -8814,34 +8805,34 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@nolebase/ui@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/ui@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: '@iconify-json/octicon': 1.2.5 less: 4.2.2 - vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) vue: 3.5.13(typescript@5.8.2) transitivePeerDependencies: - typescript - '@nolebase/vitepress-plugin-enhanced-mark@2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-enhanced-mark@2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: less: 4.2.2 - vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) - '@nolebase/vitepress-plugin-enhanced-readabilities@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-enhanced-readabilities@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: '@iconify-json/carbon': 1.2.8 '@iconify-json/icon-park-outline': 1.2.2 - '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) less: 4.2.2 - vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) transitivePeerDependencies: - typescript - '@nolebase/vitepress-plugin-git-changelog@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-git-changelog@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: '@iconify-json/octicon': 1.2.5 - '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) colorette: 2.0.20 date-fns: 4.1.0 defu: 6.1.4 @@ -8851,14 +8842,14 @@ snapshots: gray-matter: 4.0.3 less: 4.2.2 uncrypto: 0.1.3 - vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) transitivePeerDependencies: - typescript - '@nolebase/vitepress-plugin-highlight-targeted-heading@2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-highlight-targeted-heading@2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: less: 4.2.2 - vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) '@nuxt/cli@3.22.4(magicast@0.3.5)': dependencies: @@ -9763,19 +9754,10 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/linkify-it@5.0.0': {} - - '@types/markdown-it@14.1.2': - dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 - '@types/mdurl@2.0.0': {} - '@types/ms@2.1.0': {} '@types/nlcst@2.0.3': @@ -10818,7 +10800,7 @@ snapshots: chalk: 5.4.1 cli-boxes: 3.0.0 string-width: 7.2.0 - type-fest: 4.36.0 + type-fest: 4.37.0 widest-line: 5.0.0 wrap-ansi: 9.0.0 @@ -10838,7 +10820,7 @@ snapshots: browserslist@4.24.4: dependencies: caniuse-lite: 1.0.30001702 - electron-to-chromium: 1.5.111 + electron-to-chromium: 1.5.112 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) @@ -11410,7 +11392,7 @@ snapshots: dot-prop@9.0.0: dependencies: - type-fest: 4.36.0 + type-fest: 4.37.0 dotenv@16.4.7: {} @@ -11422,7 +11404,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.111: {} + electron-to-chromium@1.5.112: {} emoji-regex-xs@1.0.0: {} @@ -13578,7 +13560,7 @@ snapshots: dependencies: '@babel/code-frame': 7.26.2 index-to-position: 0.1.2 - type-fest: 4.36.0 + type-fest: 4.37.0 parse-latin@7.0.0: dependencies: @@ -13942,14 +13924,14 @@ snapshots: dependencies: find-up-simple: 1.0.1 read-pkg: 9.0.1 - type-fest: 4.36.0 + type-fest: 4.37.0 read-pkg@9.0.1: dependencies: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.2 parse-json: 8.1.0 - type-fest: 4.36.0 + type-fest: 4.37.0 unicorn-magic: 0.1.0 readable-stream@2.3.8: @@ -14747,7 +14729,7 @@ snapshots: type-fest@0.21.3: {} - type-fest@4.36.0: {} + type-fest@4.37.0: {} typescript-eslint@8.26.0(eslint@9.21.0(jiti@2.4.2))(typescript@5.8.2): dependencies: @@ -15326,7 +15308,7 @@ snapshots: transitivePeerDependencies: - supports-color - vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0): + vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0): dependencies: '@docsearch/css': 3.9.0 '@docsearch/js': 3.9.0(@algolia/client-search@5.20.3) @@ -15334,7 +15316,6 @@ snapshots: '@shikijs/core': 3.1.0 '@shikijs/transformers': 3.1.0 '@shikijs/types': 3.1.0 - '@types/markdown-it': 14.1.2 '@vitejs/plugin-vue': 5.2.1(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2)) '@vue/devtools-api': 7.7.2 '@vue/shared': 3.5.13 From eccf66c008c7e7eb36c17f3894f863b8d9e77bac Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 18:18:51 +0800 Subject: [PATCH 147/156] fix: publint --- packages/volar/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/volar/package.json b/packages/volar/package.json index 1fce9e6c1..3cbabf783 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -106,9 +106,9 @@ "default": "./dist/loader/jsx-directive.cjs" }, "./jsx-macros": { - "dev": "./src/jsx-macros.ts", - "require": "./dist/jsx-macros.js", - "import": "./dist/jsx-macros.mjs" + "types": "./dist/jsx-macros.d.ts", + "module-sync": "./dist/jsx-macros.js", + "default": "./dist/loader/jsx-macros.cjs" }, "./jsx-ref": { "types": "./dist/jsx-ref.d.ts", From 02929bfc42a41b6781c6dd0e279a57a40a0963cb Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 21:51:08 +0800 Subject: [PATCH 148/156] fix: docs:build --- docs/macros/jsx-macros.md | 43 +++------ docs/zh-CN/macros/jsx-macros.md | 40 ++------- packages/volar/src/jsx-directive/context.ts | 2 + packages/volar/src/jsx-macros.ts | 2 +- packages/volar/src/jsx-macros/global-types.ts | 4 +- pnpm-lock.yaml | 87 +++++++++++-------- 6 files changed, 78 insertions(+), 100 deletions(-) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md index 73f2580df..724a374ba 100644 --- a/docs/macros/jsx-macros.md +++ b/docs/macros/jsx-macros.md @@ -29,10 +29,8 @@ interface Options { - Support using `getCurrentInstance()` after an `await` expression. - Automatically collects used props to the defineComponent's props option. -```vue twoslash - ``` ::: details Compiled Code ```tsx -import { getCurrentInstance, withAsyncContext } from 'vue' +import { defineComponent, getCurrentInstance, withAsyncContext } from 'vue' defineComponent( async (props) => { let __temp, __restore @@ -85,9 +82,9 @@ defineComponent( - If the prop's default value ends with `!`, the prop will be inferred as required. - If a rest prop is defined, it will be converted to `useAttrs()`, and the `inheritAttrs` option will default to `false`. -```vue twoslash - ``` ::: details Compiled Code @@ -129,9 +125,7 @@ defineComponent( - Will be inferred as a required prop when the expression ends with `!`. - The modified model's value can be read synchronously, without needing to `await nextTick()`. [Related issue](https://github.com/vuejs/core/issues/11080) -```vue twoslash - ``` ::: details Compiled Code @@ -178,9 +171,7 @@ slots.default?.() - Support default slots (Recommended). -```vue twoslash - ``` ## defineExpose Just like in Vue SFC. -```vue twoslash - ``` ::: details Compiled Code @@ -372,9 +354,7 @@ defineStyle(` - Support `css modules`, if the macro is an assignment expression. -```vue twoslash - ``` ## Volar Configuration diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md index d95a8d469..c77efce44 100644 --- a/docs/zh-CN/macros/jsx-macros.md +++ b/docs/zh-CN/macros/jsx-macros.md @@ -29,10 +29,8 @@ interface Options { - 支持在 `await` 表达式后使用 `getCurrentInstance()`。 - 自动收集使用过的 props 到 defineComponent 的 props 选项中。 -```vue twoslash - ``` ::: details 编译后代码 @@ -86,9 +83,9 @@ defineComponent( - 如果 prop 的默认值以 `!` 结尾,该 prop 将被推断为必传的。 - 如果定义了 rest prop,它将被转换为 `useAttrs()`,并且 `inheritAttrs` 选项默认为 `false`。 -```vue twoslash - ``` ::: details 编译后代码 @@ -130,9 +126,7 @@ defineComponent( - 当表达式以 `!` 结尾时,将被推断为必需的 model。 - 修改后的 model 可以同步读取,无需 `await nextTick()`。[相关问题](https://github.com/vuejs/core/issues/11080) -```vue twoslash - ``` ::: details 编译后代码 @@ -179,9 +172,7 @@ slots.default?.() - 支持默认插槽(推荐)。 -```vue twoslash - ``` ## defineExpose 就像在 Vue SFC 中一样。 -```vue twoslash - ``` ::: details 编译后代码 @@ -373,9 +355,7 @@ defineStyle(` - 支持 `css modules`, 如果宏是赋值表达式。 -```vue twoslash - ``` ## Volar 配置 diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts index 47b923c0c..97087a21b 100644 --- a/packages/volar/src/jsx-directive/context.ts +++ b/packages/volar/src/jsx-directive/context.ts @@ -18,7 +18,9 @@ export function resolveCtxMap( ): Map { if (ctxNodeMap.size) { options.codes.push(` +// @ts-ignore type __VLS_IsAny = 0 extends 1 & T ? true : false; +// @ts-ignore type __VLS_PickNotAny = __VLS_IsAny
extends true ? B : A; type __VLS_Element = globalThis.JSX.Element; declare function __VLS_asFunctionalComponent any ? InstanceType : unknown>(t: T, instance?: K): diff --git a/packages/volar/src/jsx-macros.ts b/packages/volar/src/jsx-macros.ts index cf6e8f4d8..6ed9142ea 100644 --- a/packages/volar/src/jsx-macros.ts +++ b/packages/volar/src/jsx-macros.ts @@ -57,7 +57,7 @@ const plugin: PluginReturn = const rootMap = getRootMap(options) if (rootMap.size) { transformJsxMacros(rootMap, options) - codes.unshift(getGlobalTypes(options)) + codes.push(getGlobalTypes(options)) } }, } diff --git a/packages/volar/src/jsx-macros/global-types.ts b/packages/volar/src/jsx-macros/global-types.ts index ffabb1a76..b02db64b8 100644 --- a/packages/volar/src/jsx-macros/global-types.ts +++ b/packages/volar/src/jsx-macros/global-types.ts @@ -34,13 +34,15 @@ export function getGlobalTypes(options: TransformOptions): string { .filter(Boolean) .join(', ') return ` -const { ${defineModel}, ${defineComponent} } = await import('vue') +declare const { ${defineModel}, ${defineComponent} }: typeof import('vue') ${defineSlots} ${defineExpose} ${defineStyle} type ${HELPER_PREFIX}StyleArgs = [style: string, options?: { scoped?: boolean }]; type ${HELPER_PREFIX}PrettifyLocal = { [K in keyof T]: T[K]; } & {}; +// @ts-ignore type __VLS_IsAny = 0 extends 1 & T ? true : false; +// @ts-ignore type __VLS_PickNotAny = __VLS_IsAny extends true ? B : A; ` } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b817ae904..35be49d2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -107,7 +107,7 @@ catalogs: version: 0.13.0 vitepress: specifier: ^2.0.0-alpha.2 - version: 2.0.0-alpha.3 + version: 2.0.0-alpha.2 vitest: specifier: ^3.0.7 version: 3.0.7 @@ -282,16 +282,16 @@ importers: version: 1.2.5 '@nolebase/vitepress-plugin-enhanced-mark': specifier: 'catalog:' - version: 2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@nolebase/vitepress-plugin-enhanced-readabilities': specifier: 'catalog:' - version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@nolebase/vitepress-plugin-git-changelog': specifier: 'catalog:' - version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@nolebase/vitepress-plugin-highlight-targeted-heading': specifier: 'catalog:' - version: 2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + version: 2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) '@shikijs/vitepress-twoslash': specifier: 'catalog:' version: 3.1.0(@nuxt/kit@3.15.4(magicast@0.3.5))(typescript@5.8.2) @@ -309,7 +309,7 @@ importers: version: 7.7.2(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.34.9)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2)) vitepress: specifier: 'catalog:' - version: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + version: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) vitepress-plugin-group-icons: specifier: ^1.3.6 version: 1.3.6 @@ -1155,7 +1155,7 @@ importers: version: 4.34.9 type-fest: specifier: ^4.36.0 - version: 4.37.0 + version: 4.36.0 typescript: specifier: 'catalog:' version: 5.8.2 @@ -3006,9 +3006,18 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -4254,8 +4263,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.112: - resolution: {integrity: sha512-oen93kVyqSb3l+ziUgzIOlWt/oOuy4zRmpwestMn4rhFWAoFJeFuCVte9F2fASjeZZo7l/Cif9TiyrdW4CwEMA==} + electron-to-chromium@1.5.111: + resolution: {integrity: sha512-vJyJlO95wQRAw6K2ZGF/8nol7AcbCOnp8S6H91mwOOBbXoS9seDBYxCTPYAFsvXLxl3lc0jLXXe9GLxC4nXVog==} emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -6964,8 +6973,8 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@4.37.0: - resolution: {integrity: sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==} + type-fest@4.36.0: + resolution: {integrity: sha512-3T/PUdKTCnkUmhQU6FFJEHsLwadsRegktX3TNHk+2JJB9HlA8gp1/VXblXVDI93kSnXF2rdPx0GMbHtJIV2LPg==} engines: {node: '>=16'} typescript-eslint@8.26.0: @@ -7427,8 +7436,8 @@ packages: vitepress-plugin-group-icons@1.3.6: resolution: {integrity: sha512-MzUAuMZ43f51dfBKYowW7yv/A2DxIjtN50d8Dcj31nU9RB6GuYBJ48E/Ze88U0bEn4wlnrjMXFh2j2e0rYmGug==} - vitepress@2.0.0-alpha.3: - resolution: {integrity: sha512-vTsaF2pcVp4krxgEbT96RWiVanyHCxr0BvCaidS2Han0rkM3BDh2nnjJ7iaxtgCoFhsHxMCxwx/xN9UfYVbBew==} + vitepress@2.0.0-alpha.2: + resolution: {integrity: sha512-w+1WCkd8ko8lDUh61OWo4dj5Y4VHYJvwmJ9/iOXoVlzxOfO5Hoio2H3OMOgNlCzq0E0rTp9UR5GPU120AnH2dg==} hasBin: true peerDependencies: markdown-it-mathjax3: ^4 @@ -8805,34 +8814,34 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@nolebase/ui@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/ui@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: '@iconify-json/octicon': 1.2.5 less: 4.2.2 - vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) vue: 3.5.13(typescript@5.8.2) transitivePeerDependencies: - typescript - '@nolebase/vitepress-plugin-enhanced-mark@2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-enhanced-mark@2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: less: 4.2.2 - vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) - '@nolebase/vitepress-plugin-enhanced-readabilities@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-enhanced-readabilities@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: '@iconify-json/carbon': 1.2.8 '@iconify-json/icon-park-outline': 1.2.2 - '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) less: 4.2.2 - vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) transitivePeerDependencies: - typescript - '@nolebase/vitepress-plugin-git-changelog@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-git-changelog@2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: '@iconify-json/octicon': 1.2.5 - '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) + '@nolebase/ui': 2.15.0(typescript@5.8.2)(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0)) colorette: 2.0.20 date-fns: 4.1.0 defu: 6.1.4 @@ -8842,14 +8851,14 @@ snapshots: gray-matter: 4.0.3 less: 4.2.2 uncrypto: 0.1.3 - vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) transitivePeerDependencies: - typescript - '@nolebase/vitepress-plugin-highlight-targeted-heading@2.15.0(vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': + '@nolebase/vitepress-plugin-highlight-targeted-heading@2.15.0(vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0))': dependencies: less: 4.2.2 - vitepress: 2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) + vitepress: 2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0) '@nuxt/cli@3.22.4(magicast@0.3.5)': dependencies: @@ -9754,10 +9763,19 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 + '@types/mdurl@2.0.0': {} + '@types/ms@2.1.0': {} '@types/nlcst@2.0.3': @@ -10800,7 +10818,7 @@ snapshots: chalk: 5.4.1 cli-boxes: 3.0.0 string-width: 7.2.0 - type-fest: 4.37.0 + type-fest: 4.36.0 widest-line: 5.0.0 wrap-ansi: 9.0.0 @@ -10820,7 +10838,7 @@ snapshots: browserslist@4.24.4: dependencies: caniuse-lite: 1.0.30001702 - electron-to-chromium: 1.5.112 + electron-to-chromium: 1.5.111 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) @@ -11392,7 +11410,7 @@ snapshots: dot-prop@9.0.0: dependencies: - type-fest: 4.37.0 + type-fest: 4.36.0 dotenv@16.4.7: {} @@ -11404,7 +11422,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.112: {} + electron-to-chromium@1.5.111: {} emoji-regex-xs@1.0.0: {} @@ -13560,7 +13578,7 @@ snapshots: dependencies: '@babel/code-frame': 7.26.2 index-to-position: 0.1.2 - type-fest: 4.37.0 + type-fest: 4.36.0 parse-latin@7.0.0: dependencies: @@ -13924,14 +13942,14 @@ snapshots: dependencies: find-up-simple: 1.0.1 read-pkg: 9.0.1 - type-fest: 4.37.0 + type-fest: 4.36.0 read-pkg@9.0.1: dependencies: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.2 parse-json: 8.1.0 - type-fest: 4.37.0 + type-fest: 4.36.0 unicorn-magic: 0.1.0 readable-stream@2.3.8: @@ -14729,7 +14747,7 @@ snapshots: type-fest@0.21.3: {} - type-fest@4.37.0: {} + type-fest@4.36.0: {} typescript-eslint@8.26.0(eslint@9.21.0(jiti@2.4.2))(typescript@5.8.2): dependencies: @@ -15308,7 +15326,7 @@ snapshots: transitivePeerDependencies: - supports-color - vitepress@2.0.0-alpha.3(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0): + vitepress@2.0.0-alpha.2(@algolia/client-search@5.20.3)(@types/node@22.13.9)(change-case@5.4.4)(fuse.js@7.1.0)(jiti@2.4.2)(less@4.2.2)(postcss@8.5.3)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)(yaml@2.7.0): dependencies: '@docsearch/css': 3.9.0 '@docsearch/js': 3.9.0(@algolia/client-search@5.20.3) @@ -15316,6 +15334,7 @@ snapshots: '@shikijs/core': 3.1.0 '@shikijs/transformers': 3.1.0 '@shikijs/types': 3.1.0 + '@types/markdown-it': 14.1.2 '@vitejs/plugin-vue': 5.2.1(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2)) '@vue/devtools-api': 7.7.2 '@vue/shared': 3.5.13 From c1869f9d960175ef9664821096b68f13ab53f635 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Tue, 4 Mar 2025 21:54:30 +0800 Subject: [PATCH 149/156] fix: format --- docs/macros/jsx-macros.md | 8 ++------ docs/zh-CN/macros/jsx-macros.md | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/docs/macros/jsx-macros.md b/docs/macros/jsx-macros.md index 724a374ba..995af57c9 100644 --- a/docs/macros/jsx-macros.md +++ b/docs/macros/jsx-macros.md @@ -188,12 +188,8 @@ function Comp() { export default () => ( > - - + + ) ``` diff --git a/docs/zh-CN/macros/jsx-macros.md b/docs/zh-CN/macros/jsx-macros.md index c77efce44..cf7ce2131 100644 --- a/docs/zh-CN/macros/jsx-macros.md +++ b/docs/zh-CN/macros/jsx-macros.md @@ -189,12 +189,8 @@ function Comp() { export default () => ( > - - + + ) ``` From 3453d0a1b6de0ec8bcb484dc40f3d5916cad66bc Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 5 Mar 2025 11:35:09 +0800 Subject: [PATCH 150/156] refactor: next --- monoman.config.ts | 2 +- packages/jsx/package.json | 116 ++++++++++--------------- packages/jsx/src/index.ts | 2 +- packages/jsx/src/{core => }/options.ts | 0 packages/jsx/src/raw.ts | 2 +- packages/jsx/src/volar.ts | 2 +- packages/jsx/volar.cjs | 1 + packages/jsx/volar.d.ts | 1 + packages/volar/package.json | 6 ++ packages/volar/src/jsx.ts | 23 +++++ pnpm-lock.yaml | 3 + 11 files changed, 83 insertions(+), 75 deletions(-) rename packages/jsx/src/{core => }/options.ts (100%) create mode 100644 packages/jsx/volar.cjs create mode 100644 packages/jsx/volar.d.ts create mode 100644 packages/volar/src/jsx.ts diff --git a/monoman.config.ts b/monoman.config.ts index ad763a98a..ba4990d5a 100644 --- a/monoman.config.ts +++ b/monoman.config.ts @@ -83,7 +83,7 @@ export default defineConfig([ data.files = ['dist'] if (hasRootDts) data.files.push('*.d.ts') - if (pkgName === 'macros') data.files.push('volar.cjs') + if (['macros', 'jsx'].includes(pkgName)) data.files.push('volar.cjs') data.files.sort() if ( diff --git a/packages/jsx/package.json b/packages/jsx/package.json index 58e9589ca..a7348b7f5 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -1,6 +1,6 @@ { "name": "@vue-macros/jsx", - "version": "0.0.1", + "version": "3.0.0-beta.2", "packageManager": "pnpm@10.4.1", "description": "jsx feature from Vue Macros.", "type": "module", @@ -25,68 +25,67 @@ }, "author": "三咲智子 ", "files": [ - "dist" + "*.d.ts", + "dist", + "volar.cjs" ], - "main": "dist/index.cjs", + "main": "dist/index.js", "module": "dist/index.js", "types": "dist/index.d.ts", "exports": { ".": { "dev": "./src/index.ts", - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "default": "./dist/index.js" }, "./esbuild": { "dev": "./src/esbuild.ts", - "require": "./dist/esbuild.cjs", - "import": "./dist/esbuild.js" + "default": "./dist/esbuild.js" }, "./jsx-runtime": { "dev": "./src/jsx-runtime.ts", - "require": "./dist/jsx-runtime.cjs", - "import": "./dist/jsx-runtime.js" + "default": "./dist/jsx-runtime.js" + }, + "./options": { + "dev": "./src/options.ts", + "default": "./dist/options.js" }, "./raw": { "dev": "./src/raw.ts", - "require": "./dist/raw.cjs", - "import": "./dist/raw.js" + "default": "./dist/raw.js" }, "./rolldown": { "dev": "./src/rolldown.ts", - "require": "./dist/rolldown.cjs", - "import": "./dist/rolldown.js" + "default": "./dist/rolldown.js" }, "./rollup": { "dev": "./src/rollup.ts", - "require": "./dist/rollup.cjs", - "import": "./dist/rollup.js" + "default": "./dist/rollup.js" }, "./rspack": { "dev": "./src/rspack.ts", - "require": "./dist/rspack.cjs", - "import": "./dist/rspack.js" + "default": "./dist/rspack.js" }, "./runtime": { "dev": "./src/runtime.ts", - "require": "./dist/runtime.cjs", - "import": "./dist/runtime.js" + "default": "./dist/runtime.js" }, "./vite": { "dev": "./src/vite.ts", - "require": "./dist/vite.cjs", - "import": "./dist/vite.js" + "default": "./dist/vite.js" }, "./volar": { "dev": "./src/volar.ts", - "require": "./dist/volar.cjs", - "import": "./dist/volar.js" + "types": "./volar.d.ts", + "default": "./volar.cjs" }, "./webpack": { "dev": "./src/webpack.ts", - "require": "./dist/webpack.cjs", - "import": "./dist/webpack.js" + "default": "./dist/webpack.js" }, - "./*": "./*" + "./*": [ + "./*", + "./*.d.ts" + ] }, "typesVersions": { "*": { @@ -99,52 +98,27 @@ "publishConfig": { "access": "public", "exports": { - ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" - }, - "./esbuild": { - "require": "./dist/esbuild.cjs", - "import": "./dist/esbuild.js" - }, - "./jsx-runtime": { - "require": "./dist/jsx-runtime.cjs", - "import": "./dist/jsx-runtime.js" - }, - "./raw": { - "require": "./dist/raw.cjs", - "import": "./dist/raw.js" - }, - "./rolldown": { - "require": "./dist/rolldown.cjs", - "import": "./dist/rolldown.js" - }, - "./rollup": { - "require": "./dist/rollup.cjs", - "import": "./dist/rollup.js" - }, - "./rspack": { - "require": "./dist/rspack.cjs", - "import": "./dist/rspack.js" - }, - "./runtime": { - "require": "./dist/runtime.cjs", - "import": "./dist/runtime.js" - }, - "./vite": { - "require": "./dist/vite.cjs", - "import": "./dist/vite.js" - }, + ".": "./dist/index.js", + "./esbuild": "./dist/esbuild.js", + "./jsx-runtime": "./dist/jsx-runtime.js", + "./options": "./dist/options.js", + "./raw": "./dist/raw.js", + "./rolldown": "./dist/rolldown.js", + "./rollup": "./dist/rollup.js", + "./rspack": "./dist/rspack.js", + "./runtime": "./dist/runtime.js", + "./vite": "./dist/vite.js", "./volar": { - "require": "./dist/volar.cjs", - "import": "./dist/volar.js" - }, - "./webpack": { - "require": "./dist/webpack.cjs", - "import": "./dist/webpack.js" + "types": "./volar.d.ts", + "default": "./volar.cjs" }, - "./*": "./*" - } + "./webpack": "./dist/webpack.js", + "./*": [ + "./*", + "./*.d.ts" + ] + }, + "tag": "next" }, "scripts": { "build": "tsup", @@ -166,6 +140,6 @@ "vue": "catalog:" }, "engines": { - "node": ">=16.14.0" + "node": ">=20.18.0" } } diff --git a/packages/jsx/src/index.ts b/packages/jsx/src/index.ts index 5e177d86b..ea963bfef 100644 --- a/packages/jsx/src/index.ts +++ b/packages/jsx/src/index.ts @@ -6,7 +6,7 @@ import { createCombinePlugin, type UnpluginCombineInstance, } from 'unplugin-combine' -import { resolveJSXOptions, type JSXOptions } from './core/options' +import { resolveJSXOptions, type JSXOptions } from './options' const jsxPlugins = [ ['directive', jsxDirective], diff --git a/packages/jsx/src/core/options.ts b/packages/jsx/src/options.ts similarity index 100% rename from packages/jsx/src/core/options.ts rename to packages/jsx/src/options.ts diff --git a/packages/jsx/src/raw.ts b/packages/jsx/src/raw.ts index f7e22dce0..751dd57ee 100644 --- a/packages/jsx/src/raw.ts +++ b/packages/jsx/src/raw.ts @@ -1,7 +1,7 @@ import jsxDirective from '@vue-macros/jsx-directive/raw' import jsxMacros from '@vue-macros/jsx-macros/raw' -import { resolveJSXOptions, type JSXOptions } from './core/options' +import { resolveJSXOptions, type JSXOptions } from './options' import type { UnpluginFactory } from 'unplugin' const jsxPlugins = [ diff --git a/packages/jsx/src/volar.ts b/packages/jsx/src/volar.ts index a8858de86..4d8383904 100644 --- a/packages/jsx/src/volar.ts +++ b/packages/jsx/src/volar.ts @@ -2,7 +2,7 @@ import jsxDirective from '@vue-macros/volar/jsx-directive' import jsxMacros from '@vue-macros/volar/jsx-macros' import jsxRef from '@vue-macros/volar/jsx-ref' import { createPlugin, type PluginReturn } from 'ts-macro' -import { resolveJSXOptions, type JSXOptions } from './core/options' +import { resolveJSXOptions, type JSXOptions } from './options' const jsxPlugins = [ ['directive', jsxDirective], diff --git a/packages/jsx/volar.cjs b/packages/jsx/volar.cjs new file mode 100644 index 000000000..ded4b642c --- /dev/null +++ b/packages/jsx/volar.cjs @@ -0,0 +1 @@ +module.exports = require('@vue-macros/volar/jsx') diff --git a/packages/jsx/volar.d.ts b/packages/jsx/volar.d.ts new file mode 100644 index 000000000..0295885a8 --- /dev/null +++ b/packages/jsx/volar.d.ts @@ -0,0 +1 @@ +export { default } from '@vue-macros/volar/jsx' diff --git a/packages/volar/package.json b/packages/volar/package.json index 5e3ef349f..06049e9f3 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -115,6 +115,11 @@ "module-sync": "./dist/jsx-ref.js", "default": "./dist/loader/jsx-ref.cjs" }, + "./jsx": { + "types": "./dist/jsx.d.ts", + "module-sync": "./dist/jsx.js", + "default": "./dist/loader/jsx.cjs" + }, "./script-lang": { "types": "./dist/script-lang.d.ts", "module-sync": "./dist/script-lang.js", @@ -177,6 +182,7 @@ "@vue-macros/boolean-prop": "workspace:*", "@vue-macros/common": "workspace:*", "@vue-macros/config": "workspace:*", + "@vue-macros/jsx": "workspace:*", "@vue-macros/short-bind": "workspace:*", "@vue-macros/short-vmodel": "workspace:*", "@vue/compiler-dom": "catalog:", diff --git a/packages/volar/src/jsx.ts b/packages/volar/src/jsx.ts new file mode 100644 index 000000000..cc7ab1b32 --- /dev/null +++ b/packages/volar/src/jsx.ts @@ -0,0 +1,23 @@ +import { resolveJSXOptions, type JSXOptions } from '@vue-macros/jsx/options' +import { createPlugin, type PluginReturn } from 'ts-macro' +import jsxDirective from './jsx-directive' +import jsxMacros from './jsx-macros' +import jsxRef from './jsx-ref' + +const jsxPlugins = [ + ['directive', jsxDirective], + ['macros', jsxMacros], + ['ref', jsxRef], +] as const + +const plugin: PluginReturn = createPlugin( + (ctx, userOptions) => { + const options = resolveJSXOptions(userOptions) + return jsxPlugins.flatMap(([name, plugin]) => + options[name] ? plugin(options[name])(ctx) : [], + ) + }, +) + +export default plugin +export { plugin as 'module.exports' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b48cdc82..fd59bb40e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1082,6 +1082,9 @@ importers: '@vue-macros/config': specifier: workspace:* version: link:../config + '@vue-macros/jsx': + specifier: workspace:* + version: link:../jsx '@vue-macros/short-bind': specifier: workspace:* version: link:../short-bind From 2d3f30afda30840c99287e671a61f499ba9b1ee7 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Wed, 5 Mar 2025 16:23:48 +0800 Subject: [PATCH 151/156] feat: only esm for volar plugin --- monoman.config.ts | 4 ++-- packages/jsx/package.json | 27 +++++++++------------------ packages/jsx/volar.cjs | 1 - packages/jsx/volar.d.ts | 1 - packages/volar/package.json | 6 ------ packages/volar/src/jsx.ts | 23 ----------------------- pnpm-lock.yaml | 3 --- 7 files changed, 11 insertions(+), 54 deletions(-) delete mode 100644 packages/jsx/volar.cjs delete mode 100644 packages/jsx/volar.d.ts delete mode 100644 packages/volar/src/jsx.ts diff --git a/monoman.config.ts b/monoman.config.ts index ba4990d5a..70e31b3bf 100644 --- a/monoman.config.ts +++ b/monoman.config.ts @@ -83,7 +83,7 @@ export default defineConfig([ data.files = ['dist'] if (hasRootDts) data.files.push('*.d.ts') - if (['macros', 'jsx'].includes(pkgName)) data.files.push('volar.cjs') + if (pkgName === 'macros') data.files.push('volar.cjs') data.files.sort() if ( @@ -161,7 +161,7 @@ export default unplugin.${entry} as typeof unplugin.${entry}\n`, const map: Record = {} if (withDev) map.dev = `./src/${entry}.ts` - if (entry === 'volar') { + if (entry === 'volar' && pkgName !== 'jsx') { map.types = `./volar.d.ts` map.default = `./volar.cjs` } else { diff --git a/packages/jsx/package.json b/packages/jsx/package.json index a7348b7f5..fd908aa26 100644 --- a/packages/jsx/package.json +++ b/packages/jsx/package.json @@ -23,11 +23,12 @@ "url": "git+https://github.com/vue-macros/vue-macros.git", "directory": "packages/jsx" }, - "author": "三咲智子 ", + "author": "zhiyuanzmj", + "contributors": [ + "三咲智子 " + ], "files": [ - "*.d.ts", - "dist", - "volar.cjs" + "dist" ], "main": "dist/index.js", "module": "dist/index.js", @@ -75,17 +76,13 @@ }, "./volar": { "dev": "./src/volar.ts", - "types": "./volar.d.ts", - "default": "./volar.cjs" + "default": "./dist/volar.js" }, "./webpack": { "dev": "./src/webpack.ts", "default": "./dist/webpack.js" }, - "./*": [ - "./*", - "./*.d.ts" - ] + "./*": "./*" }, "typesVersions": { "*": { @@ -108,15 +105,9 @@ "./rspack": "./dist/rspack.js", "./runtime": "./dist/runtime.js", "./vite": "./dist/vite.js", - "./volar": { - "types": "./volar.d.ts", - "default": "./volar.cjs" - }, + "./volar": "./dist/volar.js", "./webpack": "./dist/webpack.js", - "./*": [ - "./*", - "./*.d.ts" - ] + "./*": "./*" }, "tag": "next" }, diff --git a/packages/jsx/volar.cjs b/packages/jsx/volar.cjs deleted file mode 100644 index ded4b642c..000000000 --- a/packages/jsx/volar.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@vue-macros/volar/jsx') diff --git a/packages/jsx/volar.d.ts b/packages/jsx/volar.d.ts deleted file mode 100644 index 0295885a8..000000000 --- a/packages/jsx/volar.d.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vue-macros/volar/jsx' diff --git a/packages/volar/package.json b/packages/volar/package.json index 06049e9f3..5e3ef349f 100644 --- a/packages/volar/package.json +++ b/packages/volar/package.json @@ -115,11 +115,6 @@ "module-sync": "./dist/jsx-ref.js", "default": "./dist/loader/jsx-ref.cjs" }, - "./jsx": { - "types": "./dist/jsx.d.ts", - "module-sync": "./dist/jsx.js", - "default": "./dist/loader/jsx.cjs" - }, "./script-lang": { "types": "./dist/script-lang.d.ts", "module-sync": "./dist/script-lang.js", @@ -182,7 +177,6 @@ "@vue-macros/boolean-prop": "workspace:*", "@vue-macros/common": "workspace:*", "@vue-macros/config": "workspace:*", - "@vue-macros/jsx": "workspace:*", "@vue-macros/short-bind": "workspace:*", "@vue-macros/short-vmodel": "workspace:*", "@vue/compiler-dom": "catalog:", diff --git a/packages/volar/src/jsx.ts b/packages/volar/src/jsx.ts deleted file mode 100644 index cc7ab1b32..000000000 --- a/packages/volar/src/jsx.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { resolveJSXOptions, type JSXOptions } from '@vue-macros/jsx/options' -import { createPlugin, type PluginReturn } from 'ts-macro' -import jsxDirective from './jsx-directive' -import jsxMacros from './jsx-macros' -import jsxRef from './jsx-ref' - -const jsxPlugins = [ - ['directive', jsxDirective], - ['macros', jsxMacros], - ['ref', jsxRef], -] as const - -const plugin: PluginReturn = createPlugin( - (ctx, userOptions) => { - const options = resolveJSXOptions(userOptions) - return jsxPlugins.flatMap(([name, plugin]) => - options[name] ? plugin(options[name])(ctx) : [], - ) - }, -) - -export default plugin -export { plugin as 'module.exports' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fd59bb40e..7b48cdc82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1082,9 +1082,6 @@ importers: '@vue-macros/config': specifier: workspace:* version: link:../config - '@vue-macros/jsx': - specifier: workspace:* - version: link:../jsx '@vue-macros/short-bind': specifier: workspace:* version: link:../short-bind From bab24815cb2dd36b2bb78ae034a0cab26895a8e2 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Sun, 9 Mar 2025 21:33:52 +0800 Subject: [PATCH 152/156] fix: mono --- packages/jsx-macros/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index f5b9a7efa..e6e5f4b97 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,6 +1,6 @@ { "name": "@vue-macros/jsx-macros", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "packageManager": "pnpm@10.4.1", "description": "jsxMacros feature from Vue Macros.", "type": "module", @@ -28,6 +28,7 @@ "contributors": [ "三咲智子 " ], + "funding": "https://github.com/sponsors/vue-macros", "files": [ "dist" ], From 025912f002b579f7d475102f6460d920a032bb1e Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Mon, 10 Mar 2025 12:04:16 +0800 Subject: [PATCH 153/156] fix: build --- pnpm-lock.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6697cf5f7..389358cc7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,6 +96,9 @@ catalogs: unplugin: specifier: ^2.2.0 version: 2.2.0 + unplugin-combine: + specifier: ^1.2.1 + version: 1.2.1 unplugin-oxc: specifier: ^0.2.7 version: 0.2.7 @@ -739,7 +742,7 @@ importers: specifier: 'catalog:' version: 0.1.19(rollup@4.35.0)(typescript@5.8.2) unplugin-combine: - specifier: ^1.2.0 + specifier: 'catalog:' version: 1.2.1(@rspack/core@1.2.7(@swc/helpers@0.5.15))(esbuild@0.25.0)(rolldown@1.0.0-beta.3(typescript@5.8.2))(rollup@4.35.0)(unplugin@2.2.0)(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(webpack@5.98.0(esbuild@0.25.0)) devDependencies: csstype: @@ -879,7 +882,7 @@ importers: specifier: 'catalog:' version: 2.2.0 unplugin-combine: - specifier: ^1.2.1 + specifier: 'catalog:' version: 1.2.1(@rspack/core@1.2.7(@swc/helpers@0.5.15))(esbuild@0.25.0)(rolldown@1.0.0-beta.3(typescript@5.8.2))(rollup@4.35.0)(unplugin@2.2.0)(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(webpack@5.98.0(esbuild@0.25.0)) unplugin-vue-define-options: specifier: workspace:* From 0193fa058aeeffab54abf5d41f3c55c227f2164b Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 14 Mar 2025 09:59:08 +0800 Subject: [PATCH 154/156] fix: test --- packages/jsx-macros/package.json | 2 +- packages/jsx-macros/src/core/define-component/await.ts | 1 - packages/jsx-macros/src/core/define-component/index.ts | 4 ++-- packages/jsx-macros/src/core/define-expose/react.ts | 2 ++ packages/jsx-macros/src/core/define-expose/vue.ts | 6 +++--- packages/jsx-macros/src/core/define-model.ts | 2 +- packages/jsx-macros/src/core/define-slots.ts | 2 +- packages/jsx-macros/src/core/restructure.ts | 2 +- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index a8fad157c..3db8e9eaf 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -1,6 +1,6 @@ { "name": "@vue-macros/jsx-macros", - "version": "3.0.0-beta.4", + "version": "3.0.0-beta.5", "packageManager": "pnpm@10.4.1", "description": "jsxMacros feature from Vue Macros.", "type": "module", diff --git a/packages/jsx-macros/src/core/define-component/await.ts b/packages/jsx-macros/src/core/define-component/await.ts index fe651eb7b..f63edcfad 100644 --- a/packages/jsx-macros/src/core/define-component/await.ts +++ b/packages/jsx-macros/src/core/define-component/await.ts @@ -86,7 +86,6 @@ function processAwait( s, 0, `withAsyncContext`, - 'vue', )}(${containsNestedAwait ? `async ` : ``}() => `, ) s.appendLeft( diff --git a/packages/jsx-macros/src/core/define-component/index.ts b/packages/jsx-macros/src/core/define-component/index.ts index 69029b9f5..f1542b6ac 100644 --- a/packages/jsx-macros/src/core/define-component/index.ts +++ b/packages/jsx-macros/src/core/define-component/index.ts @@ -22,7 +22,7 @@ export function transformDefineComponent( defineComponentName && !['defineComponent', 'defineVaporComponent'].includes(defineComponentName) ) { - importHelperFn(s, 0, 'defineComponent', 'vue', false, defineComponentName) + importHelperFn(s, 0, 'defineComponent', defineComponentName) } let hasRestProp = false @@ -35,7 +35,7 @@ export function transformDefineComponent( generateRestProps: (restPropsName, index, list) => { if (index === list.length - 1) { hasRestProp = true - const useAttrs = importHelperFn(s, 0, 'useAttrs', 'vue') + const useAttrs = importHelperFn(s, 0, 'useAttrs') return `const ${restPropsName} = ${useAttrs}()` } }, diff --git a/packages/jsx-macros/src/core/define-expose/react.ts b/packages/jsx-macros/src/core/define-expose/react.ts index ab2a57c66..109fbaa30 100644 --- a/packages/jsx-macros/src/core/define-expose/react.ts +++ b/packages/jsx-macros/src/core/define-expose/react.ts @@ -19,6 +19,7 @@ export function transformReactDefineExpose( s, 0, 'useImperativeHandle', + undefined, lib === 'preact' ? 'preact/hooks' : lib, ) const isReact19 = lib === 'react' && version >= 19 @@ -44,6 +45,7 @@ export function transformReactDefineExpose( s, 0, 'forwardRef', + undefined, lib === 'preact' ? 'preact/compat' : lib, ) if (root.type === 'FunctionDeclaration' && root.id) { diff --git a/packages/jsx-macros/src/core/define-expose/vue.ts b/packages/jsx-macros/src/core/define-expose/vue.ts index 7ef49e5f1..85298f383 100644 --- a/packages/jsx-macros/src/core/define-expose/vue.ts +++ b/packages/jsx-macros/src/core/define-expose/vue.ts @@ -9,12 +9,12 @@ export function transformVueDefineExpose( ): void { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useExpose', useExposeHelperId), + importHelperFn(s, 0, 'useExpose', undefined, useExposeHelperId), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, lib.includes('vapor') - ? `${importHelperFn(s, 0, 'currentInstance', 'vue')}, ` - : `${importHelperFn(s, 0, 'getCurrentInstance', 'vue')}(), `, + ? `${importHelperFn(s, 0, 'currentInstance')}, ` + : `${importHelperFn(s, 0, 'getCurrentInstance')}(), `, ) } diff --git a/packages/jsx-macros/src/core/define-model.ts b/packages/jsx-macros/src/core/define-model.ts index cbf5ce577..0423717cc 100644 --- a/packages/jsx-macros/src/core/define-model.ts +++ b/packages/jsx-macros/src/core/define-model.ts @@ -9,7 +9,7 @@ export function transformDefineModel( ): void { s.overwriteNode( node.callee, - importHelperFn(s, 0, 'useModel', useModelHelperId), + importHelperFn(s, 0, 'useModel', undefined, useModelHelperId), ) s.appendRight( node.arguments[0]?.start || node.end! - 1, diff --git a/packages/jsx-macros/src/core/define-slots.ts b/packages/jsx-macros/src/core/define-slots.ts index 15e72fd39..de3e762c6 100644 --- a/packages/jsx-macros/src/core/define-slots.ts +++ b/packages/jsx-macros/src/core/define-slots.ts @@ -15,7 +15,7 @@ export function transformDefineSlots( `Object.assign`, ) const slots = lib.includes('vue') - ? `${importHelperFn(s, 0, 'useSlots', 'vue')}()` + ? `${importHelperFn(s, 0, 'useSlots')}()` : `${propsName}.vSlots` s.appendLeft(node.end! - 1, `${node.arguments[0] ? ',' : '{}, '}${slots}`) } diff --git a/packages/jsx-macros/src/core/restructure.ts b/packages/jsx-macros/src/core/restructure.ts index b1ffca341..134c91fd5 100644 --- a/packages/jsx-macros/src/core/restructure.ts +++ b/packages/jsx-macros/src/core/restructure.ts @@ -67,6 +67,7 @@ export function restructure( s, 0, 'createPropsDefaultProxy', + undefined, options.withDefaultsFrom ?? withDefaultsHelperId, ) const resolvedPath = path.replace( @@ -94,7 +95,6 @@ export function restructure( s, 0, 'createPropsRestProxy', - 'vue', )}(${rest.path}, [${rest.value}])`, ) } From 2cb3a92906c276a9ed5eb7629e2b5c28c74e5c16 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 14 Mar 2025 10:06:22 +0800 Subject: [PATCH 155/156] fix: lint --- packages/jsx-macros/package.json | 4 ++-- pnpm-workspace.yaml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/jsx-macros/package.json b/packages/jsx-macros/package.json index 3db8e9eaf..b95042232 100644 --- a/packages/jsx-macros/package.json +++ b/packages/jsx-macros/package.json @@ -108,11 +108,11 @@ "dependencies": { "@vue-macros/common": "workspace:*", "@vue/compiler-sfc": "catalog:", - "hash-sum": "^2.0.0", + "hash-sum": "catalog:", "unplugin": "catalog:" }, "devDependencies": { - "@types/hash-sum": "^1.0.2", + "@types/hash-sum": "catalog:", "vue": "catalog:" }, "engines": { diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4de0bb018..20bbc605c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -15,8 +15,10 @@ defines: catalog: '@babel/parser': *babel '@babel/types': *babel + '@types/hash-sum': ^1.0.2 '@vue/language-core': *volar + hash-sum: ^2.0.0 vue-tsc: *volar '@vitest/coverage-v8': *vitest From 0bbb422690eab28ff9001592390e05c612d036e1 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <260480378@qq.com> Date: Fri, 14 Mar 2025 10:06:46 +0800 Subject: [PATCH 156/156] fix: build --- pnpm-lock.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 712c6bcab..1414a74ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,6 +66,9 @@ catalogs: '@sxzz/test-utils': specifier: ^0.5.2 version: 0.5.2 + '@types/hash-sum': + specifier: ^1.0.2 + version: 1.0.2 '@types/node': specifier: ^22.13.10 version: 22.13.10 @@ -135,6 +138,9 @@ catalogs: get-port: specifier: ^7.1.0 version: 7.1.0 + hash-sum: + specifier: ^2.0.0 + version: 2.0.0 jiti: specifier: ^2.4.2 version: 2.4.2 @@ -900,14 +906,14 @@ importers: specifier: 'catalog:' version: 3.5.13 hash-sum: - specifier: ^2.0.0 + specifier: 'catalog:' version: 2.0.0 unplugin: specifier: 'catalog:' version: 2.2.0 devDependencies: '@types/hash-sum': - specifier: ^1.0.2 + specifier: 'catalog:' version: 1.0.2 vue: specifier: 'catalog:'