mirror of
https://github.com/vuejs/babel-plugin-jsx.git
synced 2025-01-10 08:19:10 +08:00
refactor: upgrade project setup (#646)
This commit is contained in:
parent
687be8aca8
commit
dbba3205e4
@ -1,30 +0,0 @@
|
|||||||
version: 2.1
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
docker:
|
|
||||||
# specify the version you desire here
|
|
||||||
- image: vuejs/ci
|
|
||||||
user: node
|
|
||||||
|
|
||||||
working_directory: /home/node/repo
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
|
|
||||||
# Download and cache dependencies
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- v2-dependencies-{{ checksum "yarn.lock" }}
|
|
||||||
|
|
||||||
- run: yarn install --pure-lockfile
|
|
||||||
|
|
||||||
- save_cache:
|
|
||||||
paths:
|
|
||||||
- node_modules
|
|
||||||
- ~/.cache/yarn
|
|
||||||
key: v2-dependencies-{{ checksum "yarn.lock" }}
|
|
||||||
|
|
||||||
- run: yarn lint
|
|
||||||
|
|
||||||
# run tests!
|
|
||||||
- run: yarn test
|
|
@ -1 +1,3 @@
|
|||||||
dist
|
dist
|
||||||
|
coverage
|
||||||
|
node_modules
|
||||||
|
70
.eslintrc.js
70
.eslintrc.js
@ -1,34 +1,60 @@
|
|||||||
|
const { builtinModules } = require('node:module');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
project: './tsconfig.json',
|
|
||||||
},
|
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
node: true,
|
node: true,
|
||||||
jest: true,
|
|
||||||
es6: true,
|
es6: true,
|
||||||
},
|
},
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
plugins: ['@typescript-eslint', 'import'],
|
|
||||||
extends: [
|
extends: [
|
||||||
'airbnb-typescript/base',
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'prettier',
|
||||||
],
|
],
|
||||||
|
plugins: ['import'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
sourceType: 'module',
|
||||||
|
ecmaFeatures: {
|
||||||
|
jsx: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
rules: {
|
rules: {
|
||||||
'no-nested-ternary': [0],
|
eqeqeq: ['warn', 'always', { null: 'never' }],
|
||||||
'no-param-reassign': [0],
|
'no-debugger': ['error'],
|
||||||
'no-use-before-define': [0],
|
'no-empty': ['warn', { allowEmptyCatch: true }],
|
||||||
'no-restricted-syntax': [0],
|
'prefer-const': [
|
||||||
'no-plusplus': [0],
|
'warn',
|
||||||
'import/no-extraneous-dependencies': [0],
|
{
|
||||||
'consistent-return': [0],
|
destructuring: 'all',
|
||||||
'no-bitwise': [0],
|
},
|
||||||
'@typescript-eslint/no-use-before-define': [0],
|
],
|
||||||
'prefer-destructuring': [2, { array: false }],
|
'@typescript-eslint/ban-ts-comment': 'off',
|
||||||
'max-len': [0],
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/consistent-type-imports': [
|
||||||
|
'error',
|
||||||
|
{ prefer: 'type-imports', fixStyle: 'inline-type-imports' },
|
||||||
|
],
|
||||||
|
|
||||||
|
'import/no-nodejs-modules': [
|
||||||
|
'error',
|
||||||
|
{ allow: builtinModules.map((mod) => `node:${mod}`) },
|
||||||
|
],
|
||||||
|
'import/no-duplicates': 'error',
|
||||||
|
'import/order': 'error',
|
||||||
|
'sort-imports': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignoreCase: false,
|
||||||
|
ignoreDeclarationSort: true,
|
||||||
|
ignoreMemberSort: false,
|
||||||
|
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
|
||||||
|
allowSeparatedGroups: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -8,16 +8,13 @@ assignees:
|
|||||||
|
|
||||||
### 🐛 Bug description
|
### 🐛 Bug description
|
||||||
|
|
||||||
|
|
||||||
<!-- Please describe the bug in detail above so that everyone can understand. -->
|
<!-- Please describe the bug in detail above so that everyone can understand. -->
|
||||||
|
|
||||||
### 🏞 Desired result
|
### 🏞 Desired result
|
||||||
|
|
||||||
|
|
||||||
<!-- Please describe above what you expected to see. -->
|
<!-- Please describe above what you expected to see. -->
|
||||||
|
|
||||||
### 🚑 Other information
|
### 🚑 Other information
|
||||||
|
|
||||||
|
|
||||||
<!-- Please enter other information such as screenshots above. -->
|
<!-- Please enter other information such as screenshots above. -->
|
||||||
<!-- From: https://github.com/one-template/issue-template -->
|
<!-- From: https://github.com/one-template/issue-template -->
|
||||||
|
3
.github/ISSUE_TEMPLATE/question.md
vendored
3
.github/ISSUE_TEMPLATE/question.md
vendored
@ -8,16 +8,13 @@ assignees: ''
|
|||||||
|
|
||||||
### 🧐 Problem Description
|
### 🧐 Problem Description
|
||||||
|
|
||||||
|
|
||||||
<!-- Describe the problem in detail so that everyone can understand. -->
|
<!-- Describe the problem in detail so that everyone can understand. -->
|
||||||
|
|
||||||
### 💻 Sample code
|
### 💻 Sample code
|
||||||
|
|
||||||
|
|
||||||
<!-- If you have a solution, state it clearly here. -->
|
<!-- If you have a solution, state it clearly here. -->
|
||||||
|
|
||||||
### 🚑 Other information
|
### 🚑 Other information
|
||||||
|
|
||||||
|
|
||||||
<!-- Other information such as screenshots can be posted here. -->
|
<!-- Other information such as screenshots can be posted here. -->
|
||||||
<!-- From: https://github.com/one-template/issue-template -->
|
<!-- From: https://github.com/one-template/issue-template -->
|
||||||
|
25
.github/renovate.json5
vendored
Normal file
25
.github/renovate.json5
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
$schema: 'https://docs.renovatebot.com/renovate-schema.json',
|
||||||
|
extends: [
|
||||||
|
'config:base',
|
||||||
|
'schedule:weekly',
|
||||||
|
'group:allNonMajor',
|
||||||
|
':semanticCommitTypeAll(chore)',
|
||||||
|
],
|
||||||
|
labels: ['dependencies'],
|
||||||
|
pin: false,
|
||||||
|
rangeStrategy: 'bump',
|
||||||
|
node: false,
|
||||||
|
packageRules: [
|
||||||
|
{
|
||||||
|
depTypeList: ['peerDependencies'],
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ignoreDeps: [
|
||||||
|
'typescript',
|
||||||
|
|
||||||
|
// Pure ESM
|
||||||
|
'camelcase',
|
||||||
|
],
|
||||||
|
}
|
67
.github/workflows/ci.yml
vendored
Normal file
67
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
timeout-minutes: 20
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Unit Test
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- name: Install deps
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Test unit
|
||||||
|
run: pnpm run test
|
||||||
|
|
||||||
|
lint:
|
||||||
|
timeout-minutes: 10
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Lint
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- name: Install deps
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: pnpm run lint
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: pnpm prettier --check .
|
||||||
|
|
||||||
|
- name: Typecheck
|
||||||
|
run: pnpm run typecheck
|
4
.github/workflows/issue-reply.yml
vendored
4
.github/workflows/issue-reply.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: help wanted
|
- name: help wanted
|
||||||
if: github.event.label.name == 'help wanted'
|
if: github.event.label.name == 'help wanted'
|
||||||
uses: actions-cool/issues-helper@v2.5.0
|
uses: actions-cool/issues-helper@v3
|
||||||
with:
|
with:
|
||||||
actions: 'create-comment'
|
actions: 'create-comment'
|
||||||
issue-number: ${{ github.event.issue.number }}
|
issue-number: ${{ github.event.issue.number }}
|
||||||
@ -19,7 +19,7 @@ jobs:
|
|||||||
|
|
||||||
- name: need reproduction
|
- name: need reproduction
|
||||||
if: github.event.label.name == 'need reproduction'
|
if: github.event.label.name == 'need reproduction'
|
||||||
uses: actions-cool/issues-helper@v2.5.0
|
uses: actions-cool/issues-helper@v3
|
||||||
with:
|
with:
|
||||||
actions: 'create-comment'
|
actions: 'create-comment'
|
||||||
issue-number: ${{ github.event.issue.number }}
|
issue-number: ${{ github.event.issue.number }}
|
||||||
|
40
.github/workflows/release.yml
vendored
Normal file
40
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
|
||||||
|
- name: Set node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
cache: pnpm
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
||||||
|
- run: npx changelogithub
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: pnpm i
|
||||||
|
|
||||||
|
- name: PNPM build
|
||||||
|
run: pnpm run build
|
||||||
|
|
||||||
|
- name: Publish to NPM
|
||||||
|
run: pnpm -r publish --access public --no-git-checks
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,10 +1,7 @@
|
|||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
pnpm-debug.log*
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
coverage
|
||||||
|
pnpm-lock.yaml
|
||||||
|
CHANGELOG.md
|
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
3
global.d.ts
vendored
3
global.d.ts
vendored
@ -1,3 +0,0 @@
|
|||||||
declare module '*.js';
|
|
||||||
declare module '@babel/helper-module-imports';
|
|
||||||
declare module '@babel/plugin-syntax-jsx';
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"npmClient": "yarn",
|
|
||||||
"useWorkspaces": true,
|
|
||||||
"packages": [
|
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"version": "1.1.1"
|
|
||||||
}
|
|
6
netlify.toml
Normal file
6
netlify.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[build.environment]
|
||||||
|
NODE_VERSION = "18"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
command = "pnpm run build"
|
||||||
|
publish = "packages/jsx-explorer/dist"
|
38
package.json
38
package.json
@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"packageManager": "pnpm@8.6.2",
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"publish": "lerna publish",
|
"build": "pnpm run -r build",
|
||||||
"test": "lerna run test",
|
"test": "vitest",
|
||||||
"lint": "lerna run lint",
|
"lint": "eslint --cache .",
|
||||||
"dev": "node scripts/dev.js",
|
"format": "prettier --write .",
|
||||||
"site": "node scripts/site.js"
|
"typecheck": "tsc --noEmit",
|
||||||
|
"release": "bumpp -r"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -16,13 +15,20 @@
|
|||||||
"jsx"
|
"jsx"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
"@rollup/plugin-babel": "^6.0.3",
|
||||||
"eslint": "^7.32.0",
|
"@types/babel__core": "^7.20.1",
|
||||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
"@types/node": "^20.3.1",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||||
"lerna": "^3.22.1"
|
"@vitest/coverage-v8": "^0.32.2",
|
||||||
},
|
"bumpp": "^9.1.1",
|
||||||
"resolutions": {
|
"eslint": "^8.43.0",
|
||||||
"@types/node": "18.8.0"
|
"eslint-config-prettier": "^8.8.0",
|
||||||
|
"eslint-plugin-import": "^2.27.5",
|
||||||
|
"jsdom": "^22.1.0",
|
||||||
|
"prettier": "^2.8.8",
|
||||||
|
"tsup": "^7.0.0",
|
||||||
|
"typescript": "^5.1.3",
|
||||||
|
"vite": "^4.3.9",
|
||||||
|
"vitest": "^0.32.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
packages/babel-helper-vue-transform-on/index.d.ts
vendored
Normal file
4
packages/babel-helper-vue-transform-on/index.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare function transformOn(
|
||||||
|
obj: Record<string, any>
|
||||||
|
): Record<`on${string}`, any>;
|
||||||
|
export default transformOn;
|
@ -1,7 +1,7 @@
|
|||||||
const transformOn = (obj) => {
|
const transformOn = (obj) => {
|
||||||
const result = {};
|
const result = {};
|
||||||
Object.keys(obj).forEach((evt) => {
|
Object.keys(obj).forEach((evt) => {
|
||||||
result[`on${evt[0].toUpperCase()}${evt.substr(1)}`] = obj[evt];
|
result[`on${evt[0].toUpperCase()}${evt.slice(1)}`] = obj[evt];
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
@ -4,5 +4,6 @@
|
|||||||
"description": "to help transform on",
|
"description": "to help transform on",
|
||||||
"author": "Amour1688 <lcz_1996@foxmail.com>",
|
"author": "Amour1688 <lcz_1996@foxmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "index.js"
|
"main": "index.js",
|
||||||
|
"types": "index.d.ts"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Vue 3 Babel JSX 插件
|
# Vue 3 Babel JSX 插件
|
||||||
|
|
||||||
[![CircleCI](https://circleci.com/gh/vuejs/babel-plugin-jsx.svg?style=svg)](https://circleci.com/gh/vuejs/vue-next) [![npm package](https://img.shields.io/npm/v/@vue/babel-plugin-jsx.svg?style=flat-square)](https://www.npmjs.com/package/@vue/babel-plugin-jsx)
|
[![npm package](https://img.shields.io/npm/v/@vue/babel-plugin-jsx.svg?style=flat-square)](https://www.npmjs.com/package/@vue/babel-plugin-jsx)
|
||||||
[![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-orange?style=flat-square)](https://github.com/actions-cool/issues-helper)
|
[![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-orange?style=flat-square)](https://github.com/actions-cool/issues-helper)
|
||||||
|
|
||||||
以 JSX 的方式来编写 Vue 代码
|
以 JSX 的方式来编写 Vue 代码
|
||||||
@ -92,7 +92,7 @@ const App = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import { withModifiers, defineComponent } from "vue";
|
import { withModifiers, defineComponent } from 'vue';
|
||||||
|
|
||||||
const App = defineComponent({
|
const App = defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
@ -103,7 +103,7 @@ const App = defineComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div onClick={withModifiers(inc, ["self"])}>{count.value}</div>
|
<div onClick={withModifiers(inc, ['self'])}>{count.value}</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -129,7 +129,7 @@ const App = () => <input type="email" />;
|
|||||||
动态绑定:
|
动态绑定:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const placeholderText = "email";
|
const placeholderText = 'email';
|
||||||
const App = () => <input type="email" placeholder={placeholderText} />;
|
const App = () => <input type="email" placeholder={placeholderText} />;
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -161,11 +161,11 @@ const App = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<input v-model={[val, ["modifier"]]} />
|
<input v-model={[val, ['modifier']]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<A v-model={[val, "argument", ["modifier"]]} />
|
<A v-model={[val, 'argument', ['modifier']]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
会编译成:
|
会编译成:
|
||||||
@ -176,7 +176,7 @@ h(A, {
|
|||||||
argumentModifiers: {
|
argumentModifiers: {
|
||||||
modifier: true,
|
modifier: true,
|
||||||
},
|
},
|
||||||
"onUpdate:argument": ($event) => (val = $event),
|
'onUpdate:argument': ($event) => (val = $event),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -185,14 +185,14 @@ h(A, {
|
|||||||
> 注意: 你应该传递一个二维数组给 v-models。
|
> 注意: 你应该传递一个二维数组给 v-models。
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<A v-models={[[foo], [bar, "bar"]]} />
|
<A v-models={[[foo], [bar, 'bar']]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<A
|
<A
|
||||||
v-models={[
|
v-models={[
|
||||||
[foo, "foo"],
|
[foo, 'foo'],
|
||||||
[bar, "bar"],
|
[bar, 'bar'],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
@ -200,8 +200,8 @@ h(A, {
|
|||||||
```jsx
|
```jsx
|
||||||
<A
|
<A
|
||||||
v-models={[
|
v-models={[
|
||||||
[foo, ["modifier"]],
|
[foo, ['modifier']],
|
||||||
[bar, "bar", ["modifier"]],
|
[bar, 'bar', ['modifier']],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
@ -214,12 +214,12 @@ h(A, {
|
|||||||
modelModifiers: {
|
modelModifiers: {
|
||||||
modifier: true,
|
modifier: true,
|
||||||
},
|
},
|
||||||
"onUpdate:modelValue": ($event) => (foo = $event),
|
'onUpdate:modelValue': ($event) => (foo = $event),
|
||||||
bar: bar,
|
bar: bar,
|
||||||
barModifiers: {
|
barModifiers: {
|
||||||
modifier: true,
|
modifier: true,
|
||||||
},
|
},
|
||||||
"onUpdate:bar": ($event) => (bar = $event),
|
'onUpdate:bar': ($event) => (bar = $event),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ const App = {
|
|||||||
const App = {
|
const App = {
|
||||||
directives: { custom: customDirective },
|
directives: { custom: customDirective },
|
||||||
setup() {
|
setup() {
|
||||||
return () => <a v-custom={[val, "arg", ["a", "b"]]} />;
|
return () => <a v-custom={[val, 'arg', ['a', 'b']]} />;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@ -252,8 +252,8 @@ const App = {
|
|||||||
```jsx
|
```jsx
|
||||||
const A = (props, { slots }) => (
|
const A = (props, { slots }) => (
|
||||||
<>
|
<>
|
||||||
<h1>{ slots.default ? slots.default() : 'foo' }</h1>
|
<h1>{slots.default ? slots.default() : 'foo'}</h1>
|
||||||
<h2>{ slots.bar?.() }</h2>
|
<h2>{slots.bar?.()}</h2>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ const App = {
|
|||||||
bar: () => <span>B</span>,
|
bar: () => <span>B</span>,
|
||||||
}}
|
}}
|
||||||
</A>
|
</A>
|
||||||
<B>{() => "foo"}</B>
|
<B>{() => 'foo'}</B>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Babel Plugin JSX for Vue 3.0
|
# Babel Plugin JSX for Vue 3
|
||||||
|
|
||||||
[![CircleCI](https://circleci.com/gh/vuejs/babel-plugin-jsx.svg?style=svg)](https://circleci.com/gh/vuejs/babel-plugin-jsx) [![npm package](https://img.shields.io/npm/v/@vue/babel-plugin-jsx.svg?style=flat-square)](https://www.npmjs.com/package/@vue/babel-plugin-jsx)
|
[![npm package](https://img.shields.io/npm/v/@vue/babel-plugin-jsx.svg?style=flat-square)](https://www.npmjs.com/package/@vue/babel-plugin-jsx)
|
||||||
[![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-blueviolet?style=flat-square)](https://github.com/actions-cool/issues-helper)
|
[![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-blueviolet?style=flat-square)](https://github.com/actions-cool/issues-helper)
|
||||||
|
|
||||||
To add Vue JSX support.
|
To add Vue JSX support.
|
||||||
@ -96,7 +96,7 @@ const App = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import { withModifiers, defineComponent } from "vue";
|
import { withModifiers, defineComponent } from 'vue';
|
||||||
|
|
||||||
const App = defineComponent({
|
const App = defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
@ -107,7 +107,7 @@ const App = defineComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div onClick={withModifiers(inc, ["self"])}>{count.value}</div>
|
<div onClick={withModifiers(inc, ['self'])}>{count.value}</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -133,7 +133,7 @@ const App = () => <input type="email" />;
|
|||||||
with a dynamic binding:
|
with a dynamic binding:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const placeholderText = "email";
|
const placeholderText = 'email';
|
||||||
const App = () => <input type="email" placeholder={placeholderText} />;
|
const App = () => <input type="email" placeholder={placeholderText} />;
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -165,11 +165,11 @@ const App = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<input v-model={[val, ["modifier"]]} />
|
<input v-model={[val, ['modifier']]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<A v-model={[val, "argument", ["modifier"]]} />
|
<A v-model={[val, 'argument', ['modifier']]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
Will compile to:
|
Will compile to:
|
||||||
@ -180,7 +180,7 @@ h(A, {
|
|||||||
argumentModifiers: {
|
argumentModifiers: {
|
||||||
modifier: true,
|
modifier: true,
|
||||||
},
|
},
|
||||||
"onUpdate:argument": ($event) => (val = $event),
|
'onUpdate:argument': ($event) => (val = $event),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -189,14 +189,14 @@ h(A, {
|
|||||||
> Note: You should pass a Two-dimensional Arrays to v-models.
|
> Note: You should pass a Two-dimensional Arrays to v-models.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<A v-models={[[foo], [bar, "bar"]]} />
|
<A v-models={[[foo], [bar, 'bar']]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<A
|
<A
|
||||||
v-models={[
|
v-models={[
|
||||||
[foo, "foo"],
|
[foo, 'foo'],
|
||||||
[bar, "bar"],
|
[bar, 'bar'],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
@ -204,8 +204,8 @@ h(A, {
|
|||||||
```jsx
|
```jsx
|
||||||
<A
|
<A
|
||||||
v-models={[
|
v-models={[
|
||||||
[foo, ["modifier"]],
|
[foo, ['modifier']],
|
||||||
[bar, "bar", ["modifier"]],
|
[bar, 'bar', ['modifier']],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
@ -218,12 +218,12 @@ h(A, {
|
|||||||
modelModifiers: {
|
modelModifiers: {
|
||||||
modifier: true,
|
modifier: true,
|
||||||
},
|
},
|
||||||
"onUpdate:modelValue": ($event) => (foo = $event),
|
'onUpdate:modelValue': ($event) => (foo = $event),
|
||||||
bar: bar,
|
bar: bar,
|
||||||
barModifiers: {
|
barModifiers: {
|
||||||
modifier: true,
|
modifier: true,
|
||||||
},
|
},
|
||||||
"onUpdate:bar": ($event) => (bar = $event),
|
'onUpdate:bar': ($event) => (bar = $event),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ const App = {
|
|||||||
const App = {
|
const App = {
|
||||||
directives: { custom: customDirective },
|
directives: { custom: customDirective },
|
||||||
setup() {
|
setup() {
|
||||||
return () => <a v-custom={[val, "arg", ["a", "b"]]} />;
|
return () => <a v-custom={[val, 'arg', ['a', 'b']]} />;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@ -256,8 +256,8 @@ const App = {
|
|||||||
```jsx
|
```jsx
|
||||||
const A = (props, { slots }) => (
|
const A = (props, { slots }) => (
|
||||||
<>
|
<>
|
||||||
<h1>{ slots.default ? slots.default() : 'foo' }</h1>
|
<h1>{slots.default ? slots.default() : 'foo'}</h1>
|
||||||
<h2>{ slots.bar?.() }</h2>
|
<h2>{slots.bar?.()}</h2>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ const App = {
|
|||||||
bar: () => <span>B</span>,
|
bar: () => <span>B</span>,
|
||||||
}}
|
}}
|
||||||
</A>
|
</A>
|
||||||
<B>{() => "foo"}</B>
|
<B>{() => 'foo'}</B>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
/* istanbul ignore next */
|
|
||||||
module.exports = {
|
|
||||||
presets: [
|
|
||||||
'@babel/preset-env',
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
/* eslint-disable-next-line global-require */
|
|
||||||
[require('./dist/index.js'), { optimize: true, isCustomElement: (tag) => /^x-/.test(tag) }],
|
|
||||||
],
|
|
||||||
};
|
|
2
packages/babel-plugin-jsx/global.d.ts
vendored
2
packages/babel-plugin-jsx/global.d.ts
vendored
@ -1,2 +0,0 @@
|
|||||||
declare module '@babel/helper-module-imports';
|
|
||||||
declare module '@babel/plugin-syntax-jsx';
|
|
@ -1,11 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
setupFiles: ['./test/setup.ts'],
|
|
||||||
transform: {
|
|
||||||
'\\.(ts|tsx)$': 'ts-jest',
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
'ts-jest': {
|
|
||||||
babelConfig: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,21 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "@vue/babel-plugin-jsx",
|
"name": "@vue/babel-plugin-jsx",
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"description": "Babel plugin for Vue 3.0 JSX",
|
"description": "Babel plugin for Vue 3 JSX",
|
||||||
"author": "Amour1688 <lcz_1996@foxmail.com>",
|
"author": "Amour1688 <lcz_1996@foxmail.com>",
|
||||||
"homepage": "https://github.com/vuejs/babel-plugin-jsx/tree/dev/packages/babel-plugin-jsx#readme",
|
"homepage": "https://github.com/vuejs/babel-plugin-jsx/tree/dev/packages/babel-plugin-jsx#readme",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.mjs",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/vuejs/babel-plugin-jsx.git"
|
"url": "git+https://github.com/vuejs/babel-plugin-jsx.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rm -rf dist && tsc",
|
"build": "tsup",
|
||||||
"watch": "rm -rf dist && tsc --watch",
|
"watch": "tsup --watch"
|
||||||
"lint": "eslint 'src/*.ts'",
|
|
||||||
"test": "yarn build && jest --coverage",
|
|
||||||
"prepublishOnly": "yarn build"
|
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/vuejs/babel-plugin-jsx/issues"
|
"url": "https://github.com/vuejs/babel-plugin-jsx/issues"
|
||||||
@ -24,30 +23,26 @@
|
|||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-module-imports": "^7.18.6",
|
"@babel/helper-module-imports": "^7.22.5",
|
||||||
"@babel/plugin-syntax-jsx": "^7.18.6",
|
"@babel/plugin-syntax-jsx": "^7.22.5",
|
||||||
"@babel/template": "^7.18.10",
|
"@babel/template": "^7.22.5",
|
||||||
"@babel/traverse": "^7.19.4",
|
"@babel/traverse": "^7.22.5",
|
||||||
"@babel/types": "^7.19.4",
|
"@babel/types": "^7.22.5",
|
||||||
"@vue/babel-helper-vue-transform-on": "^1.0.2",
|
"@vue/babel-helper-vue-transform-on": "workspace:^",
|
||||||
"camelcase": "^6.3.0",
|
"camelcase": "^6.3.0",
|
||||||
"html-tags": "^3.2.0",
|
"html-tags": "^3.3.1",
|
||||||
"svg-tags": "^1.0.0"
|
"svg-tags": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.19.3",
|
"@babel/core": "^7.22.5",
|
||||||
"@babel/preset-env": "^7.19.4",
|
"@babel/preset-env": "^7.22.5",
|
||||||
"@types/jest": "^26.0.24",
|
"@types/babel__template": "^7.4.1",
|
||||||
|
"@types/babel__traverse": "^7.20.1",
|
||||||
"@types/svg-tags": "^1.0.0",
|
"@types/svg-tags": "^1.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
"@vue/runtime-dom": "^3.3.4",
|
||||||
"@typescript-eslint/parser": "^4.33.0",
|
"@vue/test-utils": "^2.3.2",
|
||||||
"@vue/compiler-dom": "3.2.41",
|
"regenerator-runtime": "^0.13.11",
|
||||||
"@vue/test-utils": "2.0.0-beta.2",
|
"vue": "^3.3.4"
|
||||||
"jest": "^26.6.3",
|
|
||||||
"regenerator-runtime": "^0.13.10",
|
|
||||||
"ts-jest": "^26.5.6",
|
|
||||||
"typescript": "^4.8.4",
|
|
||||||
"vue": "3.2.41"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@babel/core": "^7.0.0-0"
|
"@babel/core": "^7.0.0-0"
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import * as BabelCore from '@babel/core';
|
import type * as BabelCore from '@babel/core';
|
||||||
import template from '@babel/template';
|
import template from '@babel/template';
|
||||||
|
// @ts-expect-error
|
||||||
import syntaxJsx from '@babel/plugin-syntax-jsx';
|
import syntaxJsx from '@babel/plugin-syntax-jsx';
|
||||||
import { addNamed, isModule, addNamespace } from '@babel/helper-module-imports';
|
// @ts-expect-error
|
||||||
import { NodePath } from '@babel/traverse';
|
import { addNamed, addNamespace, isModule } from '@babel/helper-module-imports';
|
||||||
|
import { type NodePath } from '@babel/traverse';
|
||||||
import transformVueJSX from './transform-vue-jsx';
|
import transformVueJSX from './transform-vue-jsx';
|
||||||
import sugarFragment from './sugar-fragment';
|
import sugarFragment from './sugar-fragment';
|
||||||
import type { VueJSXPluginOptions, State } from './interface';
|
import type { State, VueJSXPluginOptions } from './interface';
|
||||||
|
|
||||||
export { VueJSXPluginOptions };
|
export { VueJSXPluginOptions };
|
||||||
|
|
||||||
@ -77,7 +79,7 @@ export default ({ types }: typeof BabelCore) => ({
|
|||||||
return importMap.runtimeIsSlot;
|
return importMap.runtimeIsSlot;
|
||||||
}
|
}
|
||||||
const { name: isVNodeName } = state.get(
|
const { name: isVNodeName } = state.get(
|
||||||
'isVNode',
|
'isVNode'
|
||||||
)() as t.Identifier;
|
)() as t.Identifier;
|
||||||
const isSlot = path.scope.generateUidIdentifier('isSlot');
|
const isSlot = path.scope.generateUidIdentifier('isSlot');
|
||||||
const ast = template.ast`
|
const ast = template.ast`
|
||||||
@ -119,21 +121,24 @@ export default ({ types }: typeof BabelCore) => ({
|
|||||||
}
|
}
|
||||||
const isSlot = path.scope.generateUidIdentifier('isSlot');
|
const isSlot = path.scope.generateUidIdentifier('isSlot');
|
||||||
const { object: objectName } = state.get(
|
const { object: objectName } = state.get(
|
||||||
'isVNode',
|
'isVNode'
|
||||||
)() as t.MemberExpression;
|
)() as t.MemberExpression;
|
||||||
const ast = template.ast`
|
const ast = template.ast`
|
||||||
function ${isSlot.name}(s) {
|
function ${isSlot.name}(s) {
|
||||||
return typeof s === 'function' || (Object.prototype.toString.call(s) === '[object Object]' && !${(objectName as t.Identifier).name}.isVNode(s));
|
return typeof s === 'function' || (Object.prototype.toString.call(s) === '[object Object]' && !${
|
||||||
|
(objectName as t.Identifier).name
|
||||||
|
}.isVNode(s));
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const nodePaths = path.get('body') as NodePath[];
|
const nodePaths = path.get('body') as NodePath[];
|
||||||
const lastImport = nodePaths
|
const lastImport = nodePaths
|
||||||
.filter(
|
.filter(
|
||||||
(p) => p.isVariableDeclaration()
|
(p) =>
|
||||||
&& p.node.declarations.some(
|
p.isVariableDeclaration() &&
|
||||||
(d) => (d.id as t.Identifier)?.name === sourceName.name,
|
p.node.declarations.some(
|
||||||
),
|
(d) => (d.id as t.Identifier)?.name === sourceName.name
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.pop();
|
.pop();
|
||||||
if (lastImport) {
|
if (lastImport) {
|
||||||
@ -169,17 +174,18 @@ export default ({ types }: typeof BabelCore) => ({
|
|||||||
|
|
||||||
body
|
body
|
||||||
.filter(
|
.filter(
|
||||||
(nodePath) => t.isImportDeclaration(nodePath.node)
|
(nodePath) =>
|
||||||
&& nodePath.node.source.value === 'vue',
|
t.isImportDeclaration(nodePath.node) &&
|
||||||
|
nodePath.node.source.value === 'vue'
|
||||||
)
|
)
|
||||||
.forEach((nodePath) => {
|
.forEach((nodePath) => {
|
||||||
const { specifiers } = nodePath.node as t.ImportDeclaration;
|
const { specifiers } = nodePath.node as t.ImportDeclaration;
|
||||||
let shouldRemove = false;
|
let shouldRemove = false;
|
||||||
specifiers.forEach((specifier) => {
|
specifiers.forEach((specifier) => {
|
||||||
if (
|
if (
|
||||||
!specifier.loc
|
!specifier.loc &&
|
||||||
&& t.isImportSpecifier(specifier)
|
t.isImportSpecifier(specifier) &&
|
||||||
&& t.isIdentifier(specifier.imported)
|
t.isIdentifier(specifier.imported)
|
||||||
) {
|
) {
|
||||||
specifiersMap.set(specifier.imported.name, specifier);
|
specifiersMap.set(specifier.imported.name, specifier);
|
||||||
shouldRemove = true;
|
shouldRemove = true;
|
||||||
@ -191,12 +197,12 @@ export default ({ types }: typeof BabelCore) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const specifiers = [...specifiersMap.keys()].map(
|
const specifiers = [...specifiersMap.keys()].map(
|
||||||
(imported) => specifiersMap.get(imported)!,
|
(imported) => specifiersMap.get(imported)!
|
||||||
);
|
);
|
||||||
if (specifiers.length) {
|
if (specifiers.length) {
|
||||||
path.unshiftContainer(
|
path.unshiftContainer(
|
||||||
'body',
|
'body',
|
||||||
t.importDeclaration(specifiers, t.stringLiteral('vue')),
|
t.importDeclaration(specifiers, t.stringLiteral('vue'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as t from '@babel/types';
|
import type * as t from '@babel/types';
|
||||||
import * as BabelCore from '@babel/core';
|
import type * as BabelCore from '@babel/core';
|
||||||
|
|
||||||
export type Slots = t.Identifier | t.ObjectExpression | null;
|
export type Slots = t.Identifier | t.ObjectExpression | null;
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ export type State = {
|
|||||||
get: (name: string) => any;
|
get: (name: string) => any;
|
||||||
set: (name: string, value: any) => any;
|
set: (name: string, value: any) => any;
|
||||||
opts: VueJSXPluginOptions;
|
opts: VueJSXPluginOptions;
|
||||||
file: BabelCore.BabelFile
|
file: BabelCore.BabelFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface VueJSXPluginOptions {
|
export interface VueJSXPluginOptions {
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import { NodePath } from '@babel/traverse';
|
import { type NodePath } from '@babel/traverse';
|
||||||
import { createIdentifier } from './utils';
|
import { createIdentifier } from './utils';
|
||||||
import type { State } from './interface';
|
import type { State } from './interface';
|
||||||
|
|
||||||
export type Tag = t.Identifier | t.MemberExpression | t.StringLiteral | t.CallExpression;
|
export type Tag =
|
||||||
|
| t.Identifier
|
||||||
|
| t.MemberExpression
|
||||||
|
| t.StringLiteral
|
||||||
|
| t.CallExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get JSX element type
|
* Get JSX element type
|
||||||
@ -11,37 +15,35 @@ export type Tag = t.Identifier | t.MemberExpression | t.StringLiteral | t.CallEx
|
|||||||
* @param path Path<JSXOpeningElement>
|
* @param path Path<JSXOpeningElement>
|
||||||
*/
|
*/
|
||||||
const getType = (path: NodePath<t.JSXOpeningElement>) => {
|
const getType = (path: NodePath<t.JSXOpeningElement>) => {
|
||||||
const typePath = path
|
const typePath = path.get('attributes').find((attribute) => {
|
||||||
.get('attributes')
|
if (!attribute.isJSXAttribute()) {
|
||||||
.find((attribute) => {
|
|
||||||
if (!t.isJSXAttribute(attribute)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return t.isJSXIdentifier(attribute.get('name'))
|
return (
|
||||||
&& (attribute.get('name') as NodePath<t.JSXIdentifier>).node.name === 'type';
|
attribute.get('name').isJSXIdentifier() &&
|
||||||
|
(attribute.get('name') as NodePath<t.JSXIdentifier>).node.name === 'type'
|
||||||
|
);
|
||||||
}) as NodePath<t.JSXAttribute> | undefined;
|
}) as NodePath<t.JSXAttribute> | undefined;
|
||||||
|
|
||||||
return typePath ? typePath.get('value').node : null;
|
return typePath ? typePath.get('value').node : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseModifiers = (value: any): string[] => (
|
const parseModifiers = (value: any): string[] =>
|
||||||
t.isArrayExpression(value)
|
t.isArrayExpression(value)
|
||||||
? value.elements
|
? value.elements
|
||||||
.map((el) => (t.isStringLiteral(el) ? el.value : ''))
|
.map((el) => (t.isStringLiteral(el) ? el.value : ''))
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
: []);
|
: [];
|
||||||
|
|
||||||
const parseDirectives = (params: {
|
const parseDirectives = (params: {
|
||||||
name: string,
|
name: string;
|
||||||
path: NodePath<t.JSXAttribute>,
|
path: NodePath<t.JSXAttribute>;
|
||||||
value: t.Expression | null,
|
value: t.Expression | null;
|
||||||
state: State,
|
state: State;
|
||||||
tag: Tag,
|
tag: Tag;
|
||||||
isComponent: boolean
|
isComponent: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const { path, value, state, tag, isComponent } = params;
|
||||||
path, value, state, tag, isComponent,
|
|
||||||
} = params;
|
|
||||||
const args: Array<t.Expression | t.NullLiteral> = [];
|
const args: Array<t.Expression | t.NullLiteral> = [];
|
||||||
const vals: t.Expression[] = [];
|
const vals: t.Expression[] = [];
|
||||||
const modifiersSet: Set<string>[] = [];
|
const modifiersSet: Set<string>[] = [];
|
||||||
@ -70,7 +72,7 @@ const parseDirectives = (params: {
|
|||||||
|
|
||||||
const isVModels = directiveName === 'models';
|
const isVModels = directiveName === 'models';
|
||||||
const isVModel = directiveName === 'model';
|
const isVModel = directiveName === 'model';
|
||||||
if (isVModel && !t.isJSXExpressionContainer(path.get('value'))) {
|
if (isVModel && !path.get('value').isJSXExpressionContainer()) {
|
||||||
throw new Error('You have to use JSX Expression inside your v-model');
|
throw new Error('You have to use JSX Expression inside your v-model');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +80,9 @@ const parseDirectives = (params: {
|
|||||||
throw new Error('v-models can only use in custom components');
|
throw new Error('v-models can only use in custom components');
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldResolve = !['html', 'text', 'model', 'models'].includes(directiveName)
|
const shouldResolve =
|
||||||
|| (isVModel && !isComponent);
|
!['html', 'text', 'model', 'models'].includes(directiveName) ||
|
||||||
|
(isVModel && !isComponent);
|
||||||
|
|
||||||
let modifiers = directiveModifiers;
|
let modifiers = directiveModifiers;
|
||||||
|
|
||||||
@ -94,7 +97,11 @@ const parseDirectives = (params: {
|
|||||||
const { elements } = element as t.ArrayExpression;
|
const { elements } = element as t.ArrayExpression;
|
||||||
const [first, second, third] = elements;
|
const [first, second, third] = elements;
|
||||||
|
|
||||||
if (second && !t.isArrayExpression(second) && !t.isSpreadElement(second)) {
|
if (
|
||||||
|
second &&
|
||||||
|
!t.isArrayExpression(second) &&
|
||||||
|
!t.isSpreadElement(second)
|
||||||
|
) {
|
||||||
args.push(second);
|
args.push(second);
|
||||||
modifiers = parseModifiers(third as t.ArrayExpression);
|
modifiers = parseModifiers(third as t.ArrayExpression);
|
||||||
} else if (t.isArrayExpression(second)) {
|
} else if (t.isArrayExpression(second)) {
|
||||||
@ -122,21 +129,21 @@ const parseDirectives = (params: {
|
|||||||
modifiers: modifiersSet,
|
modifiers: modifiersSet,
|
||||||
values: vals.length ? vals : [value],
|
values: vals.length ? vals : [value],
|
||||||
args,
|
args,
|
||||||
directive: shouldResolve ? [
|
directive: shouldResolve
|
||||||
|
? ([
|
||||||
resolveDirective(path, state, tag, directiveName),
|
resolveDirective(path, state, tag, directiveName),
|
||||||
vals[0] || value,
|
vals[0] || value,
|
||||||
modifiersSet[0]?.size
|
modifiersSet[0]?.size
|
||||||
? args[0] || t.unaryExpression('void', t.numericLiteral(0), true)
|
? args[0] || t.unaryExpression('void', t.numericLiteral(0), true)
|
||||||
: args[0],
|
: args[0],
|
||||||
!!modifiersSet[0]?.size && t.objectExpression(
|
!!modifiersSet[0]?.size &&
|
||||||
[...modifiersSet[0]].map(
|
t.objectExpression(
|
||||||
(modifier) => t.objectProperty(
|
[...modifiersSet[0]].map((modifier) =>
|
||||||
t.identifier(modifier),
|
t.objectProperty(t.identifier(modifier), t.booleanLiteral(true))
|
||||||
t.booleanLiteral(true),
|
)
|
||||||
),
|
),
|
||||||
),
|
].filter(Boolean) as t.Expression[])
|
||||||
),
|
: undefined,
|
||||||
].filter(Boolean) as t.Expression[] : undefined,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -144,7 +151,7 @@ const resolveDirective = (
|
|||||||
path: NodePath<t.JSXAttribute>,
|
path: NodePath<t.JSXAttribute>,
|
||||||
state: State,
|
state: State,
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
directiveName: string,
|
directiveName: string
|
||||||
) => {
|
) => {
|
||||||
if (directiveName === 'show') {
|
if (directiveName === 'show') {
|
||||||
return createIdentifier(state, 'vShow');
|
return createIdentifier(state, 'vShow');
|
||||||
@ -177,11 +184,9 @@ const resolveDirective = (
|
|||||||
}
|
}
|
||||||
return modelToUse;
|
return modelToUse;
|
||||||
}
|
}
|
||||||
return t.callExpression(
|
return t.callExpression(createIdentifier(state, 'resolveDirective'), [
|
||||||
createIdentifier(state, 'resolveDirective'), [
|
|
||||||
t.stringLiteral(directiveName),
|
t.stringLiteral(directiveName),
|
||||||
],
|
]);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default parseDirectives;
|
export default parseDirectives;
|
||||||
|
@ -1,34 +1,36 @@
|
|||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import { NodePath } from '@babel/traverse';
|
import { type NodePath } from '@babel/traverse';
|
||||||
import type { State } from './interface';
|
import type { State } from './interface';
|
||||||
import { createIdentifier, FRAGMENT } from './utils';
|
import { FRAGMENT, createIdentifier } from './utils';
|
||||||
|
|
||||||
const transformFragment = (
|
const transformFragment = (
|
||||||
path: NodePath<t.JSXElement>,
|
path: NodePath<t.JSXElement>,
|
||||||
Fragment: t.JSXIdentifier | t.JSXMemberExpression,
|
Fragment: t.JSXIdentifier | t.JSXMemberExpression
|
||||||
) => {
|
) => {
|
||||||
const children = path.get('children') || [];
|
const children = path.get('children') || [];
|
||||||
return t.jsxElement(
|
return t.jsxElement(
|
||||||
t.jsxOpeningElement(Fragment, []),
|
t.jsxOpeningElement(Fragment, []),
|
||||||
t.jsxClosingElement(Fragment),
|
t.jsxClosingElement(Fragment),
|
||||||
children.map(({ node }) => node),
|
children.map(({ node }) => node),
|
||||||
false,
|
false
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({
|
export default {
|
||||||
JSXFragment: {
|
JSXFragment: {
|
||||||
enter(path: NodePath<t.JSXElement>, state: State) {
|
enter(path: NodePath<t.JSXElement>, state: State) {
|
||||||
const fragmentCallee = createIdentifier(state, FRAGMENT);
|
const fragmentCallee = createIdentifier(state, FRAGMENT);
|
||||||
path.replaceWith(transformFragment(
|
path.replaceWith(
|
||||||
|
transformFragment(
|
||||||
path,
|
path,
|
||||||
t.isIdentifier(fragmentCallee)
|
t.isIdentifier(fragmentCallee)
|
||||||
? t.jsxIdentifier(fragmentCallee.name)
|
? t.jsxIdentifier(fragmentCallee.name)
|
||||||
: t.jsxMemberExpression(
|
: t.jsxMemberExpression(
|
||||||
t.jsxIdentifier((fragmentCallee.object as t.Identifier).name),
|
t.jsxIdentifier((fragmentCallee.object as t.Identifier).name),
|
||||||
t.jsxIdentifier((fragmentCallee.property as t.Identifier).name),
|
t.jsxIdentifier((fragmentCallee.property as t.Identifier).name)
|
||||||
),
|
)
|
||||||
));
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import { NodePath } from '@babel/traverse';
|
import { type NodePath } from '@babel/traverse';
|
||||||
|
// @ts-expect-error
|
||||||
import { addDefault } from '@babel/helper-module-imports';
|
import { addDefault } from '@babel/helper-module-imports';
|
||||||
import {
|
import {
|
||||||
|
buildIIFE,
|
||||||
|
checkIsComponent,
|
||||||
createIdentifier,
|
createIdentifier,
|
||||||
|
dedupeProperties,
|
||||||
|
getJSXAttributeName,
|
||||||
|
getTag,
|
||||||
|
isConstant,
|
||||||
|
isDirective,
|
||||||
|
isOn,
|
||||||
|
transformJSXExpressionContainer,
|
||||||
|
transformJSXSpreadAttribute,
|
||||||
transformJSXSpreadChild,
|
transformJSXSpreadChild,
|
||||||
transformJSXText,
|
transformJSXText,
|
||||||
transformJSXExpressionContainer,
|
|
||||||
walksScope,
|
walksScope,
|
||||||
buildIIFE,
|
|
||||||
isDirective,
|
|
||||||
checkIsComponent,
|
|
||||||
getTag,
|
|
||||||
getJSXAttributeName,
|
|
||||||
isOn,
|
|
||||||
isConstant,
|
|
||||||
dedupeProperties,
|
|
||||||
transformJSXSpreadAttribute,
|
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import SlotFlags from './slotFlags';
|
import SlotFlags from './slotFlags';
|
||||||
import { PatchFlags } from './patchFlags';
|
import { PatchFlags } from './patchFlags';
|
||||||
import parseDirectives from './parseDirectives';
|
import parseDirectives from './parseDirectives';
|
||||||
import type { State, Slots } from './interface';
|
import type { Slots, State } from './interface';
|
||||||
|
|
||||||
const xlinkRE = /^xlink([A-Z])/;
|
const xlinkRE = /^xlink([A-Z])/;
|
||||||
|
|
||||||
@ -28,10 +29,8 @@ type ExcludesBoolean = <T>(x: T | false | true) => x is T;
|
|||||||
|
|
||||||
const getJSXAttributeValue = (
|
const getJSXAttributeValue = (
|
||||||
path: NodePath<t.JSXAttribute>,
|
path: NodePath<t.JSXAttribute>,
|
||||||
state: State,
|
state: State
|
||||||
): (
|
): t.StringLiteral | t.Expression | null => {
|
||||||
t.StringLiteral | t.Expression | null
|
|
||||||
) => {
|
|
||||||
const valuePath = path.get('value');
|
const valuePath = path.get('value');
|
||||||
if (valuePath.isJSXElement()) {
|
if (valuePath.isJSXElement()) {
|
||||||
return transformJSXElement(valuePath, state);
|
return transformJSXElement(valuePath, state);
|
||||||
@ -77,10 +76,10 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
let hasHydrationEventBinding = false;
|
let hasHydrationEventBinding = false;
|
||||||
let hasDynamicKeys = false;
|
let hasDynamicKeys = false;
|
||||||
|
|
||||||
const mergeArgs: (t.CallExpression | t.ObjectExpression | t.Identifier)[] = [];
|
const mergeArgs: (t.CallExpression | t.ObjectExpression | t.Identifier)[] =
|
||||||
|
[];
|
||||||
const { mergeProps = true } = state.opts;
|
const { mergeProps = true } = state.opts;
|
||||||
props
|
props.forEach((prop) => {
|
||||||
.forEach((prop) => {
|
|
||||||
if (prop.isJSXAttribute()) {
|
if (prop.isJSXAttribute()) {
|
||||||
let name = getJSXAttributeName(prop);
|
let name = getJSXAttributeName(prop);
|
||||||
|
|
||||||
@ -88,13 +87,13 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
|
|
||||||
if (!isConstant(attributeValue) || name === 'ref') {
|
if (!isConstant(attributeValue) || name === 'ref') {
|
||||||
if (
|
if (
|
||||||
!isComponent
|
!isComponent &&
|
||||||
&& isOn(name)
|
isOn(name) &&
|
||||||
// omit the flag for click handlers becaues hydration gives click
|
// omit the flag for click handlers becaues hydration gives click
|
||||||
// dedicated fast path.
|
// dedicated fast path.
|
||||||
&& name.toLowerCase() !== 'onclick'
|
name.toLowerCase() !== 'onclick' &&
|
||||||
// omit v-model handlers
|
// omit v-model handlers
|
||||||
&& name !== 'onUpdate:modelValue'
|
name !== 'onUpdate:modelValue'
|
||||||
) {
|
) {
|
||||||
hasHydrationEventBinding = true;
|
hasHydrationEventBinding = true;
|
||||||
}
|
}
|
||||||
@ -105,32 +104,29 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
hasClassBinding = true;
|
hasClassBinding = true;
|
||||||
} else if (name === 'style' && !isComponent) {
|
} else if (name === 'style' && !isComponent) {
|
||||||
hasStyleBinding = true;
|
hasStyleBinding = true;
|
||||||
} else if (
|
} else if (name !== 'key' && !isDirective(name) && name !== 'on') {
|
||||||
name !== 'key'
|
|
||||||
&& !isDirective(name)
|
|
||||||
&& name !== 'on'
|
|
||||||
) {
|
|
||||||
dynamicPropNames.add(name);
|
dynamicPropNames.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.opts.transformOn && (name === 'on' || name === 'nativeOn')) {
|
if (state.opts.transformOn && (name === 'on' || name === 'nativeOn')) {
|
||||||
if (!state.get('transformOn')) {
|
if (!state.get('transformOn')) {
|
||||||
state.set('transformOn', addDefault(
|
state.set(
|
||||||
path,
|
'transformOn',
|
||||||
'@vue/babel-helper-vue-transform-on',
|
addDefault(path, '@vue/babel-helper-vue-transform-on', {
|
||||||
{ nameHint: '_transformOn' },
|
nameHint: '_transformOn',
|
||||||
));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
mergeArgs.push(t.callExpression(
|
mergeArgs.push(
|
||||||
state.get('transformOn'),
|
t.callExpression(state.get('transformOn'), [
|
||||||
[attributeValue || t.booleanLiteral(true)],
|
attributeValue || t.booleanLiteral(true),
|
||||||
));
|
])
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDirective(name)) {
|
if (isDirective(name)) {
|
||||||
const {
|
const { directive, modifiers, values, args, directiveName } =
|
||||||
directive, modifiers, values, args, directiveName,
|
parseDirectives({
|
||||||
} = parseDirectives({
|
|
||||||
tag,
|
tag,
|
||||||
isComponent,
|
isComponent,
|
||||||
name,
|
name,
|
||||||
@ -146,16 +142,14 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
if (directive) {
|
if (directive) {
|
||||||
directives.push(t.arrayExpression(directive));
|
directives.push(t.arrayExpression(directive));
|
||||||
} else if (directiveName === 'html') {
|
} else if (directiveName === 'html') {
|
||||||
properties.push(t.objectProperty(
|
properties.push(
|
||||||
t.stringLiteral('innerHTML'),
|
t.objectProperty(t.stringLiteral('innerHTML'), values[0] as any)
|
||||||
values[0] as any,
|
);
|
||||||
));
|
|
||||||
dynamicPropNames.add('innerHTML');
|
dynamicPropNames.add('innerHTML');
|
||||||
} else if (directiveName === 'text') {
|
} else if (directiveName === 'text') {
|
||||||
properties.push(t.objectProperty(
|
properties.push(
|
||||||
t.stringLiteral('textContent'),
|
t.objectProperty(t.stringLiteral('textContent'), values[0] as any)
|
||||||
values[0] as any,
|
);
|
||||||
));
|
|
||||||
dynamicPropNames.add('textContent');
|
dynamicPropNames.add('textContent');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,49 +157,77 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
values.forEach((value, index) => {
|
values.forEach((value, index) => {
|
||||||
const propName = args[index];
|
const propName = args[index];
|
||||||
// v-model target with variable
|
// v-model target with variable
|
||||||
const isDynamic = propName && !t.isStringLiteral(propName) && !t.isNullLiteral(propName);
|
const isDynamic =
|
||||||
|
propName &&
|
||||||
|
!t.isStringLiteral(propName) &&
|
||||||
|
!t.isNullLiteral(propName);
|
||||||
|
|
||||||
// must be v-model or v-models and is a component
|
// must be v-model or v-models and is a component
|
||||||
if (!directive) {
|
if (!directive) {
|
||||||
properties.push(
|
properties.push(
|
||||||
t.objectProperty(t.isNullLiteral(propName)
|
t.objectProperty(
|
||||||
? t.stringLiteral('modelValue') : propName, value as any, isDynamic),
|
t.isNullLiteral(propName)
|
||||||
|
? t.stringLiteral('modelValue')
|
||||||
|
: propName,
|
||||||
|
value as any,
|
||||||
|
isDynamic
|
||||||
|
)
|
||||||
);
|
);
|
||||||
if (!isDynamic) {
|
if (!isDynamic) {
|
||||||
dynamicPropNames.add((propName as t.StringLiteral)?.value || 'modelValue');
|
dynamicPropNames.add(
|
||||||
|
(propName as t.StringLiteral)?.value || 'modelValue'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifiers[index]?.size) {
|
if (modifiers[index]?.size) {
|
||||||
properties.push(
|
properties.push(
|
||||||
t.objectProperty(
|
t.objectProperty(
|
||||||
isDynamic
|
isDynamic
|
||||||
? t.binaryExpression('+', propName, t.stringLiteral('Modifiers'))
|
? t.binaryExpression(
|
||||||
: t.stringLiteral(`${(propName as t.StringLiteral)?.value || 'model'}Modifiers`),
|
'+',
|
||||||
|
propName,
|
||||||
|
t.stringLiteral('Modifiers')
|
||||||
|
)
|
||||||
|
: t.stringLiteral(
|
||||||
|
`${
|
||||||
|
(propName as t.StringLiteral)?.value || 'model'
|
||||||
|
}Modifiers`
|
||||||
|
),
|
||||||
t.objectExpression(
|
t.objectExpression(
|
||||||
[...modifiers[index]].map((modifier) => t.objectProperty(
|
[...modifiers[index]].map((modifier) =>
|
||||||
|
t.objectProperty(
|
||||||
t.stringLiteral(modifier),
|
t.stringLiteral(modifier),
|
||||||
t.booleanLiteral(true),
|
t.booleanLiteral(true)
|
||||||
)),
|
)
|
||||||
),
|
)
|
||||||
isDynamic,
|
|
||||||
),
|
),
|
||||||
|
isDynamic
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateName = isDynamic
|
const updateName = isDynamic
|
||||||
? t.binaryExpression('+', t.stringLiteral('onUpdate'), propName)
|
? t.binaryExpression('+', t.stringLiteral('onUpdate'), propName)
|
||||||
: t.stringLiteral(`onUpdate:${(propName as t.StringLiteral)?.value || 'modelValue'}`);
|
: t.stringLiteral(
|
||||||
|
`onUpdate:${
|
||||||
|
(propName as t.StringLiteral)?.value || 'modelValue'
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
|
||||||
properties.push(
|
properties.push(
|
||||||
t.objectProperty(
|
t.objectProperty(
|
||||||
updateName,
|
updateName,
|
||||||
t.arrowFunctionExpression(
|
t.arrowFunctionExpression(
|
||||||
[t.identifier('$event')],
|
[t.identifier('$event')],
|
||||||
t.assignmentExpression('=', value as any, t.identifier('$event')),
|
t.assignmentExpression(
|
||||||
),
|
'=',
|
||||||
isDynamic,
|
value as any,
|
||||||
|
t.identifier('$event')
|
||||||
|
)
|
||||||
),
|
),
|
||||||
|
isDynamic
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isDynamic) {
|
if (!isDynamic) {
|
||||||
@ -217,16 +239,23 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (name.match(xlinkRE)) {
|
if (name.match(xlinkRE)) {
|
||||||
name = name.replace(xlinkRE, (_, firstCharacter) => `xlink:${firstCharacter.toLowerCase()}`);
|
name = name.replace(
|
||||||
|
xlinkRE,
|
||||||
|
(_, firstCharacter) => `xlink:${firstCharacter.toLowerCase()}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
properties.push(t.objectProperty(
|
properties.push(
|
||||||
|
t.objectProperty(
|
||||||
t.stringLiteral(name),
|
t.stringLiteral(name),
|
||||||
attributeValue || t.booleanLiteral(true),
|
attributeValue || t.booleanLiteral(true)
|
||||||
));
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (properties.length && mergeProps) {
|
if (properties.length && mergeProps) {
|
||||||
mergeArgs.push(t.objectExpression(dedupeProperties(properties, mergeProps)));
|
mergeArgs.push(
|
||||||
|
t.objectExpression(dedupeProperties(properties, mergeProps))
|
||||||
|
);
|
||||||
properties = [];
|
properties = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +265,7 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
path as NodePath,
|
path as NodePath,
|
||||||
prop as NodePath<t.JSXSpreadAttribute>,
|
prop as NodePath<t.JSXSpreadAttribute>,
|
||||||
mergeProps,
|
mergeProps,
|
||||||
mergeProps ? mergeArgs : properties,
|
mergeProps ? mergeArgs : properties
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -260,21 +289,24 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(patchFlag === 0 || patchFlag === PatchFlags.HYDRATE_EVENTS)
|
(patchFlag === 0 || patchFlag === PatchFlags.HYDRATE_EVENTS) &&
|
||||||
&& (hasRef || directives.length > 0)
|
(hasRef || directives.length > 0)
|
||||||
) {
|
) {
|
||||||
patchFlag |= PatchFlags.NEED_PATCH;
|
patchFlag |= PatchFlags.NEED_PATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
let propsExpression: t.Expression | t.ObjectProperty | t.Literal = t.nullLiteral();
|
let propsExpression: t.Expression | t.ObjectProperty | t.Literal =
|
||||||
|
t.nullLiteral();
|
||||||
if (mergeArgs.length) {
|
if (mergeArgs.length) {
|
||||||
if (properties.length) {
|
if (properties.length) {
|
||||||
mergeArgs.push(t.objectExpression(dedupeProperties(properties, mergeProps)));
|
mergeArgs.push(
|
||||||
|
t.objectExpression(dedupeProperties(properties, mergeProps))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (mergeArgs.length > 1) {
|
if (mergeArgs.length > 1) {
|
||||||
propsExpression = t.callExpression(
|
propsExpression = t.callExpression(
|
||||||
createIdentifier(state, 'mergeProps'),
|
createIdentifier(state, 'mergeProps'),
|
||||||
mergeArgs,
|
mergeArgs
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// single no need for a mergeProps call
|
// single no need for a mergeProps call
|
||||||
@ -285,7 +317,9 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
if (properties.length === 1 && t.isSpreadElement(properties[0])) {
|
if (properties.length === 1 && t.isSpreadElement(properties[0])) {
|
||||||
propsExpression = (properties[0] as unknown as t.SpreadElement).argument;
|
propsExpression = (properties[0] as unknown as t.SpreadElement).argument;
|
||||||
} else {
|
} else {
|
||||||
propsExpression = t.objectExpression(dedupeProperties(properties, mergeProps));
|
propsExpression = t.objectExpression(
|
||||||
|
dedupeProperties(properties, mergeProps)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,19 +341,22 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
|
|||||||
*/
|
*/
|
||||||
const getChildren = (
|
const getChildren = (
|
||||||
paths: NodePath<
|
paths: NodePath<
|
||||||
t.JSXText
|
| t.JSXText
|
||||||
| t.JSXExpressionContainer
|
| t.JSXExpressionContainer
|
||||||
| t.JSXSpreadChild
|
| t.JSXSpreadChild
|
||||||
| t.JSXElement
|
| t.JSXElement
|
||||||
| t.JSXFragment
|
| t.JSXFragment
|
||||||
>[],
|
>[],
|
||||||
state: State,
|
state: State
|
||||||
): t.Expression[] => paths
|
): t.Expression[] =>
|
||||||
|
paths
|
||||||
.map((path) => {
|
.map((path) => {
|
||||||
if (path.isJSXText()) {
|
if (path.isJSXText()) {
|
||||||
const transformedText = transformJSXText(path);
|
const transformedText = transformJSXText(path);
|
||||||
if (transformedText) {
|
if (transformedText) {
|
||||||
return t.callExpression(createIdentifier(state, 'createTextVNode'), [transformedText]);
|
return t.callExpression(createIdentifier(state, 'createTextVNode'), [
|
||||||
|
transformedText,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
return transformedText;
|
return transformedText;
|
||||||
}
|
}
|
||||||
@ -336,8 +373,8 @@ const getChildren = (
|
|||||||
|
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
if (t.isJSXSpreadChild(path)) {
|
if (path.isJSXSpreadChild()) {
|
||||||
return transformJSXSpreadChild(path as NodePath<t.JSXSpreadChild>);
|
return transformJSXSpreadChild(path);
|
||||||
}
|
}
|
||||||
if (path.isCallExpression()) {
|
if (path.isCallExpression()) {
|
||||||
return (path as NodePath<t.CallExpression>).node;
|
return (path as NodePath<t.CallExpression>).node;
|
||||||
@ -346,15 +383,14 @@ const getChildren = (
|
|||||||
return transformJSXElement(path, state);
|
return transformJSXElement(path, state);
|
||||||
}
|
}
|
||||||
throw new Error(`getChildren: ${path.type} is not supported`);
|
throw new Error(`getChildren: ${path.type} is not supported`);
|
||||||
}).filter(((value: any) => (
|
})
|
||||||
value !== undefined
|
.filter(
|
||||||
&& value !== null
|
((value: any) => value != null && !t.isJSXEmptyExpression(value)) as any
|
||||||
&& !t.isJSXEmptyExpression(value)
|
);
|
||||||
)) as any);
|
|
||||||
|
|
||||||
const transformJSXElement = (
|
const transformJSXElement = (
|
||||||
path: NodePath<t.JSXElement>,
|
path: NodePath<t.JSXElement>,
|
||||||
state: State,
|
state: State
|
||||||
): t.CallExpression => {
|
): t.CallExpression => {
|
||||||
const children = getChildren(path.get('children'), state);
|
const children = getChildren(path.get('children'), state);
|
||||||
const {
|
const {
|
||||||
@ -380,21 +416,25 @@ const transformJSXElement = (
|
|||||||
*/
|
*/
|
||||||
VNodeChild = isComponent
|
VNodeChild = isComponent
|
||||||
? children.length
|
? children.length
|
||||||
? t.objectExpression([
|
? t.objectExpression(
|
||||||
!!children.length && t.objectProperty(
|
[
|
||||||
|
!!children.length &&
|
||||||
|
t.objectProperty(
|
||||||
t.identifier('default'),
|
t.identifier('default'),
|
||||||
t.arrowFunctionExpression([], t.arrayExpression(buildIIFE(path, children))),
|
t.arrowFunctionExpression(
|
||||||
|
[],
|
||||||
|
t.arrayExpression(buildIIFE(path, children))
|
||||||
|
)
|
||||||
),
|
),
|
||||||
...(slots ? (
|
...(slots
|
||||||
t.isObjectExpression(slots)
|
? t.isObjectExpression(slots)
|
||||||
? (slots! as t.ObjectExpression).properties
|
? (slots! as t.ObjectExpression).properties
|
||||||
: [t.spreadElement(slots!)]
|
: [t.spreadElement(slots!)]
|
||||||
) : []),
|
: []),
|
||||||
optimize && t.objectProperty(
|
optimize &&
|
||||||
t.identifier('_'),
|
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
|
||||||
t.numericLiteral(slotFlag),
|
].filter(Boolean as any)
|
||||||
),
|
)
|
||||||
].filter(Boolean as any))
|
|
||||||
: slots
|
: slots
|
||||||
: t.arrayExpression(children);
|
: t.arrayExpression(children);
|
||||||
} else if (children.length === 1) {
|
} else if (children.length === 1) {
|
||||||
@ -403,25 +443,35 @@ const transformJSXElement = (
|
|||||||
*/
|
*/
|
||||||
const { enableObjectSlots = true } = state.opts;
|
const { enableObjectSlots = true } = state.opts;
|
||||||
const child = children[0];
|
const child = children[0];
|
||||||
const objectExpression = t.objectExpression([
|
const objectExpression = t.objectExpression(
|
||||||
|
[
|
||||||
t.objectProperty(
|
t.objectProperty(
|
||||||
t.identifier('default'),
|
t.identifier('default'),
|
||||||
t.arrowFunctionExpression([], t.arrayExpression(buildIIFE(path, [child]))),
|
t.arrowFunctionExpression(
|
||||||
|
[],
|
||||||
|
t.arrayExpression(buildIIFE(path, [child]))
|
||||||
|
)
|
||||||
),
|
),
|
||||||
optimize && t.objectProperty(
|
optimize &&
|
||||||
|
(t.objectProperty(
|
||||||
t.identifier('_'),
|
t.identifier('_'),
|
||||||
t.numericLiteral(slotFlag),
|
t.numericLiteral(slotFlag)
|
||||||
) as any,
|
) as any),
|
||||||
].filter(Boolean));
|
].filter(Boolean)
|
||||||
|
);
|
||||||
if (t.isIdentifier(child) && isComponent) {
|
if (t.isIdentifier(child) && isComponent) {
|
||||||
VNodeChild = enableObjectSlots ? t.conditionalExpression(
|
VNodeChild = enableObjectSlots
|
||||||
t.callExpression(state.get('@vue/babel-plugin-jsx/runtimeIsSlot')(), [child]),
|
? t.conditionalExpression(
|
||||||
|
t.callExpression(
|
||||||
|
state.get('@vue/babel-plugin-jsx/runtimeIsSlot')(),
|
||||||
|
[child]
|
||||||
|
),
|
||||||
child,
|
child,
|
||||||
objectExpression,
|
objectExpression
|
||||||
) : objectExpression;
|
)
|
||||||
} else if (
|
: objectExpression;
|
||||||
t.isCallExpression(child) && child.loc && isComponent
|
} else if (t.isCallExpression(child) && child.loc && isComponent) {
|
||||||
) { // the element was generated and doesn't have location information
|
// the element was generated and doesn't have location information
|
||||||
if (enableObjectSlots) {
|
if (enableObjectSlots) {
|
||||||
const { scope } = path;
|
const { scope } = path;
|
||||||
const slotId = scope.generateUidIdentifier('slot');
|
const slotId = scope.generateUidIdentifier('slot');
|
||||||
@ -431,63 +481,72 @@ const transformJSXElement = (
|
|||||||
kind: 'let',
|
kind: 'let',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const alternate = t.objectExpression([
|
const alternate = t.objectExpression(
|
||||||
|
[
|
||||||
t.objectProperty(
|
t.objectProperty(
|
||||||
t.identifier('default'),
|
t.identifier('default'),
|
||||||
t.arrowFunctionExpression([], t.arrayExpression(buildIIFE(path, [slotId]))),
|
t.arrowFunctionExpression(
|
||||||
), optimize && t.objectProperty(
|
[],
|
||||||
|
t.arrayExpression(buildIIFE(path, [slotId]))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
optimize &&
|
||||||
|
(t.objectProperty(
|
||||||
t.identifier('_'),
|
t.identifier('_'),
|
||||||
t.numericLiteral(slotFlag),
|
t.numericLiteral(slotFlag)
|
||||||
) as any,
|
) as any),
|
||||||
].filter(Boolean));
|
].filter(Boolean)
|
||||||
|
);
|
||||||
const assignment = t.assignmentExpression('=', slotId, child);
|
const assignment = t.assignmentExpression('=', slotId, child);
|
||||||
const condition = t.callExpression(
|
const condition = t.callExpression(
|
||||||
state.get('@vue/babel-plugin-jsx/runtimeIsSlot')(),
|
state.get('@vue/babel-plugin-jsx/runtimeIsSlot')(),
|
||||||
[assignment],
|
[assignment]
|
||||||
);
|
|
||||||
VNodeChild = t.conditionalExpression(
|
|
||||||
condition,
|
|
||||||
slotId,
|
|
||||||
alternate,
|
|
||||||
);
|
);
|
||||||
|
VNodeChild = t.conditionalExpression(condition, slotId, alternate);
|
||||||
} else {
|
} else {
|
||||||
VNodeChild = objectExpression;
|
VNodeChild = objectExpression;
|
||||||
}
|
}
|
||||||
} else if (t.isFunctionExpression(child) || t.isArrowFunctionExpression(child)) {
|
} else if (
|
||||||
|
t.isFunctionExpression(child) ||
|
||||||
|
t.isArrowFunctionExpression(child)
|
||||||
|
) {
|
||||||
VNodeChild = t.objectExpression([
|
VNodeChild = t.objectExpression([
|
||||||
t.objectProperty(
|
t.objectProperty(t.identifier('default'), child),
|
||||||
t.identifier('default'),
|
|
||||||
child,
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
} else if (t.isObjectExpression(child)) {
|
} else if (t.isObjectExpression(child)) {
|
||||||
VNodeChild = t.objectExpression([
|
VNodeChild = t.objectExpression(
|
||||||
|
[
|
||||||
...child.properties,
|
...child.properties,
|
||||||
optimize && t.objectProperty(
|
optimize &&
|
||||||
t.identifier('_'),
|
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
|
||||||
t.numericLiteral(slotFlag),
|
].filter(Boolean as any)
|
||||||
),
|
);
|
||||||
].filter(Boolean as any));
|
|
||||||
} else {
|
} else {
|
||||||
VNodeChild = isComponent ? t.objectExpression([
|
VNodeChild = isComponent
|
||||||
|
? t.objectExpression([
|
||||||
t.objectProperty(
|
t.objectProperty(
|
||||||
t.identifier('default'),
|
t.identifier('default'),
|
||||||
t.arrowFunctionExpression([], t.arrayExpression([child])),
|
t.arrowFunctionExpression([], t.arrayExpression([child]))
|
||||||
),
|
),
|
||||||
]) : t.arrayExpression([child]);
|
])
|
||||||
|
: t.arrayExpression([child]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const createVNode = t.callExpression(createIdentifier(state, 'createVNode'), [
|
const createVNode = t.callExpression(
|
||||||
|
createIdentifier(state, 'createVNode'),
|
||||||
|
[
|
||||||
tag,
|
tag,
|
||||||
props,
|
props,
|
||||||
VNodeChild || t.nullLiteral(),
|
VNodeChild || t.nullLiteral(),
|
||||||
!!patchFlag && optimize && t.numericLiteral(patchFlag),
|
!!patchFlag && optimize && t.numericLiteral(patchFlag),
|
||||||
!!dynamicPropNames.size && optimize
|
!!dynamicPropNames.size &&
|
||||||
&& t.arrayExpression(
|
optimize &&
|
||||||
[...dynamicPropNames.keys()].map((name) => t.stringLiteral(name)),
|
t.arrayExpression(
|
||||||
|
[...dynamicPropNames.keys()].map((name) => t.stringLiteral(name))
|
||||||
),
|
),
|
||||||
].filter(Boolean as unknown as ExcludesBoolean));
|
].filter(Boolean as unknown as ExcludesBoolean)
|
||||||
|
);
|
||||||
|
|
||||||
if (!directives.length) {
|
if (!directives.length) {
|
||||||
return createVNode;
|
return createVNode;
|
||||||
@ -499,10 +558,10 @@ const transformJSXElement = (
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({
|
export default {
|
||||||
JSXElement: {
|
JSXElement: {
|
||||||
exit(path: NodePath<t.JSXElement>, state: State) {
|
exit(path: NodePath<t.JSXElement>, state: State) {
|
||||||
path.replaceWith(transformJSXElement(path, state));
|
path.replaceWith(transformJSXElement(path, state));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import htmlTags from 'html-tags';
|
import htmlTags from 'html-tags';
|
||||||
import svgTags from 'svg-tags';
|
import svgTags from 'svg-tags';
|
||||||
import { NodePath } from '@babel/traverse';
|
import { type NodePath } from '@babel/traverse';
|
||||||
import type { State } from './interface';
|
import type { State } from './interface';
|
||||||
import SlotFlags from './slotFlags';
|
import SlotFlags from './slotFlags';
|
||||||
|
|
||||||
@ -17,15 +17,17 @@ export const KEEP_ALIVE = 'KeepAlive';
|
|||||||
* @returns MemberExpression
|
* @returns MemberExpression
|
||||||
*/
|
*/
|
||||||
export const createIdentifier = (
|
export const createIdentifier = (
|
||||||
state: State, name: string,
|
state: State,
|
||||||
|
name: string
|
||||||
): t.Identifier | t.MemberExpression => state.get(name)();
|
): t.Identifier | t.MemberExpression => state.get(name)();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if string is describing a directive
|
* Checks if string is describing a directive
|
||||||
* @param src string
|
* @param src string
|
||||||
*/
|
*/
|
||||||
export const isDirective = (src: string): boolean => src.startsWith('v-')
|
export const isDirective = (src: string): boolean =>
|
||||||
|| (src.startsWith('v') && src.length >= 2 && src[1] >= 'A' && src[1] <= 'Z');
|
src.startsWith('v-') ||
|
||||||
|
(src.startsWith('v') && src.length >= 2 && src[1] >= 'A' && src[1] <= 'Z');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should transformed to slots
|
* Should transformed to slots
|
||||||
@ -33,7 +35,8 @@ export const isDirective = (src: string): boolean => src.startsWith('v-')
|
|||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
// if _Fragment is already imported, it will end with number
|
// if _Fragment is already imported, it will end with number
|
||||||
export const shouldTransformedToSlots = (tag: string) => !(tag.match(RegExp(`^_?${FRAGMENT}\\d*$`)) || tag === KEEP_ALIVE);
|
export const shouldTransformedToSlots = (tag: string) =>
|
||||||
|
!(tag.match(RegExp(`^_?${FRAGMENT}\\d*$`)) || tag === KEEP_ALIVE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a Node is a component
|
* Check if a Node is a component
|
||||||
@ -42,7 +45,10 @@ export const shouldTransformedToSlots = (tag: string) => !(tag.match(RegExp(`^_?
|
|||||||
* @param path JSXOpeningElement
|
* @param path JSXOpeningElement
|
||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
export const checkIsComponent = (path: NodePath<t.JSXOpeningElement>, state: State): boolean => {
|
export const checkIsComponent = (
|
||||||
|
path: NodePath<t.JSXOpeningElement>,
|
||||||
|
state: State
|
||||||
|
): boolean => {
|
||||||
const namePath = path.get('name');
|
const namePath = path.get('name');
|
||||||
|
|
||||||
if (namePath.isJSXMemberExpression()) {
|
if (namePath.isJSXMemberExpression()) {
|
||||||
@ -51,7 +57,12 @@ export const checkIsComponent = (path: NodePath<t.JSXOpeningElement>, state: Sta
|
|||||||
|
|
||||||
const tag = (namePath as NodePath<t.JSXIdentifier>).node.name;
|
const tag = (namePath as NodePath<t.JSXIdentifier>).node.name;
|
||||||
|
|
||||||
return !state.opts.isCustomElement?.(tag) && shouldTransformedToSlots(tag) && !htmlTags.includes(tag as htmlTags.htmlTags) && !svgTags.includes(tag);
|
return (
|
||||||
|
!state.opts.isCustomElement?.(tag) &&
|
||||||
|
shouldTransformedToSlots(tag) &&
|
||||||
|
!htmlTags.includes(tag as htmlTags.htmlTags) &&
|
||||||
|
!svgTags.includes(tag)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,12 +71,14 @@ export const checkIsComponent = (path: NodePath<t.JSXOpeningElement>, state: Sta
|
|||||||
* @returns MemberExpression
|
* @returns MemberExpression
|
||||||
*/
|
*/
|
||||||
export const transformJSXMemberExpression = (
|
export const transformJSXMemberExpression = (
|
||||||
path: NodePath<t.JSXMemberExpression>,
|
path: NodePath<t.JSXMemberExpression>
|
||||||
): t.MemberExpression => {
|
): t.MemberExpression => {
|
||||||
const objectPath = path.node.object;
|
const objectPath = path.node.object;
|
||||||
const propertyPath = path.node.property;
|
const propertyPath = path.node.property;
|
||||||
const transformedObject = t.isJSXMemberExpression(objectPath)
|
const transformedObject = t.isJSXMemberExpression(objectPath)
|
||||||
? transformJSXMemberExpression(path.get('object') as NodePath<t.JSXMemberExpression>)
|
? transformJSXMemberExpression(
|
||||||
|
path.get('object') as NodePath<t.JSXMemberExpression>
|
||||||
|
)
|
||||||
: t.isJSXIdentifier(objectPath)
|
: t.isJSXIdentifier(objectPath)
|
||||||
? t.identifier(objectPath.name)
|
? t.identifier(objectPath.name)
|
||||||
: t.nullLiteral();
|
: t.nullLiteral();
|
||||||
@ -81,19 +94,24 @@ export const transformJSXMemberExpression = (
|
|||||||
*/
|
*/
|
||||||
export const getTag = (
|
export const getTag = (
|
||||||
path: NodePath<t.JSXElement>,
|
path: NodePath<t.JSXElement>,
|
||||||
state: State,
|
state: State
|
||||||
): t.Identifier | t.CallExpression | t.StringLiteral | t.MemberExpression => {
|
): t.Identifier | t.CallExpression | t.StringLiteral | t.MemberExpression => {
|
||||||
const namePath = path.get('openingElement').get('name');
|
const namePath = path.get('openingElement').get('name');
|
||||||
if (namePath.isJSXIdentifier()) {
|
if (namePath.isJSXIdentifier()) {
|
||||||
const { name } = namePath.node;
|
const { name } = namePath.node;
|
||||||
if (!htmlTags.includes(name as htmlTags.htmlTags) && !svgTags.includes(name)) {
|
if (
|
||||||
return (name === FRAGMENT
|
!htmlTags.includes(name as htmlTags.htmlTags) &&
|
||||||
|
!svgTags.includes(name)
|
||||||
|
) {
|
||||||
|
return name === FRAGMENT
|
||||||
? createIdentifier(state, FRAGMENT)
|
? createIdentifier(state, FRAGMENT)
|
||||||
: path.scope.hasBinding(name)
|
: path.scope.hasBinding(name)
|
||||||
? t.identifier(name)
|
? t.identifier(name)
|
||||||
: state.opts.isCustomElement?.(name)
|
: state.opts.isCustomElement?.(name)
|
||||||
? t.stringLiteral(name)
|
? t.stringLiteral(name)
|
||||||
: t.callExpression(createIdentifier(state, 'resolveComponent'), [t.stringLiteral(name)]));
|
: t.callExpression(createIdentifier(state, 'resolveComponent'), [
|
||||||
|
t.stringLiteral(name),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.stringLiteral(name);
|
return t.stringLiteral(name);
|
||||||
@ -119,7 +137,9 @@ export const getJSXAttributeName = (path: NodePath<t.JSXAttribute>): string => {
|
|||||||
* @param path JSXText
|
* @param path JSXText
|
||||||
* @returns StringLiteral | null
|
* @returns StringLiteral | null
|
||||||
*/
|
*/
|
||||||
export const transformJSXText = (path: NodePath<t.JSXText>): t.StringLiteral | null => {
|
export const transformJSXText = (
|
||||||
|
path: NodePath<t.JSXText>
|
||||||
|
): t.StringLiteral | null => {
|
||||||
const { node } = path;
|
const { node } = path;
|
||||||
const lines = node.value.split(/\r\n|\n|\r/);
|
const lines = node.value.split(/\r\n|\n|\r/);
|
||||||
|
|
||||||
@ -171,10 +191,8 @@ export const transformJSXText = (path: NodePath<t.JSXText>): t.StringLiteral | n
|
|||||||
* @returns Expression
|
* @returns Expression
|
||||||
*/
|
*/
|
||||||
export const transformJSXExpressionContainer = (
|
export const transformJSXExpressionContainer = (
|
||||||
path: NodePath<t.JSXExpressionContainer>,
|
path: NodePath<t.JSXExpressionContainer>
|
||||||
): (
|
): t.Expression => path.get('expression').node as t.Expression;
|
||||||
t.Expression
|
|
||||||
) => path.get('expression').node as t.Expression;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform JSXSpreadChild
|
* Transform JSXSpreadChild
|
||||||
@ -182,10 +200,14 @@ export const transformJSXExpressionContainer = (
|
|||||||
* @returns SpreadElement
|
* @returns SpreadElement
|
||||||
*/
|
*/
|
||||||
export const transformJSXSpreadChild = (
|
export const transformJSXSpreadChild = (
|
||||||
path: NodePath<t.JSXSpreadChild>,
|
path: NodePath<t.JSXSpreadChild>
|
||||||
): t.SpreadElement => t.spreadElement(path.get('expression').node);
|
): t.SpreadElement => t.spreadElement(path.get('expression').node);
|
||||||
|
|
||||||
export const walksScope = (path: NodePath, name: string, slotFlag: SlotFlags): void => {
|
export const walksScope = (
|
||||||
|
path: NodePath,
|
||||||
|
name: string,
|
||||||
|
slotFlag: SlotFlags
|
||||||
|
): void => {
|
||||||
if (path.scope.hasBinding(name) && path.parentPath) {
|
if (path.scope.hasBinding(name) && path.parentPath) {
|
||||||
if (t.isJSXElement(path.parentPath.node)) {
|
if (t.isJSXElement(path.parentPath.node)) {
|
||||||
path.parentPath.setData('slotFlag', slotFlag);
|
path.parentPath.setData('slotFlag', slotFlag);
|
||||||
@ -194,9 +216,12 @@ export const walksScope = (path: NodePath, name: string, slotFlag: SlotFlags): v
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildIIFE = (path: NodePath<t.JSXElement>, children: t.Expression[]) => {
|
export const buildIIFE = (
|
||||||
|
path: NodePath<t.JSXElement>,
|
||||||
|
children: t.Expression[]
|
||||||
|
) => {
|
||||||
const { parentPath } = path;
|
const { parentPath } = path;
|
||||||
if (t.isAssignmentExpression(parentPath)) {
|
if (parentPath.isAssignmentExpression()) {
|
||||||
const { left } = parentPath.node as t.AssignmentExpression;
|
const { left } = parentPath.node as t.AssignmentExpression;
|
||||||
if (t.isIdentifier(left)) {
|
if (t.isIdentifier(left)) {
|
||||||
return children.map((child) => {
|
return children.map((child) => {
|
||||||
@ -207,11 +232,15 @@ export const buildIIFE = (path: NodePath<t.JSXElement>, children: t.Expression[]
|
|||||||
t.variableDeclarator(
|
t.variableDeclarator(
|
||||||
insertName,
|
insertName,
|
||||||
t.callExpression(
|
t.callExpression(
|
||||||
t.functionExpression(null, [], t.blockStatement([t.returnStatement(child)])),
|
t.functionExpression(
|
||||||
|
null,
|
||||||
[],
|
[],
|
||||||
|
t.blockStatement([t.returnStatement(child)])
|
||||||
),
|
),
|
||||||
|
[]
|
||||||
|
)
|
||||||
),
|
),
|
||||||
]),
|
])
|
||||||
);
|
);
|
||||||
return insertName;
|
return insertName;
|
||||||
}
|
}
|
||||||
@ -226,7 +255,10 @@ const onRE = /^on[^a-z]/;
|
|||||||
|
|
||||||
export const isOn = (key: string) => onRE.test(key);
|
export const isOn = (key: string) => onRE.test(key);
|
||||||
|
|
||||||
const mergeAsArray = (existing: t.ObjectProperty, incoming: t.ObjectProperty) => {
|
const mergeAsArray = (
|
||||||
|
existing: t.ObjectProperty,
|
||||||
|
incoming: t.ObjectProperty
|
||||||
|
) => {
|
||||||
if (t.isArrayExpression(existing.value)) {
|
if (t.isArrayExpression(existing.value)) {
|
||||||
existing.value.elements.push(incoming.value as t.Expression);
|
existing.value.elements.push(incoming.value as t.Expression);
|
||||||
} else {
|
} else {
|
||||||
@ -237,7 +269,10 @@ const mergeAsArray = (existing: t.ObjectProperty, incoming: t.ObjectProperty) =>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dedupeProperties = (properties: t.ObjectProperty[] = [], mergeProps?: boolean) => {
|
export const dedupeProperties = (
|
||||||
|
properties: t.ObjectProperty[] = [],
|
||||||
|
mergeProps?: boolean
|
||||||
|
) => {
|
||||||
if (!mergeProps) {
|
if (!mergeProps) {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
@ -270,7 +305,7 @@ export const dedupeProperties = (properties: t.ObjectProperty[] = [], mergeProps
|
|||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
export const isConstant = (
|
export const isConstant = (
|
||||||
node: t.Expression | t.Identifier | t.Literal | t.SpreadElement | null,
|
node: t.Expression | t.Identifier | t.Literal | t.SpreadElement | null
|
||||||
): boolean => {
|
): boolean => {
|
||||||
if (t.isIdentifier(node)) {
|
if (t.isIdentifier(node)) {
|
||||||
return node.name === 'undefined';
|
return node.name === 'undefined';
|
||||||
@ -280,7 +315,9 @@ export const isConstant = (
|
|||||||
return elements.every((element) => element && isConstant(element));
|
return elements.every((element) => element && isConstant(element));
|
||||||
}
|
}
|
||||||
if (t.isObjectExpression(node)) {
|
if (t.isObjectExpression(node)) {
|
||||||
return node.properties.every((property) => isConstant((property as any).value));
|
return node.properties.every((property) =>
|
||||||
|
isConstant((property as any).value)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (t.isLiteral(node)) {
|
if (t.isLiteral(node)) {
|
||||||
return true;
|
return true;
|
||||||
@ -292,13 +329,21 @@ export const transformJSXSpreadAttribute = (
|
|||||||
nodePath: NodePath,
|
nodePath: NodePath,
|
||||||
path: NodePath<t.JSXSpreadAttribute>,
|
path: NodePath<t.JSXSpreadAttribute>,
|
||||||
mergeProps: boolean,
|
mergeProps: boolean,
|
||||||
args: (t.ObjectProperty | t.Expression | t.SpreadElement)[],
|
args: (t.ObjectProperty | t.Expression | t.SpreadElement)[]
|
||||||
) => {
|
) => {
|
||||||
const argument = path.get('argument') as NodePath<t.ObjectExpression | t.Identifier>;
|
const argument = path.get('argument') as NodePath<
|
||||||
const properties = t.isObjectExpression(argument.node) ? argument.node.properties : undefined;
|
t.ObjectExpression | t.Identifier
|
||||||
|
>;
|
||||||
|
const properties = t.isObjectExpression(argument.node)
|
||||||
|
? argument.node.properties
|
||||||
|
: undefined;
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
if (argument.isIdentifier()) {
|
if (argument.isIdentifier()) {
|
||||||
walksScope(nodePath, (argument.node as t.Identifier).name, SlotFlags.DYNAMIC);
|
walksScope(
|
||||||
|
nodePath,
|
||||||
|
(argument.node as t.Identifier).name,
|
||||||
|
SlotFlags.DYNAMIC
|
||||||
|
);
|
||||||
}
|
}
|
||||||
args.push(mergeProps ? argument.node : t.spreadElement(argument.node));
|
args.push(mergeProps ? argument.node : t.spreadElement(argument.node));
|
||||||
} else if (mergeProps) {
|
} else if (mergeProps) {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`_Fragment already imported: _Fragment already imported 1`] = `
|
exports[`_Fragment already imported > _Fragment already imported 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode, Fragment as _Fragment2 } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode, Fragment as _Fragment2 } from \\"vue\\";
|
||||||
import { Fragment as _Fragment } from 'vue';
|
import { Fragment as _Fragment } from 'vue';
|
||||||
const Root1 = () => _createVNode(_Fragment2, null, [_createTextVNode(\\"root1\\")]);
|
const Root1 = () => _createVNode(_Fragment2, null, [_createTextVNode(\\"root1\\")]);
|
||||||
const Root2 = () => _createVNode(_Fragment, null, [_createTextVNode(\\"root2\\")]);"
|
const Root2 = () => _createVNode(_Fragment, null, [_createTextVNode(\\"root2\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`MereProps Order: MereProps Order 1`] = `
|
exports[`MereProps Order > MereProps Order 1`] = `
|
||||||
"import { createVNode as _createVNode, mergeProps as _mergeProps, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, mergeProps as _mergeProps, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
_createVNode(\\"button\\", _mergeProps({
|
_createVNode(\\"button\\", _mergeProps({
|
||||||
\\"loading\\": true
|
\\"loading\\": true
|
||||||
@ -16,7 +16,7 @@ _createVNode(\\"button\\", _mergeProps({
|
|||||||
}), [_createTextVNode(\\"btn\\")], 16, [\\"loading\\"]);"
|
}), [_createTextVNode(\\"btn\\")], 16, [\\"loading\\"]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Merge class/ style attributes into array: Merge class/ style attributes into array 1`] = `
|
exports[`Merge class/ style attributes into array > Merge class/ style attributes into array 1`] = `
|
||||||
"import { createVNode as _createVNode } from \\"vue\\";
|
"import { createVNode as _createVNode } from \\"vue\\";
|
||||||
_createVNode(\\"div\\", {
|
_createVNode(\\"div\\", {
|
||||||
\\"class\\": [\\"a\\", b],
|
\\"class\\": [\\"a\\", b],
|
||||||
@ -24,22 +24,22 @@ _createVNode(\\"div\\", {
|
|||||||
}, null, 6);"
|
}, null, 6);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Without JSX should work: Without JSX should work 1`] = `
|
exports[`Without JSX should work > Without JSX should work 1`] = `
|
||||||
"import { createVNode } from 'vue';
|
"import { createVNode } from 'vue';
|
||||||
createVNode('div', null, ['Without JSX should work']);"
|
createVNode('div', null, ['Without JSX should work']);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Without props: Without props 1`] = `
|
exports[`Without props > Without props 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
_createVNode(\\"a\\", null, [_createTextVNode(\\"a\\")]);"
|
_createVNode(\\"a\\", null, [_createTextVNode(\\"a\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`custom directive: custom directive 1`] = `
|
exports[`custom directive > custom directive 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"cus\\"), x]]);"
|
_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"cus\\"), x]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`custom directive: custom directive 2`] = `
|
exports[`custom directive > custom directive 2`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent, Fragment as _Fragment } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent, Fragment as _Fragment } from \\"vue\\";
|
||||||
_createVNode(_Fragment, null, [_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, 'y']]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, 'y', {
|
_createVNode(_Fragment, null, [_withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x]]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, 'y']]), _withDirectives(_createVNode(_resolveComponent(\\"A\\"), null, null, 512), [[_resolveDirective(\\"xxx\\"), x, 'y', {
|
||||||
a: true,
|
a: true,
|
||||||
@ -56,7 +56,7 @@ _createVNode(_Fragment, null, [_withDirectives(_createVNode(_resolveComponent(\\
|
|||||||
}]])]);"
|
}]])]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`disable object slot syntax with defaultSlot: defaultSlot 1`] = `
|
exports[`disable object slot syntax with defaultSlot > defaultSlot 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"Badge\\"), null, {
|
_createVNode(_resolveComponent(\\"Badge\\"), null, {
|
||||||
default: () => [slots.default()],
|
default: () => [slots.default()],
|
||||||
@ -64,7 +64,7 @@ _createVNode(_resolveComponent(\\"Badge\\"), null, {
|
|||||||
});"
|
});"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`dynamic type in input: dynamic type in input 1`] = `
|
exports[`dynamic type in input > dynamic type in input 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelDynamic as _vModelDynamic } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelDynamic as _vModelDynamic } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"input\\", {
|
_withDirectives(_createVNode(\\"input\\", {
|
||||||
\\"type\\": type,
|
\\"type\\": type,
|
||||||
@ -72,7 +72,7 @@ _withDirectives(_createVNode(\\"input\\", {
|
|||||||
}, null, 8, [\\"type\\", \\"onUpdate:modelValue\\"]), [[_vModelDynamic, test]]);"
|
}, null, 8, [\\"type\\", \\"onUpdate:modelValue\\"]), [[_vModelDynamic, test]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`input[type="checkbox"]: input[type="checkbox"] 1`] = `
|
exports[`input[type="checkbox"] > input[type="checkbox"] 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelCheckbox as _vModelCheckbox } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelCheckbox as _vModelCheckbox } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"input\\", {
|
_withDirectives(_createVNode(\\"input\\", {
|
||||||
\\"type\\": \\"checkbox\\",
|
\\"type\\": \\"checkbox\\",
|
||||||
@ -80,7 +80,7 @@ _withDirectives(_createVNode(\\"input\\", {
|
|||||||
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelCheckbox, test]]);"
|
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelCheckbox, test]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`input[type="radio"]: input[type="radio"] 1`] = `
|
exports[`input[type="radio"] > input[type="radio"] 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelRadio as _vModelRadio, Fragment as _Fragment } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelRadio as _vModelRadio, Fragment as _Fragment } from \\"vue\\";
|
||||||
_createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
|
_createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
|
||||||
\\"type\\": \\"radio\\",
|
\\"type\\": \\"radio\\",
|
||||||
@ -95,7 +95,7 @@ _createVNode(_Fragment, null, [_withDirectives(_createVNode(\\"input\\", {
|
|||||||
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelRadio, test]])]);"
|
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelRadio, test]])]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`input[type="text"] .lazy modifier: input[type="text"] .lazy modifier 1`] = `
|
exports[`input[type="text"] .lazy modifier > input[type="text"] .lazy modifier 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"input\\", {
|
_withDirectives(_createVNode(\\"input\\", {
|
||||||
\\"onUpdate:modelValue\\": $event => test = $event
|
\\"onUpdate:modelValue\\": $event => test = $event
|
||||||
@ -104,31 +104,31 @@ _withDirectives(_createVNode(\\"input\\", {
|
|||||||
}]]);"
|
}]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`input[type="text"]: input[type="text"] 1`] = `
|
exports[`input[type="text"] > input[type="text"] 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"input\\", {
|
_withDirectives(_createVNode(\\"input\\", {
|
||||||
\\"onUpdate:modelValue\\": $event => test = $event
|
\\"onUpdate:modelValue\\": $event => test = $event
|
||||||
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
|
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`isCustomElement: isCustomElement 1`] = `
|
exports[`isCustomElement > isCustomElement 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
_createVNode(\\"foo\\", null, [_createVNode(\\"span\\", null, [_createTextVNode(\\"foo\\")])]);"
|
_createVNode(\\"foo\\", null, [_createVNode(\\"span\\", null, [_createTextVNode(\\"foo\\")])]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`named import specifier \`Keep Alive\`: named import specifier \`Keep Alive\` 1`] = `
|
exports[`named import specifier \`Keep Alive\` > named import specifier \`Keep Alive\` 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
import { KeepAlive } from 'vue';
|
import { KeepAlive } from 'vue';
|
||||||
_createVNode(KeepAlive, null, [_createTextVNode(\\"123\\")]);"
|
_createVNode(KeepAlive, null, [_createTextVNode(\\"123\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`namespace specifier \`Keep Alive\`: namespace specifier \`Keep Alive\` 1`] = `
|
exports[`namespace specifier \`Keep Alive\` > namespace specifier \`Keep Alive\` 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
import * as Vue from 'vue';
|
import * as Vue from 'vue';
|
||||||
_createVNode(Vue.KeepAlive, null, [_createTextVNode(\\"123\\")]);"
|
_createVNode(Vue.KeepAlive, null, [_createTextVNode(\\"123\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`override props multiple: multiple 1`] = `
|
exports[`override props multiple > multiple 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"A\\"), {
|
_createVNode(_resolveComponent(\\"A\\"), {
|
||||||
\\"loading\\": true,
|
\\"loading\\": true,
|
||||||
@ -142,12 +142,12 @@ _createVNode(_resolveComponent(\\"A\\"), {
|
|||||||
}, null);"
|
}, null);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`override props single: single 1`] = `
|
exports[`override props single > single 1`] = `
|
||||||
"import { createVNode as _createVNode } from \\"vue\\";
|
"import { createVNode as _createVNode } from \\"vue\\";
|
||||||
_createVNode(\\"div\\", a, null);"
|
_createVNode(\\"div\\", a, null);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`passing object slots via JSX children multiple expressions: multiple expressions 1`] = `
|
exports[`passing object slots via JSX children multiple expressions > multiple expressions 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"A\\"), null, {
|
_createVNode(_resolveComponent(\\"A\\"), null, {
|
||||||
default: () => [foo, bar],
|
default: () => [foo, bar],
|
||||||
@ -155,14 +155,14 @@ _createVNode(_resolveComponent(\\"A\\"), null, {
|
|||||||
});"
|
});"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`passing object slots via JSX children single expression, function expression: single expression, function expression 1`] = `
|
exports[`passing object slots via JSX children single expression, function expression > single expression, function expression 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"A\\"), null, {
|
_createVNode(_resolveComponent(\\"A\\"), null, {
|
||||||
default: () => \\"foo\\"
|
default: () => \\"foo\\"
|
||||||
});"
|
});"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`passing object slots via JSX children single expression, non-literal value: runtime check: single expression, non-literal value: runtime check 1`] = `
|
exports[`passing object slots via JSX children single expression, non-literal value: runtime check > single expression, non-literal value: runtime check 1`] = `
|
||||||
"let _slot;
|
"let _slot;
|
||||||
import { createVNode as _createVNode, isVNode as _isVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
import { createVNode as _createVNode, isVNode as _isVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
function _isSlot(s) {
|
function _isSlot(s) {
|
||||||
@ -175,7 +175,7 @@ _createVNode(_resolveComponent(\\"A\\"), null, _isSlot(_slot = foo()) ? _slot :
|
|||||||
});"
|
});"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`reassign variable as component: reassign variable as component 1`] = `
|
exports[`reassign variable as component > reassign variable as component 1`] = `
|
||||||
"import { isVNode as _isVNode, createVNode as _createVNode } from \\"vue\\";
|
"import { isVNode as _isVNode, createVNode as _createVNode } from \\"vue\\";
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
function _isSlot(s) {
|
function _isSlot(s) {
|
||||||
@ -200,7 +200,7 @@ a = _createVNode(A, null, _isSlot(a) ? a : {
|
|||||||
});"
|
});"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`select: select 1`] = `
|
exports[`select > select 1`] = `
|
||||||
"import { withDirectives as _withDirectives, vModelSelect as _vModelSelect, createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { withDirectives as _withDirectives, vModelSelect as _vModelSelect, createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"select\\", {
|
_withDirectives(_createVNode(\\"select\\", {
|
||||||
\\"onUpdate:modelValue\\": $event => test = $event
|
\\"onUpdate:modelValue\\": $event => test = $event
|
||||||
@ -213,37 +213,37 @@ _withDirectives(_createVNode(\\"select\\", {
|
|||||||
}, [_createTextVNode(\\"c\\")])], 8, [\\"onUpdate:modelValue\\"]), [[_vModelSelect, test]]);"
|
}, [_createTextVNode(\\"c\\")])], 8, [\\"onUpdate:modelValue\\"]), [[_vModelSelect, test]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`set pragma to custom: custom 1`] = `
|
exports[`set pragma to custom > custom 1`] = `
|
||||||
"import { createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
custom(\\"div\\", null, [_createTextVNode(\\"pragma\\")]);"
|
custom(\\"div\\", null, [_createTextVNode(\\"pragma\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`should keep \`import * as Vue from "vue"\`: should keep \`import * as Vue from "vue"\` 1`] = `
|
exports[`should keep \`import * as Vue from "vue"\` > should keep \`import * as Vue from "vue"\` 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
import * as Vue from 'vue';
|
import * as Vue from 'vue';
|
||||||
_createVNode(\\"div\\", null, [_createTextVNode(\\"Vue\\")]);"
|
_createVNode(\\"div\\", null, [_createTextVNode(\\"Vue\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`single no need for a mergeProps call: single no need for a mergeProps call 1`] = `
|
exports[`single no need for a mergeProps call > single no need for a mergeProps call 1`] = `
|
||||||
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createVNode as _createVNode, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
_createVNode(\\"div\\", x, [_createTextVNode(\\"single\\")], 16);"
|
_createVNode(\\"div\\", x, [_createTextVNode(\\"single\\")], 16);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`specifiers should be merged into a single importDeclaration: specifiers should be merged into a single importDeclaration 1`] = `
|
exports[`specifiers should be merged into a single importDeclaration > specifiers should be merged into a single importDeclaration 1`] = `
|
||||||
"import { createVNode as _createVNode } from \\"vue\\";
|
"import { createVNode as _createVNode } from \\"vue\\";
|
||||||
import { createVNode, Fragment as _Fragment } from 'vue';
|
import { createVNode, Fragment as _Fragment } from 'vue';
|
||||||
import { vShow } from 'vue';
|
import { vShow } from 'vue';
|
||||||
_createVNode(_Fragment, null, null);"
|
_createVNode(_Fragment, null, null);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`textarea: textarea 1`] = `
|
exports[`textarea > textarea 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vModelText as _vModelText } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"textarea\\", {
|
_withDirectives(_createVNode(\\"textarea\\", {
|
||||||
\\"onUpdate:modelValue\\": $event => test = $event
|
\\"onUpdate:modelValue\\": $event => test = $event
|
||||||
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
|
}, null, 8, [\\"onUpdate:modelValue\\"]), [[_vModelText, test]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`use "@jsx" comment specify pragma: use "@jsx" comment specify pragma 1`] = `
|
exports[`use "@jsx" comment specify pragma > use "@jsx" comment specify pragma 1`] = `
|
||||||
"import { createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
/* @jsx custom */
|
/* @jsx custom */
|
||||||
custom(\\"div\\", {
|
custom(\\"div\\", {
|
||||||
@ -251,7 +251,7 @@ custom(\\"div\\", {
|
|||||||
}, [_createTextVNode(\\"Hello\\")]);"
|
}, [_createTextVNode(\\"Hello\\")]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`use "model" as the prop name: use "model" as the prop name 1`] = `
|
exports[`use "model" as the prop name > use "model" as the prop name 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"C\\"), {
|
_createVNode(_resolveComponent(\\"C\\"), {
|
||||||
\\"model\\": foo,
|
\\"model\\": foo,
|
||||||
@ -259,12 +259,12 @@ _createVNode(_resolveComponent(\\"C\\"), {
|
|||||||
}, null, 8, [\\"model\\", \\"onUpdate:model\\"]);"
|
}, null, 8, [\\"model\\", \\"onUpdate:model\\"]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`using v-slots without children should not be spread: using v-slots without children should not be spread 1`] = `
|
exports[`using v-slots without children should not be spread > using v-slots without children should not be spread 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveDirective as _resolveDirective, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"A\\"), null, slots);"
|
_createVNode(_resolveComponent(\\"A\\"), null, slots);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-model target value support variable: v-model target value support variable 1`] = `
|
exports[`v-model target value support variable > v-model target value support variable 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment } from \\"vue\\";
|
||||||
const foo = 'foo';
|
const foo = 'foo';
|
||||||
const a = () => 'a';
|
const a = () => 'a';
|
||||||
@ -307,19 +307,19 @@ _createVNode(_Fragment, null, [_createVNode(_resolveComponent(\\"A\\"), {
|
|||||||
}, null, 16)]);"
|
}, null, 16)]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-show: v-show 1`] = `
|
exports[`v-show > v-show 1`] = `
|
||||||
"import { withDirectives as _withDirectives, createVNode as _createVNode, vShow as _vShow, createTextVNode as _createTextVNode } from \\"vue\\";
|
"import { withDirectives as _withDirectives, createVNode as _createVNode, vShow as _vShow, createTextVNode as _createTextVNode } from \\"vue\\";
|
||||||
_withDirectives(_createVNode(\\"div\\", null, [_createTextVNode(\\"vShow\\")], 512), [[_vShow, x]]);"
|
_withDirectives(_createVNode(\\"div\\", null, [_createTextVNode(\\"vShow\\")], 512), [[_vShow, x]]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`vHtml: vHtml 1`] = `
|
exports[`vHtml > vHtml 1`] = `
|
||||||
"import { createVNode as _createVNode } from \\"vue\\";
|
"import { createVNode as _createVNode } from \\"vue\\";
|
||||||
_createVNode(\\"h1\\", {
|
_createVNode(\\"h1\\", {
|
||||||
\\"innerHTML\\": \\"<div>foo</div>\\"
|
\\"innerHTML\\": \\"<div>foo</div>\\"
|
||||||
}, null, 8, [\\"innerHTML\\"]);"
|
}, null, 8, [\\"innerHTML\\"]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`vModels: vModels 1`] = `
|
exports[`vModels > vModels 1`] = `
|
||||||
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
"import { createVNode as _createVNode, resolveComponent as _resolveComponent } from \\"vue\\";
|
||||||
_createVNode(_resolveComponent(\\"C\\"), {
|
_createVNode(_resolveComponent(\\"C\\"), {
|
||||||
\\"modelValue\\": foo,
|
\\"modelValue\\": foo,
|
||||||
@ -336,7 +336,7 @@ _createVNode(_resolveComponent(\\"C\\"), {
|
|||||||
}, null, 8, [\\"modelValue\\", \\"onUpdate:modelValue\\", \\"bar\\", \\"onUpdate:bar\\"]);"
|
}, null, 8, [\\"modelValue\\", \\"onUpdate:modelValue\\", \\"bar\\", \\"onUpdate:bar\\"]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`vText: vText 1`] = `
|
exports[`vText > vText 1`] = `
|
||||||
"import { createVNode as _createVNode } from \\"vue\\";
|
"import { createVNode as _createVNode } from \\"vue\\";
|
||||||
_createVNode(\\"div\\", {
|
_createVNode(\\"div\\", {
|
||||||
\\"textContent\\": text
|
\\"textContent\\": text
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import {
|
import {
|
||||||
|
type CSSProperties,
|
||||||
|
type ComponentPublicInstance,
|
||||||
|
Transition,
|
||||||
|
defineComponent,
|
||||||
reactive,
|
reactive,
|
||||||
ref,
|
ref,
|
||||||
defineComponent,
|
|
||||||
CSSProperties,
|
|
||||||
ComponentPublicInstance,
|
|
||||||
Transition,
|
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { shallowMount, mount, VueWrapper } from '@vue/test-utils';
|
import { type VueWrapper, mount, shallowMount } from '@vue/test-utils';
|
||||||
|
|
||||||
const patchFlagExpect = (
|
const patchFlagExpect = (
|
||||||
wrapper: VueWrapper<ComponentPublicInstance>,
|
wrapper: VueWrapper<ComponentPublicInstance>,
|
||||||
flag: number,
|
flag: number,
|
||||||
dynamic: string[] | null,
|
dynamic: string[] | null
|
||||||
) => {
|
) => {
|
||||||
const { patchFlag, dynamicProps } = wrapper.vm.$.subTree as any;
|
const { patchFlag, dynamicProps } = wrapper.vm.$.subTree as any;
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ describe('Transform JSX', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.html()).toBe('<div>123</div><div>456</div>');
|
expect(wrapper.html()).toBe('<div>123</div>\n<div>456</div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('nested component', () => {
|
test('nested component', () => {
|
||||||
@ -125,7 +125,7 @@ describe('Transform JSX', () => {
|
|||||||
test('Merge class', () => {
|
test('Merge class', () => {
|
||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount({
|
||||||
setup() {
|
setup() {
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
return () => <div class="a" {...{ class: 'b' }} />;
|
return () => <div class="a" {...{ class: 'b' }} />;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -152,7 +152,7 @@ describe('Transform JSX', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(wrapper.html()).toBe(
|
expect(wrapper.html()).toBe(
|
||||||
'<div style="color: blue; width: 300px; height: 300px;"></div>',
|
'<div style="color: blue; width: 300px; height: 300px;"></div>'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -234,8 +234,8 @@ describe('Transform JSX', () => {
|
|||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount({
|
||||||
setup() {
|
setup() {
|
||||||
return () => (
|
return () => (
|
||||||
<a
|
<button
|
||||||
href="huhu"
|
type="button"
|
||||||
{...data}
|
{...data}
|
||||||
class={{ c: true }}
|
class={{ c: true }}
|
||||||
onClick={() => calls.push(4)}
|
onClick={() => calls.push(4)}
|
||||||
@ -246,7 +246,7 @@ describe('Transform JSX', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.attributes('id')).toBe('hehe');
|
expect(wrapper.attributes('id')).toBe('hehe');
|
||||||
expect(wrapper.attributes('href')).toBe('huhu');
|
expect(wrapper.attributes('type')).toBe('button');
|
||||||
expect(wrapper.text()).toBe('2');
|
expect(wrapper.text()).toBe('2');
|
||||||
expect(wrapper.classes()).toEqual(expect.arrayContaining(['a', 'b', 'c']));
|
expect(wrapper.classes()).toEqual(expect.arrayContaining(['a', 'b', 'c']));
|
||||||
|
|
||||||
@ -261,10 +261,10 @@ describe('directive', () => {
|
|||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount({
|
||||||
setup() {
|
setup() {
|
||||||
const html = '<div>foo</div>';
|
const html = '<div>foo</div>';
|
||||||
return () => <h1 v-html={ html }></h1>;
|
return () => <h1 v-html={html}></h1>;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(wrapper.html()).toBe('<h1><div>foo</div></h1>');
|
expect(wrapper.html()).toBe('<h1>\n <div>foo</div>\n</h1>');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('vText', () => {
|
test('vText', () => {
|
||||||
@ -420,7 +420,7 @@ describe('variables outside slots', () => {
|
|||||||
</A>
|
</A>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(wrapper.get('#textarea').element.innerHTML).toBe('0');
|
expect(wrapper.get('#textarea').element.innerHTML).toBe('0');
|
||||||
@ -582,8 +582,15 @@ describe('should support passing object slots via JSX children', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.html()).toBe(
|
expect(wrapper.html()).toMatchInlineSnapshot(
|
||||||
'<span><span>A</span><!----></span><span><span>B</span><!----></span><span><span>C</span><!----></span>',
|
`
|
||||||
|
"<span><span>A</span>
|
||||||
|
<!----></span>
|
||||||
|
<span><span>B</span>
|
||||||
|
<!----></span>
|
||||||
|
<span><span>C</span>
|
||||||
|
<!----></span>"
|
||||||
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -602,8 +609,15 @@ describe('should support passing object slots via JSX children', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.html()).toBe(
|
expect(wrapper.html()).toMatchInlineSnapshot(
|
||||||
'<span><span>A</span><!----></span><span><span>B</span><!----></span><span><span>C</span><!----></span>',
|
`
|
||||||
|
"<span><span>A</span>
|
||||||
|
<!----></span>
|
||||||
|
<span><span>B</span>
|
||||||
|
<!----></span>
|
||||||
|
<span><span>C</span>
|
||||||
|
<!----></span>"
|
||||||
|
`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
import { transform } from '@babel/core';
|
import { transform } from '@babel/core';
|
||||||
import JSX, { VueJSXPluginOptions } from '../src';
|
import JSX, { type VueJSXPluginOptions } from '../src';
|
||||||
|
|
||||||
interface Test {
|
interface Test {
|
||||||
name: string;
|
name: string;
|
||||||
from: string;
|
from: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transpile = (
|
const transpile = (source: string, options: VueJSXPluginOptions = {}) =>
|
||||||
source: string, options: VueJSXPluginOptions = {},
|
new Promise((resolve, reject) =>
|
||||||
) => new Promise((resolve, reject) => transform(
|
transform(
|
||||||
source,
|
source,
|
||||||
{
|
{
|
||||||
filename: '',
|
filename: '',
|
||||||
presets: null,
|
presets: null,
|
||||||
plugins: [[JSX, options]],
|
plugins: [[JSX, options]],
|
||||||
configFile: false,
|
configFile: false,
|
||||||
}, (error, result) => {
|
},
|
||||||
|
(error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return reject(error);
|
return reject(error);
|
||||||
}
|
}
|
||||||
resolve(result?.code);
|
resolve(result?.code);
|
||||||
},
|
}
|
||||||
));
|
)
|
||||||
|
);
|
||||||
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -206,34 +208,29 @@ const transpile = (
|
|||||||
name: 'using v-slots without children should not be spread',
|
name: 'using v-slots without children should not be spread',
|
||||||
from: '<A v-slots={slots} />',
|
from: '<A v-slots={slots} />',
|
||||||
},
|
},
|
||||||
].forEach((
|
].forEach(({ name, from }) => {
|
||||||
{ name, from },
|
test(name, async () => {
|
||||||
) => {
|
expect(
|
||||||
test(
|
await transpile(from, { optimize: true, enableObjectSlots: true })
|
||||||
name,
|
).toMatchSnapshot(name);
|
||||||
async () => {
|
});
|
||||||
expect(await transpile(from, { optimize: true, enableObjectSlots: true })).toMatchSnapshot(name);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const overridePropsTests: Test[] = [{
|
const overridePropsTests: Test[] = [
|
||||||
|
{
|
||||||
name: 'single',
|
name: 'single',
|
||||||
from: '<div {...a} />',
|
from: '<div {...a} />',
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: 'multiple',
|
name: 'multiple',
|
||||||
from: '<A loading {...a} {...{ b: 1, c: { d: 2 } }} class="x" style={x} />',
|
from: '<A loading {...a} {...{ b: 1, c: { d: 2 } }} class="x" style={x} />',
|
||||||
}];
|
|
||||||
|
|
||||||
overridePropsTests.forEach((
|
|
||||||
{ name, from },
|
|
||||||
) => {
|
|
||||||
test(
|
|
||||||
`override props ${name}`,
|
|
||||||
async () => {
|
|
||||||
expect(await transpile(from, { mergeProps: false })).toMatchSnapshot(name);
|
|
||||||
},
|
},
|
||||||
);
|
];
|
||||||
|
|
||||||
|
overridePropsTests.forEach(({ name, from }) => {
|
||||||
|
test(`override props ${name}`, async () => {
|
||||||
|
expect(await transpile(from, { mergeProps: false })).toMatchSnapshot(name);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const slotsTests: Test[] = [
|
const slotsTests: Test[] = [
|
||||||
@ -256,15 +253,12 @@ const slotsTests: Test[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
slotsTests.forEach(({
|
slotsTests.forEach(({ name, from }) => {
|
||||||
name, from,
|
test(`passing object slots via JSX children ${name}`, async () => {
|
||||||
}) => {
|
expect(
|
||||||
test(
|
await transpile(from, { optimize: true, enableObjectSlots: true })
|
||||||
`passing object slots via JSX children ${name}`,
|
).toMatchSnapshot(name);
|
||||||
async () => {
|
});
|
||||||
expect(await transpile(from, { optimize: true, enableObjectSlots: true })).toMatchSnapshot(name);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const objectSlotsTests = [
|
const objectSlotsTests = [
|
||||||
@ -274,16 +268,12 @@ const objectSlotsTests = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
objectSlotsTests.forEach(({
|
objectSlotsTests.forEach(({ name, from }) => {
|
||||||
name, from,
|
test(`disable object slot syntax with ${name}`, async () => {
|
||||||
}) => {
|
expect(
|
||||||
test(
|
await transpile(from, { optimize: true, enableObjectSlots: false })
|
||||||
`disable object slot syntax with ${name}`,
|
).toMatchSnapshot(name);
|
||||||
async () => {
|
});
|
||||||
expect(await transpile(from, { optimize: true, enableObjectSlots: false }))
|
|
||||||
.toMatchSnapshot(name);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const pragmaTests = [
|
const pragmaTests = [
|
||||||
@ -293,46 +283,40 @@ const pragmaTests = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
pragmaTests.forEach(({
|
pragmaTests.forEach(({ name, from }) => {
|
||||||
name, from,
|
test(`set pragma to ${name}`, async () => {
|
||||||
}) => {
|
expect(await transpile(from, { pragma: 'custom' })).toMatchSnapshot(name);
|
||||||
test(
|
});
|
||||||
`set pragma to ${name}`,
|
|
||||||
async () => {
|
|
||||||
expect(await transpile(from, { pragma: 'custom' }))
|
|
||||||
.toMatchSnapshot(name);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const isCustomElementTests = [{
|
const isCustomElementTests = [
|
||||||
|
{
|
||||||
name: 'isCustomElement',
|
name: 'isCustomElement',
|
||||||
from: '<foo><span>foo</span></foo>',
|
from: '<foo><span>foo</span></foo>',
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
isCustomElementTests.forEach(({ name, from }) => {
|
isCustomElementTests.forEach(({ name, from }) => {
|
||||||
test(
|
test(name, async () => {
|
||||||
name,
|
expect(
|
||||||
async () => {
|
await transpile(from, { isCustomElement: (tag) => tag === 'foo' })
|
||||||
expect(await transpile(from, { isCustomElement: (tag) => tag === 'foo' })).toMatchSnapshot(name);
|
).toMatchSnapshot(name);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fragmentTests = [{
|
const fragmentTests = [
|
||||||
|
{
|
||||||
name: '_Fragment already imported',
|
name: '_Fragment already imported',
|
||||||
from: `
|
from: `
|
||||||
import { Fragment as _Fragment } from 'vue'
|
import { Fragment as _Fragment } from 'vue'
|
||||||
const Root1 = () => <>root1</>
|
const Root1 = () => <>root1</>
|
||||||
const Root2 = () => <_Fragment>root2</_Fragment>
|
const Root2 = () => <_Fragment>root2</_Fragment>
|
||||||
`,
|
`,
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
fragmentTests.forEach(({ name, from }) => {
|
fragmentTests.forEach(({ name, from }) => {
|
||||||
test(
|
test(name, async () => {
|
||||||
name,
|
|
||||||
async () => {
|
|
||||||
expect(await transpile(from)).toMatchSnapshot(name);
|
expect(await transpile(from)).toMatchSnapshot(name);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { shallowMount, mount } from '@vue/test-utils';
|
import { mount, shallowMount } from '@vue/test-utils';
|
||||||
import { defineComponent, VNode } from '@vue/runtime-dom';
|
import { type VNode, defineComponent } from '@vue/runtime-dom';
|
||||||
|
|
||||||
test('input[type="checkbox"] should work', async () => {
|
test('input[type="checkbox"] should work', async () => {
|
||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount(
|
||||||
|
{
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
test: true,
|
test: true,
|
||||||
@ -10,8 +11,10 @@ test('input[type="checkbox"] should work', async () => {
|
|||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
return <input type="checkbox" v-model={this.test} />;
|
return <input type="checkbox" v-model={this.test} />;
|
||||||
}
|
},
|
||||||
}, { attachTo: document.body });
|
},
|
||||||
|
{ attachTo: document.body }
|
||||||
|
);
|
||||||
|
|
||||||
expect(wrapper.vm.$el.checked).toBe(true);
|
expect(wrapper.vm.$el.checked).toBe(true);
|
||||||
wrapper.vm.test = false;
|
wrapper.vm.test = false;
|
||||||
@ -24,7 +27,8 @@ test('input[type="checkbox"] should work', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('input[type="radio"] should work', async () => {
|
test('input[type="radio"] should work', async () => {
|
||||||
const wrapper = shallowMount({
|
const wrapper = shallowMount(
|
||||||
|
{
|
||||||
data: () => ({
|
data: () => ({
|
||||||
test: '1',
|
test: '1',
|
||||||
}),
|
}),
|
||||||
@ -36,7 +40,9 @@ test('input[type="radio"] should work', async () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}, { attachTo: document.body });
|
},
|
||||||
|
{ attachTo: document.body }
|
||||||
|
);
|
||||||
|
|
||||||
const [a, b] = wrapper.vm.$.subTree.children as VNode[];
|
const [a, b] = wrapper.vm.$.subTree.children as VNode[];
|
||||||
|
|
||||||
@ -244,9 +250,7 @@ test('Named model', async () => {
|
|||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
emit('update:value', 2);
|
emit('update:value', 2);
|
||||||
};
|
};
|
||||||
return () => (
|
return () => <div onClick={handleClick}>{props.value}</div>;
|
||||||
<div onClick={ handleClick }>{ props.value }</div>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -255,7 +259,7 @@ test('Named model', async () => {
|
|||||||
foo: 0,
|
foo: 0,
|
||||||
}),
|
}),
|
||||||
render() {
|
render() {
|
||||||
return <Child v-model:value={ this.foo } />;
|
return <Child v-model:value={this.foo} />;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"rootDirs": ["./src"],
|
|
||||||
"outDir": "dist",
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"declaration": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
},
|
|
||||||
"include": ["src/**/*", "global.d.ts"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
8
packages/babel-plugin-jsx/tsup.config.ts
Normal file
8
packages/babel-plugin-jsx/tsup.config.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { defineConfig } from 'tsup';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/index.ts'],
|
||||||
|
format: ['cjs', 'esm'],
|
||||||
|
dts: true,
|
||||||
|
platform: 'neutral',
|
||||||
|
});
|
@ -1,2 +1 @@
|
|||||||
# JSX Explorer
|
# JSX Explorer
|
||||||
|
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
<title>Vue JSX Explorer</title>
|
<!DOCTYPE html>
|
||||||
<link rel="stylesheet" data-name="vs/editor/editor.main" href="https://unpkg.com/monaco-editor@0.20.0/min/vs/editor/editor.main.css">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
<div id="header"></div>
|
<meta charset="UTF-8" />
|
||||||
<div id="source" class="editor"></div>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<div id="output" class="editor"></div>
|
<title>Vue JSX Explorer</title>
|
||||||
|
</head>
|
||||||
<script src="https://unpkg.com/monaco-editor@0.20.0/min/vs/loader.js"></script>
|
<body>
|
||||||
<script>
|
<div id="header"></div>
|
||||||
require.config({
|
<div id="source" class="editor"></div>
|
||||||
paths: {
|
<div id="output" class="editor"></div>
|
||||||
'vs': 'https://unpkg.com/monaco-editor@0.20.0/min/vs'
|
<script type="module" src="./src/index.ts"></script>
|
||||||
}
|
</body>
|
||||||
})
|
</html>
|
||||||
</script>
|
|
||||||
<script src="./main.js"></script>
|
|
||||||
<script>
|
|
||||||
require(['vs/editor/editor.main'], init /* injected by build */)
|
|
||||||
</script>
|
|
||||||
|
@ -2,18 +2,19 @@
|
|||||||
"name": "@vue/jsx-explorer",
|
"name": "@vue/jsx-explorer",
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"monaco-editor": "^0.34.0"
|
"@babel/core": "^7.22.5",
|
||||||
|
"@vue/babel-plugin-jsx": "workspace:*",
|
||||||
|
"monaco-editor": "^0.39.0",
|
||||||
|
"vue": "^3.3.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.19.3",
|
"vite-plugin-monaco-editor": "^1.1.0",
|
||||||
"css-loader": "^3.6.0",
|
"vite-plugin-node-polyfills": "^0.9.0"
|
||||||
"html-webpack-plugin": "^4.5.2",
|
|
||||||
"style-loader": "^1.3.0",
|
|
||||||
"ts-loader": "^8.4.0",
|
|
||||||
"typescript": "^4.8.4",
|
|
||||||
"vue": "3.2.41",
|
|
||||||
"webpack": "^4.46.0",
|
|
||||||
"webpack-dev-server": "^3.11.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
|
||||||
|
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
|
@ -1,32 +1,30 @@
|
|||||||
/* eslint-disable no-console */
|
import * as monaco from 'monaco-editor';
|
||||||
// eslint-disable-next-line import/no-unresolved
|
|
||||||
import * as m from 'monaco-editor';
|
|
||||||
import { watchEffect } from 'vue';
|
import { watchEffect } from 'vue';
|
||||||
import { transform } from '@babel/core';
|
import { transform } from '@babel/core';
|
||||||
import babelPluginJsx from '../../babel-plugin-jsx/src';
|
import babelPluginJsx from '@vue/babel-plugin-jsx';
|
||||||
import { initOptions, compilerOptions, VueJSXPluginOptions } from './options';
|
import {
|
||||||
|
type VueJSXPluginOptions,
|
||||||
|
compilerOptions,
|
||||||
|
initOptions,
|
||||||
|
} from './options';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
declare global {
|
main();
|
||||||
interface Window {
|
|
||||||
monaco: typeof m
|
|
||||||
init: () => void
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PersistedState {
|
interface PersistedState {
|
||||||
src: string
|
src: string;
|
||||||
options: VueJSXPluginOptions
|
options: VueJSXPluginOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.init = () => {
|
function main() {
|
||||||
const { monaco } = window;
|
const persistedState: PersistedState = JSON.parse(
|
||||||
|
localStorage.getItem('state') || '{}'
|
||||||
const persistedState: PersistedState = JSON.parse(localStorage.getItem('state') || '{}');
|
);
|
||||||
|
|
||||||
Object.assign(compilerOptions, persistedState.options);
|
Object.assign(compilerOptions, persistedState.options);
|
||||||
|
|
||||||
const sharedEditorOptions: m.editor.IStandaloneEditorConstructionOptions = {
|
const sharedEditorOptions: monaco.editor.IStandaloneEditorConstructionOptions =
|
||||||
|
{
|
||||||
theme: 'vs-dark',
|
theme: 'vs-dark',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
wordWrap: 'on',
|
wordWrap: 'on',
|
||||||
@ -46,7 +44,10 @@ window.init = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const editor = monaco.editor.create(document.getElementById('source')!, {
|
const editor = monaco.editor.create(document.getElementById('source')!, {
|
||||||
value: decodeURIComponent(window.location.hash.slice(1)) || persistedState.src || 'const App = () => <div>Hello World</div>',
|
value:
|
||||||
|
decodeURIComponent(window.location.hash.slice(1)) ||
|
||||||
|
persistedState.src ||
|
||||||
|
'const App = () => <div>Hello World</div>',
|
||||||
language: 'typescript',
|
language: 'typescript',
|
||||||
tabSize: 2,
|
tabSize: 2,
|
||||||
...sharedEditorOptions,
|
...sharedEditorOptions,
|
||||||
@ -69,11 +70,14 @@ window.init = () => {
|
|||||||
localStorage.setItem('state', state);
|
localStorage.setItem('state', state);
|
||||||
window.location.hash = encodeURIComponent(src);
|
window.location.hash = encodeURIComponent(src);
|
||||||
console.clear();
|
console.clear();
|
||||||
transform(src, {
|
transform(
|
||||||
|
src,
|
||||||
|
{
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
plugins: [[babelPluginJsx, compilerOptions]],
|
plugins: [[babelPluginJsx, compilerOptions]],
|
||||||
ast: true,
|
ast: true,
|
||||||
}, (err, result = {}) => {
|
},
|
||||||
|
(err, result = {}) => {
|
||||||
const res = result!;
|
const res = result!;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
console.log('AST', res.ast!);
|
console.log('AST', res.ast!);
|
||||||
@ -81,7 +85,8 @@ window.init = () => {
|
|||||||
} else {
|
} else {
|
||||||
output.setValue(err.message!);
|
output.setValue(err.message!);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle resize
|
// handle resize
|
||||||
@ -95,11 +100,9 @@ window.init = () => {
|
|||||||
|
|
||||||
// update compile output when input changes
|
// update compile output when input changes
|
||||||
editor.onDidChangeModelContent(debounce(reCompile));
|
editor.onDidChangeModelContent(debounce(reCompile));
|
||||||
};
|
}
|
||||||
|
|
||||||
function debounce<T extends(...args: any[]) => any>(
|
function debounce<T extends (...args: any[]) => any>(fn: T, delay = 300): T {
|
||||||
fn: T,
|
|
||||||
delay = 300): T {
|
|
||||||
let prevTimer: number | null = null;
|
let prevTimer: number | null = null;
|
||||||
return ((...args: any[]) => {
|
return ((...args: any[]) => {
|
||||||
if (prevTimer) {
|
if (prevTimer) {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import {
|
import { createApp, h, reactive } from 'vue';
|
||||||
h, reactive, createApp,
|
import { type VueJSXPluginOptions } from '@vue/babel-plugin-jsx';
|
||||||
} from 'vue';
|
|
||||||
import { VueJSXPluginOptions } from '../../babel-plugin-jsx/src';
|
|
||||||
|
|
||||||
export { VueJSXPluginOptions };
|
export { VueJSXPluginOptions };
|
||||||
|
|
||||||
@ -19,16 +17,15 @@ const App = {
|
|||||||
h(
|
h(
|
||||||
'a',
|
'a',
|
||||||
{
|
{
|
||||||
href: 'https://app.netlify.com/sites/vue-next-jsx-explorer/deploys',
|
href: 'https://app.netlify.com/sites/vue-jsx-explorer/deploys',
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
},
|
},
|
||||||
'History',
|
'History'
|
||||||
),
|
),
|
||||||
|
|
||||||
h('div', { id: 'options-wrapper' }, [
|
h('div', { id: 'options-wrapper' }, [
|
||||||
h('div', { id: 'options-label' }, 'Options ↘'),
|
h('div', { id: 'options-label' }, 'Options ↘'),
|
||||||
h('ul', { id: 'options' }, [
|
h('ul', { id: 'options' }, [
|
||||||
|
|
||||||
// mergeProps
|
// mergeProps
|
||||||
h('li', [
|
h('li', [
|
||||||
h('input', {
|
h('input', {
|
||||||
@ -37,7 +34,9 @@ const App = {
|
|||||||
name: 'mergeProps',
|
name: 'mergeProps',
|
||||||
checked: compilerOptions.mergeProps,
|
checked: compilerOptions.mergeProps,
|
||||||
onChange(e: Event) {
|
onChange(e: Event) {
|
||||||
compilerOptions.mergeProps = (e.target as HTMLInputElement).checked;
|
compilerOptions.mergeProps = (
|
||||||
|
e.target as HTMLInputElement
|
||||||
|
).checked;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
h('label', { for: 'mergeProps' }, 'mergeProps'),
|
h('label', { for: 'mergeProps' }, 'mergeProps'),
|
||||||
@ -50,7 +49,9 @@ const App = {
|
|||||||
id: 'optimize',
|
id: 'optimize',
|
||||||
checked: compilerOptions.optimize,
|
checked: compilerOptions.optimize,
|
||||||
onChange(e: Event) {
|
onChange(e: Event) {
|
||||||
compilerOptions.optimize = (e.target as HTMLInputElement).checked;
|
compilerOptions.optimize = (
|
||||||
|
e.target as HTMLInputElement
|
||||||
|
).checked;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
h('label', { for: 'optimize' }, 'optimize'),
|
h('label', { for: 'optimize' }, 'optimize'),
|
||||||
@ -63,7 +64,9 @@ const App = {
|
|||||||
id: 'transformOn',
|
id: 'transformOn',
|
||||||
checked: compilerOptions.transformOn,
|
checked: compilerOptions.transformOn,
|
||||||
onChange(e: Event) {
|
onChange(e: Event) {
|
||||||
compilerOptions.transformOn = (e.target as HTMLInputElement).checked;
|
compilerOptions.transformOn = (
|
||||||
|
e.target as HTMLInputElement
|
||||||
|
).checked;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
h('label', { for: 'transformOn' }, 'transformOn'),
|
h('label', { for: 'transformOn' }, 'transformOn'),
|
||||||
@ -73,10 +76,12 @@ const App = {
|
|||||||
h('li', [
|
h('li', [
|
||||||
h('input', {
|
h('input', {
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
id: 'transformOn',
|
id: 'enableObjectSlots',
|
||||||
checked: compilerOptions.enableObjectSlots,
|
checked: compilerOptions.enableObjectSlots,
|
||||||
onChange(e: Event) {
|
onChange(e: Event) {
|
||||||
compilerOptions.enableObjectSlots = (e.target as HTMLInputElement).checked;
|
compilerOptions.enableObjectSlots = (
|
||||||
|
e.target as HTMLInputElement
|
||||||
|
).checked;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
h('label', { for: 'enableObjectSlots' }, 'enableObjectSlots'),
|
h('label', { for: 'enableObjectSlots' }, 'enableObjectSlots'),
|
||||||
|
14
packages/jsx-explorer/vite.config.ts
Normal file
14
packages/jsx-explorer/vite.config.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import MonacoEditorPlugin from 'vite-plugin-monaco-editor';
|
||||||
|
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
MonacoEditorPlugin({}),
|
||||||
|
nodePolyfills({
|
||||||
|
globals: {
|
||||||
|
process: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
5732
pnpm-lock.yaml
generated
Normal file
5732
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
pnpm-workspace.yaml
Normal file
2
pnpm-workspace.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
- packages/*
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
||||||
"extends": [
|
|
||||||
"config:base",
|
|
||||||
"schedule:weekly",
|
|
||||||
"group:allNonMajor",
|
|
||||||
":semanticCommitTypeAll(chore)"
|
|
||||||
],
|
|
||||||
"rangeStrategy": "bump",
|
|
||||||
"labels": ["dependencies"],
|
|
||||||
"ignoreDeps": ["@types/node", "@vue/test-utils"]
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
const webpack = require('webpack');
|
|
||||||
const WebpackDevServer = require('webpack-dev-server');
|
|
||||||
const webpackConfig = require('./webpack.base.conf');
|
|
||||||
|
|
||||||
const compiler = webpack(webpackConfig);
|
|
||||||
|
|
||||||
const devServerOptions = {
|
|
||||||
inline: true,
|
|
||||||
open: true,
|
|
||||||
hot: true,
|
|
||||||
overlay: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const server = new WebpackDevServer(compiler, devServerOptions);
|
|
||||||
|
|
||||||
server.listen(8080, '127.0.0.1');
|
|
@ -1,13 +0,0 @@
|
|||||||
const webpack = require('webpack');
|
|
||||||
const webpackConfig = require('./webpack.base.conf');
|
|
||||||
|
|
||||||
webpack(Object.assign(webpackConfig, { mode: 'production', devtool: false }), (err, stats) => {
|
|
||||||
if (err) throw err;
|
|
||||||
process.stdout.write(`${stats.toString({
|
|
||||||
colors: true,
|
|
||||||
modules: false,
|
|
||||||
children: false,
|
|
||||||
chunks: false,
|
|
||||||
chunkModules: false,
|
|
||||||
})}\n\n`);
|
|
||||||
});
|
|
@ -1,48 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode: 'development',
|
|
||||||
devtool: false,
|
|
||||||
context: path.join(__dirname, '../packages/jsx-explorer'),
|
|
||||||
entry: './src/index.ts',
|
|
||||||
output: {
|
|
||||||
publicPath: './',
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.tsx?$/,
|
|
||||||
loader: 'ts-loader',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
options: {
|
|
||||||
transpileOnly: true,
|
|
||||||
compilerOptions: { downlevelIteration: true },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
use: [
|
|
||||||
'style-loader', 'css-loader',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.mjs$/,
|
|
||||||
include: /node_modules/,
|
|
||||||
type: 'javascript/auto'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: 'index.html',
|
|
||||||
filename: 'index.html',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.ts', '.js', '.mjs'],
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
fs: 'empty',
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,26 +1,22 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"target": "es2015",
|
"target": "ESNext",
|
||||||
"module": "commonjs",
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"experimentalDecorators": true,
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"lib": [
|
"types": ["vitest/globals"],
|
||||||
"esnext",
|
"skipLibCheck": true,
|
||||||
"dom"
|
"paths": {
|
||||||
],
|
"@vue/babel-plugin-jsx": ["./packages/babel-plugin-jsx/src"]
|
||||||
"types": ["node", "jest"],
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["packages/*/src", "packages/*/test"]
|
||||||
"global.d.ts",
|
|
||||||
"packages/*/src",
|
|
||||||
"packages/*/test",
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
22
vitest.config.ts
Normal file
22
vitest.config.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
import { babel } from '@rollup/plugin-babel';
|
||||||
|
import Jsx from './packages/babel-plugin-jsx/src';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
babel({
|
||||||
|
babelHelpers: 'bundled',
|
||||||
|
extensions: ['.tsx', '.jsx'],
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
Jsx,
|
||||||
|
{ optimize: true, isCustomElement: (tag: string) => /^x-/.test(tag) },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user