Skip to content

Commit 23b789f

Browse files
alexzhang1030sxzz
andauthored
feat: chain call (#231)
Co-authored-by: alexzhang1030 <1642114555@qq.com> Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
1 parent cccde34 commit 23b789f

30 files changed

+658
-10
lines changed

.changeset/fair-planes-pay.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@vue-macros/chain-call': patch
3+
'@vue-macros/common': patch
4+
---
5+
6+
new feature `chainCall`

packages/chain-call/macros-global.d.ts

Whitespace-only changes.

packages/chain-call/macros.d.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { type ComponentObjectPropsOptions, type ExtractPropTypes } from 'vue'
2+
3+
// copy from vue-core
4+
export type Prettify<T> = {
5+
[K in keyof T]: T[K]
6+
} & {}
7+
8+
type NotUndefined<T> = T extends undefined ? never : T
9+
type InferDefaults<T> = {
10+
[K in keyof T]?: InferDefault<T, T[K]>
11+
}
12+
type NativeType = null | number | string | boolean | symbol | Function
13+
type InferDefault<P, T> =
14+
| ((props: P) => T & {})
15+
| (T extends NativeType ? T : never)
16+
type PropsWithDefaults<
17+
T,
18+
Defaults extends InferDefaults<T>,
19+
BKeys extends keyof T
20+
> = Omit<T, keyof Defaults> & {
21+
[K in keyof Defaults]-?: K extends keyof T
22+
? Defaults[K] extends undefined
23+
? T[K]
24+
: NotUndefined<T[K]>
25+
: never
26+
} & {
27+
readonly [K in BKeys]-?: boolean
28+
}
29+
type DefineProps<T, BKeys extends keyof T> = Readonly<T> & {
30+
readonly [K in BKeys]-?: boolean
31+
}
32+
type BooleanKey<T, K extends keyof T = keyof T> = K extends any
33+
? [T[K]] extends [boolean | undefined]
34+
? K
35+
: never
36+
: never
37+
38+
// end
39+
40+
export type AttachWithDefaults<Props> = Props & {
41+
withDefaults(): Props
42+
withDefaults<
43+
BKeys extends BooleanKey<Props>,
44+
Defaults extends InferDefaults<Props>
45+
>(
46+
defaults?: Defaults
47+
): Prettify<PropsWithDefaults<Props, Defaults, BKeys>>
48+
}
49+
50+
export declare function defineProps<PropNames extends string = string>(
51+
props: PropNames[]
52+
): Prettify<
53+
AttachWithDefaults<
54+
Readonly<{
55+
[key in PropNames]?: any
56+
}>
57+
>
58+
>
59+
export declare function defineProps<
60+
PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions
61+
>(props: PP): Prettify<AttachWithDefaults<Readonly<ExtractPropTypes<PP>>>>
62+
63+
export declare function defineProps<TypeProps>(): AttachWithDefaults<
64+
DefineProps<TypeProps, BooleanKey<TypeProps>>
65+
>

packages/chain-call/package.json

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{
2+
"name": "@vue-macros/chain-call",
3+
"version": "0.0.0",
4+
"packageManager": "pnpm@8.6.0",
5+
"description": "chain-call feature from Vue Macros.",
6+
"keywords": [
7+
"vue-macros",
8+
"macros",
9+
"vue",
10+
"sfc",
11+
"setup",
12+
"script-setup",
13+
"chain-call",
14+
"unplugin"
15+
],
16+
"license": "MIT",
17+
"homepage": "https://github.com/sxzz/vue-macros#readme",
18+
"bugs": {
19+
"url": "https://github.com/sxzz/vue-macros/issues"
20+
},
21+
"repository": {
22+
"type": "git",
23+
"url": "git+https://github.com/sxzz/vue-macros.git",
24+
"directory": "packages/chain-call"
25+
},
26+
"author": "三咲智子 <sxzz@sxzz.moe>",
27+
"files": [
28+
"dist"
29+
],
30+
"main": "dist/index.js",
31+
"module": "dist/index.mjs",
32+
"types": "index.d.ts",
33+
"exports": {
34+
".": {
35+
"dev": "./src/index.ts",
36+
"types": "./dist/index.d.ts",
37+
"require": "./dist/index.js",
38+
"import": "./dist/index.mjs"
39+
},
40+
"./api": {
41+
"dev": "./src/api.ts",
42+
"types": "./dist/api.d.ts",
43+
"require": "./dist/api.js",
44+
"import": "./dist/api.mjs"
45+
},
46+
"./esbuild": {
47+
"dev": "./src/esbuild.ts",
48+
"types": "./dist/esbuild.d.ts",
49+
"require": "./dist/esbuild.js",
50+
"import": "./dist/esbuild.mjs"
51+
},
52+
"./rollup": {
53+
"dev": "./src/rollup.ts",
54+
"types": "./dist/rollup.d.ts",
55+
"require": "./dist/rollup.js",
56+
"import": "./dist/rollup.mjs"
57+
},
58+
"./vite": {
59+
"dev": "./src/vite.ts",
60+
"types": "./dist/vite.d.ts",
61+
"require": "./dist/vite.js",
62+
"import": "./dist/vite.mjs"
63+
},
64+
"./webpack": {
65+
"dev": "./src/webpack.ts",
66+
"types": "./dist/webpack.d.ts",
67+
"require": "./dist/webpack.js",
68+
"import": "./dist/webpack.mjs"
69+
},
70+
"./*": [
71+
"./*",
72+
"./*.d.ts"
73+
]
74+
},
75+
"typesVersions": {
76+
"<=4.9": {
77+
"*": [
78+
"./dist/*",
79+
"./*"
80+
]
81+
}
82+
},
83+
"scripts": {
84+
"build": "tsup && tsx ../../scripts/postbuild.ts",
85+
"dev": "DEV=1 tsup"
86+
},
87+
"dependencies": {
88+
"@vue-macros/common": "workspace:~",
89+
"unplugin": "^1.0.1"
90+
},
91+
"devDependencies": {
92+
"rollup": "^3.10.1"
93+
},
94+
"engines": {
95+
"node": ">=16.14.0"
96+
}
97+
}

packages/chain-call/src/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './core'
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {
2+
DEFINE_PROPS,
3+
MagicString,
4+
WITH_DEFAULTS,
5+
getTransformResult,
6+
isCallOf,
7+
isIdentifierOf,
8+
parseSFC,
9+
removeMacroImport,
10+
walkAST,
11+
} from '@vue-macros/common'
12+
import {
13+
type CallExpression,
14+
type MemberExpression,
15+
type Node,
16+
} from '@babel/types'
17+
18+
export function transformChainCall(code: string, id: string) {
19+
if (!code.includes(DEFINE_PROPS)) return
20+
21+
const { scriptSetup, getSetupAst, offset } = parseSFC(code, id)
22+
if (!scriptSetup) return
23+
24+
const s = new MagicString(code)
25+
const setupAst = getSetupAst()!
26+
27+
walkAST<Node>(setupAst, {
28+
enter(node) {
29+
if (removeMacroImport(node, s, offset)) return
30+
if (isChainCall(node)) processChainCall(node)
31+
},
32+
})
33+
34+
function processChainCall(node: CallExpression) {
35+
const withDefaultString: string | undefined =
36+
node.arguments[0] && s.sliceNode(node.arguments[0], { offset })
37+
const definePropsString = s.sliceNode(
38+
(node.callee as MemberExpression).object as CallExpression,
39+
{ offset }
40+
)
41+
42+
s.overwriteNode(
43+
node,
44+
withDefaultString
45+
? `${WITH_DEFAULTS}(${definePropsString}, ${withDefaultString})`
46+
: definePropsString,
47+
{ offset }
48+
)
49+
}
50+
51+
return getTransformResult(s, id)
52+
}
53+
54+
function isChainCall(node: Node): node is CallExpression {
55+
// defineProps().withDefaults()
56+
return (
57+
node.type === 'CallExpression' &&
58+
node.callee.type === 'MemberExpression' &&
59+
isCallOf(node.callee.object, DEFINE_PROPS) &&
60+
isIdentifierOf(node.callee.property, WITH_DEFAULTS)
61+
)
62+
}

packages/chain-call/src/esbuild.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import unplugin from '.'
2+
3+
export default unplugin.esbuild

packages/chain-call/src/index.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { createUnplugin } from 'unplugin'
2+
import {
3+
type BaseOptions,
4+
type MarkRequired,
5+
REGEX_SETUP_SFC,
6+
REGEX_VUE_SFC,
7+
REGEX_VUE_SUB,
8+
createFilter,
9+
detectVueVersion,
10+
} from '@vue-macros/common'
11+
import { transformChainCall } from './core'
12+
13+
export type Options = BaseOptions
14+
export type OptionsResolved = MarkRequired<Options, 'include' | 'version'>
15+
16+
function resolveOption(options: Options): OptionsResolved {
17+
const version = options.version || detectVueVersion()
18+
return {
19+
include: [REGEX_VUE_SFC, REGEX_SETUP_SFC, REGEX_VUE_SUB],
20+
...options,
21+
version,
22+
}
23+
}
24+
25+
const name = 'unplugin-vue-chain-call'
26+
27+
export default createUnplugin<Options | undefined, false>(
28+
(userOptions = {}) => {
29+
const options = resolveOption(userOptions)
30+
const filter = createFilter(options)
31+
32+
return {
33+
name,
34+
enforce: 'pre',
35+
36+
transformInclude(id) {
37+
return filter(id)
38+
},
39+
40+
transform(code, id) {
41+
return transformChainCall(code, id)
42+
},
43+
}
44+
}
45+
)

packages/chain-call/src/rollup.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import unplugin from '.'
2+
3+
export default unplugin.rollup

packages/chain-call/src/vite.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import unplugin from '.'
2+
3+
export default unplugin.vite

0 commit comments

Comments
 (0)