style: update format & lint config (#9162)

Co-authored-by: 丶远方 <yangpanteng@gmail.com>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
Co-authored-by: Guo Xingjun <99574369+Plumbiu@users.noreply.github.com>
This commit is contained in:
三咲智子 Kevin Deng 2023-12-26 19:39:47 +08:00 committed by GitHub
parent baf0b7664d
commit bfe6b459d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
464 changed files with 12844 additions and 12385 deletions

View File

@ -1,12 +1,11 @@
/* eslint-disable no-restricted-globals */
const { builtinModules } = require('node:module')
const DOMGlobals = ['window', 'document']
const NodeGlobals = ['module', 'require']
const banConstEnum = {
selector: 'TSEnumDeclaration[const=true]',
message:
'Please use non-const enums. This project automatically inlines enums.'
'Please use non-const enums. This project automatically inlines enums.',
}
/**
@ -15,9 +14,9 @@ const banConstEnum = {
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module'
sourceType: 'module',
},
plugins: ['jest'],
plugins: ['jest', 'import', '@typescript-eslint'],
rules: {
'no-debugger': 'error',
// most of the codebase are expected to be env agnostic
@ -32,8 +31,27 @@ module.exports = {
// tsc compiles assignment spread into Object.assign() calls, but esbuild
// still generates verbose helpers, so spread assignment is also prohiboted
'ObjectExpression > SpreadElement',
'AwaitExpression'
]
'AwaitExpression',
],
'sort-imports': ['error', { ignoreDeclarationSort: true }],
'import/no-nodejs-modules': [
'error',
{ allow: builtinModules.map(mod => `node:${mod}`) },
],
// This rule enforces the preference for using '@ts-expect-error' comments in TypeScript
// code to indicate intentional type errors, improving code clarity and maintainability.
'@typescript-eslint/prefer-ts-expect-error': 'error',
// Enforce the use of 'import type' for importing types
'@typescript-eslint/consistent-type-imports': [
'error',
{
fixStyle: 'inline-type-imports',
disallowTypeAnnotations: false,
},
],
// Enforce the use of top-level import type qualifier when an import only has specifiers with inline type qualifiers
'@typescript-eslint/no-import-type-side-effects': 'error',
},
overrides: [
// tests, no restrictions (runs in Node / jest with jsdom)
@ -43,54 +61,66 @@ module.exports = {
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'jest/no-disabled-tests': 'error',
'jest/no-focused-tests': 'error'
}
'jest/no-focused-tests': 'error',
},
},
// shared, may be used in any env
{
files: ['packages/shared/**'],
files: ['packages/shared/**', '.eslintrc.cjs'],
rules: {
'no-restricted-globals': 'off'
}
'no-restricted-globals': 'off',
},
},
// Packages targeting DOM
{
files: ['packages/{vue,vue-compat,runtime-dom}/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals]
}
'no-restricted-globals': ['error', ...NodeGlobals],
},
},
// Packages targeting Node
{
files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'],
rules: {
'no-restricted-globals': ['error', ...DOMGlobals],
'no-restricted-syntax': ['error', banConstEnum]
}
'no-restricted-syntax': ['error', banConstEnum],
},
},
// Private package, browser only + no syntax restrictions
{
files: ['packages/template-explorer/**', 'packages/sfc-playground/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
'no-restricted-syntax': ['error', banConstEnum]
}
'no-restricted-syntax': ['error', banConstEnum],
},
},
// JavaScript files
{
files: ['*.js', '*.cjs'],
rules: {
// We only do `no-unused-vars` checks for js files, TS files are checked by TypeScript itself.
'no-unused-vars': ['error', { vars: 'all', args: 'none' }]
}
'no-unused-vars': ['error', { vars: 'all', args: 'none' }],
},
},
// Node scripts
{
files: ['scripts/**', '*.{js,ts}', 'packages/**/index.js'],
files: [
'scripts/**',
'./*.{js,ts}',
'packages/*/*.js',
'packages/vue/*/*.js',
],
rules: {
'no-restricted-globals': 'off',
'no-restricted-syntax': ['error', banConstEnum]
}
}
]
'no-restricted-syntax': ['error', banConstEnum],
},
},
// Import nodejs modules in compiler-sfc
{
files: ['packages/compiler-sfc/src/**'],
rules: {
'import/no-nodejs-modules': ['error', { allow: builtinModules }],
},
},
],
}

View File

@ -7,35 +7,35 @@
packageRules: [
{
depTypeList: ['peerDependencies'],
enabled: false
enabled: false,
},
{
groupName: 'test',
matchPackageNames: ['vitest', 'jsdom', 'puppeteer'],
matchPackagePrefixes: ['@vitest']
matchPackagePrefixes: ['@vitest'],
},
{
groupName: 'playground',
matchFileNames: [
'packages/sfc-playground/package.json',
'packages/template-explorer/package.json'
]
'packages/template-explorer/package.json',
],
},
{
groupName: 'compiler',
matchPackageNames: ['magic-string'],
matchPackagePrefixes: ['@babel', 'postcss']
matchPackagePrefixes: ['@babel', 'postcss'],
},
{
groupName: 'build',
matchPackageNames: ['vite', 'terser'],
matchPackagePrefixes: ['rollup', 'esbuild', '@rollup', '@vitejs']
matchPackagePrefixes: ['rollup', 'esbuild', '@rollup', '@vitejs'],
},
{
groupName: 'lint',
matchPackageNames: ['simple-git-hooks', 'lint-staged'],
matchPackagePrefixes: ['@typescript-eslint', 'eslint', 'prettier']
}
matchPackagePrefixes: ['@typescript-eslint', 'eslint', 'prettier'],
},
],
ignoreDeps: [
'vue',
@ -45,6 +45,6 @@
'typescript',
// ESM only
'estree-walker'
]
'estree-walker',
],
}

View File

@ -1 +1,4 @@
dist
*.md
*.html
pnpm-lock.yaml

View File

@ -1,5 +1,5 @@
semi: false
singleQuote: true
printWidth: 80
trailingComma: 'none'
arrowParens: 'avoid'
{
"semi": false,
"singleQuote": true,
"arrowParens": "avoid"
}

2
.vscode/launch.json vendored
View File

@ -21,7 +21,7 @@
"console": "integratedTerminal",
"sourceMaps": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
]

View File

@ -13,9 +13,9 @@
"size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime",
"size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler",
"check": "tsc --incremental --noEmit",
"lint": "eslint --cache --ext .ts packages/*/{src,__tests__}/**.ts",
"format": "prettier --write --cache \"**/*.[tj]s?(x)\"",
"format-check": "prettier --check --cache \"**/*.[tj]s?(x)\"",
"lint": "eslint --cache --ext .js,.ts,.tsx .",
"format": "prettier --write --cache .",
"format-check": "prettier --check --cache .",
"test": "vitest",
"test-unit": "vitest -c vitest.unit.config.ts",
"test-e2e": "node scripts/build.js vue -f global -d && vitest -c vitest.e2e.config.ts",
@ -72,6 +72,7 @@
"@types/minimist": "^1.2.5",
"@types/node": "^20.10.5",
"@types/semver": "^7.5.5",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.15.0",
"@vitest/coverage-istanbul": "^1.1.0",
"@vue/consolidate": "0.17.3",
@ -81,6 +82,7 @@
"esbuild-plugin-polyfill-node": "^0.3.0",
"eslint": "^8.56.0",
"eslint-define-config": "^1.24.1",
"eslint-plugin-import": "npm:eslint-plugin-i@^2.29.1",
"eslint-plugin-jest": "^27.6.0",
"estree-walker": "^2.0.2",
"execa": "^8.0.1",

View File

@ -1,38 +1,38 @@
import {
locStub,
generate,
ConstantTypes,
type DirectiveArguments,
type ForCodegenNode,
type IfConditionalExpression,
NodeTypes,
RootNode,
createSimpleExpression,
type RootNode,
type VNodeCall,
createArrayExpression,
createAssignmentExpression,
createBlockStatement,
createCacheExpression,
createCallExpression,
createCompoundExpression,
createConditionalExpression,
createIfStatement,
createInterpolation,
createObjectExpression,
createObjectProperty,
createArrayExpression,
createCompoundExpression,
createInterpolation,
createCallExpression,
createConditionalExpression,
ForCodegenNode,
createCacheExpression,
createSimpleExpression,
createTemplateLiteral,
createBlockStatement,
createIfStatement,
createAssignmentExpression,
IfConditionalExpression,
createVNodeCall,
VNodeCall,
DirectiveArguments,
ConstantTypes
generate,
locStub,
} from '../src'
import {
CREATE_VNODE,
TO_DISPLAY_STRING,
RESOLVE_DIRECTIVE,
helperNameMap,
RESOLVE_COMPONENT,
CREATE_COMMENT,
CREATE_ELEMENT_VNODE,
CREATE_VNODE,
FRAGMENT,
RENDER_LIST,
CREATE_ELEMENT_VNODE
RESOLVE_COMPONENT,
RESOLVE_DIRECTIVE,
TO_DISPLAY_STRING,
helperNameMap,
} from '../src/runtimeHelpers'
import { createElementWithCodegen, genFlagText } from './testUtils'
import { PatchFlags } from '@vue/shared'
@ -51,59 +51,59 @@ function createRoot(options: Partial<RootNode> = {}): RootNode {
temps: 0,
codegenNode: createSimpleExpression(`null`, false),
loc: locStub,
...options
...options,
}
}
describe('compiler: codegen', () => {
test('module mode preamble', () => {
const root = createRoot({
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE])
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE]),
})
const { code } = generate(root, { mode: 'module' })
expect(code).toMatch(
`import { ${helperNameMap[CREATE_VNODE]} as _${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]} as _${helperNameMap[RESOLVE_DIRECTIVE]} } from "vue"`
`import { ${helperNameMap[CREATE_VNODE]} as _${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]} as _${helperNameMap[RESOLVE_DIRECTIVE]} } from "vue"`,
)
expect(code).toMatchSnapshot()
})
test('module mode preamble w/ optimizeImports: true', () => {
const root = createRoot({
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE])
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE]),
})
const { code } = generate(root, { mode: 'module', optimizeImports: true })
expect(code).toMatch(
`import { ${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]} } from "vue"`
`import { ${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]} } from "vue"`,
)
expect(code).toMatch(
`const _${helperNameMap[CREATE_VNODE]} = ${helperNameMap[CREATE_VNODE]}, _${helperNameMap[RESOLVE_DIRECTIVE]} = ${helperNameMap[RESOLVE_DIRECTIVE]}`
`const _${helperNameMap[CREATE_VNODE]} = ${helperNameMap[CREATE_VNODE]}, _${helperNameMap[RESOLVE_DIRECTIVE]} = ${helperNameMap[RESOLVE_DIRECTIVE]}`,
)
expect(code).toMatchSnapshot()
})
test('function mode preamble', () => {
const root = createRoot({
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE])
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE]),
})
const { code } = generate(root, { mode: 'function' })
expect(code).toMatch(`const _Vue = Vue`)
expect(code).toMatch(
`const { ${helperNameMap[CREATE_VNODE]}: _${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]}: _${helperNameMap[RESOLVE_DIRECTIVE]} } = _Vue`
`const { ${helperNameMap[CREATE_VNODE]}: _${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]}: _${helperNameMap[RESOLVE_DIRECTIVE]} } = _Vue`,
)
expect(code).toMatchSnapshot()
})
test('function mode preamble w/ prefixIdentifiers: true', () => {
const root = createRoot({
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE])
helpers: new Set([CREATE_VNODE, RESOLVE_DIRECTIVE]),
})
const { code } = generate(root, {
mode: 'function',
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(code).not.toMatch(`const _Vue = Vue`)
expect(code).toMatch(
`const { ${helperNameMap[CREATE_VNODE]}: _${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]}: _${helperNameMap[RESOLVE_DIRECTIVE]} } = Vue`
`const { ${helperNameMap[CREATE_VNODE]}: _${helperNameMap[CREATE_VNODE]}, ${helperNameMap[RESOLVE_DIRECTIVE]}: _${helperNameMap[RESOLVE_DIRECTIVE]} } = Vue`,
)
expect(code).toMatchSnapshot()
})
@ -112,27 +112,27 @@ describe('compiler: codegen', () => {
const root = createRoot({
components: [`Foo`, `bar-baz`, `barbaz`, `Qux__self`],
directives: [`my_dir_0`, `my_dir_1`],
temps: 3
temps: 3,
})
const { code } = generate(root, { mode: 'function' })
expect(code).toMatch(
`const _component_Foo = _${helperNameMap[RESOLVE_COMPONENT]}("Foo")\n`
`const _component_Foo = _${helperNameMap[RESOLVE_COMPONENT]}("Foo")\n`,
)
expect(code).toMatch(
`const _component_bar_baz = _${helperNameMap[RESOLVE_COMPONENT]}("bar-baz")\n`
`const _component_bar_baz = _${helperNameMap[RESOLVE_COMPONENT]}("bar-baz")\n`,
)
expect(code).toMatch(
`const _component_barbaz = _${helperNameMap[RESOLVE_COMPONENT]}("barbaz")\n`
`const _component_barbaz = _${helperNameMap[RESOLVE_COMPONENT]}("barbaz")\n`,
)
// implicit self reference from SFC filename
expect(code).toMatch(
`const _component_Qux = _${helperNameMap[RESOLVE_COMPONENT]}("Qux", true)\n`
`const _component_Qux = _${helperNameMap[RESOLVE_COMPONENT]}("Qux", true)\n`,
)
expect(code).toMatch(
`const _directive_my_dir_0 = _${helperNameMap[RESOLVE_DIRECTIVE]}("my_dir_0")\n`
`const _directive_my_dir_0 = _${helperNameMap[RESOLVE_DIRECTIVE]}("my_dir_0")\n`,
)
expect(code).toMatch(
`const _directive_my_dir_1 = _${helperNameMap[RESOLVE_DIRECTIVE]}("my_dir_1")\n`
`const _directive_my_dir_1 = _${helperNameMap[RESOLVE_DIRECTIVE]}("my_dir_1")\n`,
)
expect(code).toMatch(`let _temp0, _temp1, _temp2`)
expect(code).toMatchSnapshot()
@ -146,12 +146,12 @@ describe('compiler: codegen', () => {
[
createObjectProperty(
createSimpleExpression(`id`, true, locStub),
createSimpleExpression(`foo`, true, locStub)
)
createSimpleExpression(`foo`, true, locStub),
),
],
locStub
)
]
locStub,
),
],
})
const { code } = generate(root)
expect(code).toMatch(`const _hoisted_1 = hello`)
@ -161,7 +161,7 @@ describe('compiler: codegen', () => {
test('temps', () => {
const root = createRoot({
temps: 3
temps: 3,
})
const { code } = generate(root)
expect(code).toMatch(`let _temp0, _temp1, _temp2`)
@ -174,9 +174,9 @@ describe('compiler: codegen', () => {
codegenNode: {
type: NodeTypes.TEXT,
content: 'hello',
loc: locStub
}
})
loc: locStub,
},
}),
)
expect(code).toMatch(`return "hello"`)
expect(code).toMatchSnapshot()
@ -185,8 +185,8 @@ describe('compiler: codegen', () => {
test('interpolation', () => {
const { code } = generate(
createRoot({
codegenNode: createInterpolation(`hello`, locStub)
})
codegenNode: createInterpolation(`hello`, locStub),
}),
)
expect(code).toMatch(`return _${helperNameMap[TO_DISPLAY_STRING]}(hello)`)
expect(code).toMatchSnapshot()
@ -198,9 +198,9 @@ describe('compiler: codegen', () => {
codegenNode: {
type: NodeTypes.COMMENT,
content: 'foo',
loc: locStub
}
})
loc: locStub,
},
}),
)
expect(code).toMatch(`return _${helperNameMap[CREATE_COMMENT]}("foo")`)
expect(code).toMatchSnapshot()
@ -216,15 +216,15 @@ describe('compiler: codegen', () => {
{
type: NodeTypes.INTERPOLATION,
loc: locStub,
content: createSimpleExpression(`bar`, false, locStub)
content: createSimpleExpression(`bar`, false, locStub),
},
// nested compound
createCompoundExpression([` + `, `nested`])
])
})
createCompoundExpression([` + `, `nested`]),
]),
}),
)
expect(code).toMatch(
`return _ctx.foo + _${helperNameMap[TO_DISPLAY_STRING]}(bar) + nested`
`return _ctx.foo + _${helperNameMap[TO_DISPLAY_STRING]}(bar) + nested`,
)
expect(code).toMatchSnapshot()
})
@ -239,10 +239,10 @@ describe('compiler: codegen', () => {
codegenNode: createConditionalExpression(
createSimpleExpression('foo', false),
createSimpleExpression('bar', false),
createSimpleExpression('baz', false)
) as IfConditionalExpression
}
})
createSimpleExpression('baz', false),
) as IfConditionalExpression,
},
}),
)
expect(code).toMatch(/return foo\s+\? bar\s+: baz/)
expect(code).toMatchSnapshot()
@ -270,10 +270,10 @@ describe('compiler: codegen', () => {
patchFlag: '1',
dynamicProps: undefined,
directives: undefined,
loc: locStub
} as ForCodegenNode
}
})
loc: locStub,
} as ForCodegenNode,
},
}),
)
expect(code).toMatch(`openBlock(true)`)
expect(code).toMatchSnapshot()
@ -289,7 +289,7 @@ describe('compiler: codegen', () => {
'1 + 2',
false,
locStub,
ConstantTypes.CAN_STRINGIFY
ConstantTypes.CAN_STRINGIFY,
),
valueAlias: undefined,
keyAlias: undefined,
@ -306,10 +306,10 @@ describe('compiler: codegen', () => {
patchFlag: genFlagText(PatchFlags.STABLE_FRAGMENT),
dynamicProps: undefined,
directives: undefined,
loc: locStub
} as ForCodegenNode
}
})
loc: locStub,
} as ForCodegenNode,
},
}),
)
expect(code).toMatch(`openBlock()`)
expect(code).toMatchSnapshot()
@ -326,11 +326,11 @@ describe('compiler: codegen', () => {
[
createObjectProperty(
createSimpleExpression(`id`, true, locStub),
createSimpleExpression(`foo`, true, locStub)
createSimpleExpression(`foo`, true, locStub),
),
createObjectProperty(
createSimpleExpression(`prop`, false, locStub),
createSimpleExpression(`bar`, false, locStub)
createSimpleExpression(`bar`, false, locStub),
),
// compound expression as computed key
createObjectProperty(
@ -339,13 +339,13 @@ describe('compiler: codegen', () => {
loc: locStub,
children: [
`foo + `,
createSimpleExpression(`bar`, false, locStub)
]
createSimpleExpression(`bar`, false, locStub),
],
},
createSimpleExpression(`bar`, false, locStub)
)
createSimpleExpression(`bar`, false, locStub),
),
],
locStub
locStub,
),
// ChildNode[]
[
@ -356,17 +356,17 @@ describe('compiler: codegen', () => {
createObjectProperty(
// should quote the key!
createSimpleExpression(`some-key`, true, locStub),
createSimpleExpression(`foo`, true, locStub)
)
createSimpleExpression(`foo`, true, locStub),
),
],
locStub
)
)
locStub,
),
),
],
// flag
PatchFlags.FULL_PROPS + ''
)
})
PatchFlags.FULL_PROPS + '',
),
}),
)
expect(code).toMatch(`
return _${helperNameMap[CREATE_ELEMENT_VNODE]}("div", {
@ -384,9 +384,9 @@ describe('compiler: codegen', () => {
createRoot({
codegenNode: createArrayExpression([
createSimpleExpression(`foo`, false),
createCallExpression(`bar`, [`baz`])
])
})
createCallExpression(`bar`, [`baz`]),
]),
}),
)
expect(code).toMatch(`return [
foo,
@ -404,17 +404,17 @@ describe('compiler: codegen', () => {
createConditionalExpression(
createSimpleExpression(`orNot`, false),
createCallExpression(`bar`),
createCallExpression(`baz`)
)
)
})
createCallExpression(`baz`),
),
),
}),
)
expect(code).toMatch(
`return ok
? foo()
: orNot
? bar()
: baz()`
: baz()`,
)
expect(code).toMatchSnapshot()
})
@ -425,13 +425,13 @@ describe('compiler: codegen', () => {
cached: 1,
codegenNode: createCacheExpression(
1,
createSimpleExpression(`foo`, false)
)
createSimpleExpression(`foo`, false),
),
}),
{
mode: 'module',
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(code).toMatch(`_cache[1] || (_cache[1] = foo)`)
expect(code).toMatchSnapshot()
@ -444,13 +444,13 @@ describe('compiler: codegen', () => {
codegenNode: createCacheExpression(
1,
createSimpleExpression(`foo`, false),
true
)
true,
),
}),
{
mode: 'module',
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(code).toMatch(
`
@ -460,7 +460,7 @@ describe('compiler: codegen', () => {
_setBlockTracking(1),
_cache[1]
)
`.trim()
`.trim(),
)
expect(code).toMatchSnapshot()
})
@ -472,11 +472,11 @@ describe('compiler: codegen', () => {
createTemplateLiteral([
`foo`,
createCallExpression(`_renderAttr`, ['id', 'foo']),
`bar`
])
])
`bar`,
]),
]),
}),
{ ssr: true, mode: 'module' }
{ ssr: true, mode: 'module' },
)
expect(code).toMatchInlineSnapshot(`
"
@ -493,11 +493,11 @@ describe('compiler: codegen', () => {
codegenNode: createBlockStatement([
createIfStatement(
createSimpleExpression('foo', false),
createBlockStatement([createCallExpression(`ok`)])
)
])
createBlockStatement([createCallExpression(`ok`)]),
),
]),
}),
{ ssr: true, mode: 'module' }
{ ssr: true, mode: 'module' },
)
expect(code).toMatchInlineSnapshot(`
"
@ -516,11 +516,11 @@ describe('compiler: codegen', () => {
createIfStatement(
createSimpleExpression('foo', false),
createBlockStatement([createCallExpression(`foo`)]),
createBlockStatement([createCallExpression('bar')])
)
])
createBlockStatement([createCallExpression('bar')]),
),
]),
}),
{ ssr: true, mode: 'module' }
{ ssr: true, mode: 'module' },
)
expect(code).toMatchInlineSnapshot(`
"
@ -543,12 +543,12 @@ describe('compiler: codegen', () => {
createBlockStatement([createCallExpression(`foo`)]),
createIfStatement(
createSimpleExpression('bar', false),
createBlockStatement([createCallExpression(`bar`)])
)
)
])
createBlockStatement([createCallExpression(`bar`)]),
),
),
]),
}),
{ ssr: true, mode: 'module' }
{ ssr: true, mode: 'module' },
)
expect(code).toMatchInlineSnapshot(`
"
@ -572,12 +572,12 @@ describe('compiler: codegen', () => {
createIfStatement(
createSimpleExpression('bar', false),
createBlockStatement([createCallExpression(`bar`)]),
createBlockStatement([createCallExpression('baz')])
)
)
])
createBlockStatement([createCallExpression('baz')]),
),
),
]),
}),
{ ssr: true, mode: 'module' }
{ ssr: true, mode: 'module' },
)
expect(code).toMatchInlineSnapshot(`
"
@ -599,9 +599,9 @@ describe('compiler: codegen', () => {
createRoot({
codegenNode: createAssignmentExpression(
createSimpleExpression(`foo`, false),
createSimpleExpression(`bar`, false)
)
})
createSimpleExpression(`bar`, false),
),
}),
)
expect(code).toMatchInlineSnapshot(`
"
@ -617,17 +617,17 @@ describe('compiler: codegen', () => {
function genCode(node: VNodeCall) {
return generate(
createRoot({
codegenNode: node
})
codegenNode: node,
}),
).code.match(/with \(_ctx\) \{\s+([^]+)\s+\}\s+\}$/)![1]
}
const mockProps = createObjectExpression([
createObjectProperty(`foo`, createSimpleExpression(`bar`, true))
createObjectProperty(`foo`, createSimpleExpression(`bar`, true)),
])
const mockChildren = createCompoundExpression(['children'])
const mockDirs = createArrayExpression([
createArrayExpression([`foo`, createSimpleExpression(`bar`, false)])
createArrayExpression([`foo`, createSimpleExpression(`bar`, false)]),
]) as DirectiveArguments
test('tag only', () => {
@ -684,9 +684,9 @@ describe('compiler: codegen', () => {
undefined,
undefined,
undefined,
true
)
)
true,
),
),
).toMatchInlineSnapshot(`
"return (_openBlock(), _createElementBlock("div", { foo: "bar" }, children))
"
@ -705,9 +705,9 @@ describe('compiler: codegen', () => {
undefined,
undefined,
true,
true
)
)
true,
),
),
).toMatchInlineSnapshot(`
"return (_openBlock(true), _createElementBlock("div", { foo: "bar" }, children))
"
@ -724,9 +724,9 @@ describe('compiler: codegen', () => {
mockChildren,
undefined,
undefined,
mockDirs
)
)
mockDirs,
),
),
).toMatchInlineSnapshot(`
"return _withDirectives(_createElementVNode("div", { foo: "bar" }, children), [
[foo, bar]
@ -746,9 +746,9 @@ describe('compiler: codegen', () => {
undefined,
undefined,
mockDirs,
true
)
)
true,
),
),
).toMatchInlineSnapshot(`
"return _withDirectives((_openBlock(), _createElementBlock("div", { foo: "bar" }, children)), [
[foo, bar]

View File

@ -1,5 +1,5 @@
import { baseCompile as compile } from '../src'
import { SourceMapConsumer, RawSourceMap } from 'source-map-js'
import { type RawSourceMap, SourceMapConsumer } from 'source-map-js'
describe('compiler: integration tests', () => {
const source = `
@ -20,7 +20,7 @@ describe('compiler: integration tests', () => {
function getPositionInCode(
code: string,
token: string,
expectName: string | boolean = false
expectName: string | boolean = false,
): Pos {
const generatedOffset = code.indexOf(token)
let line = 1
@ -36,7 +36,7 @@ describe('compiler: integration tests', () => {
column:
lastNewLinePos === -1
? generatedOffset
: generatedOffset - lastNewLinePos - 1
: generatedOffset - lastNewLinePos - 1,
}
if (expectName) {
res.name = typeof expectName === 'string' ? expectName : token
@ -47,7 +47,7 @@ describe('compiler: integration tests', () => {
test('function mode', () => {
const { code, map } = compile(source, {
sourceMap: true,
filename: `foo.vue`
filename: `foo.vue`,
})
expect(code).toMatchSnapshot()
@ -57,55 +57,55 @@ describe('compiler: integration tests', () => {
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(code, `id`))
consumer.originalPositionFor(getPositionInCode(code, `id`)),
).toMatchObject(getPositionInCode(source, `id`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
consumer.originalPositionFor(getPositionInCode(code, `"foo"`)),
).toMatchObject(getPositionInCode(source, `"foo"`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `class:`))
consumer.originalPositionFor(getPositionInCode(code, `class:`)),
).toMatchObject(getPositionInCode(source, `class=`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `bar`))
consumer.originalPositionFor(getPositionInCode(code, `bar`)),
).toMatchObject(getPositionInCode(source, `bar`))
// without prefixIdentifiers: true, identifiers inside compound expressions
// are mapped to closest parent expression.
expect(
consumer.originalPositionFor(getPositionInCode(code, `baz`))
consumer.originalPositionFor(getPositionInCode(code, `baz`)),
).toMatchObject(getPositionInCode(source, `bar`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `world`))
consumer.originalPositionFor(getPositionInCode(code, `world`)),
).toMatchObject(getPositionInCode(source, `world`))
// without prefixIdentifiers: true, identifiers inside compound expressions
// are mapped to closest parent expression.
expect(
consumer.originalPositionFor(getPositionInCode(code, `burn()`))
consumer.originalPositionFor(getPositionInCode(code, `burn()`)),
).toMatchObject(getPositionInCode(source, `world`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `ok`))
consumer.originalPositionFor(getPositionInCode(code, `ok`)),
).toMatchObject(getPositionInCode(source, `ok`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `list`))
consumer.originalPositionFor(getPositionInCode(code, `list`)),
).toMatchObject(getPositionInCode(source, `list`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `value`))
consumer.originalPositionFor(getPositionInCode(code, `value`)),
).toMatchObject(getPositionInCode(source, `value`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `index`))
consumer.originalPositionFor(getPositionInCode(code, `index`)),
).toMatchObject(getPositionInCode(source, `index`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `value + index`))
consumer.originalPositionFor(getPositionInCode(code, `value + index`)),
).toMatchObject(getPositionInCode(source, `value + index`))
})
@ -113,7 +113,7 @@ describe('compiler: integration tests', () => {
const { code, map } = compile(source, {
sourceMap: true,
filename: `foo.vue`,
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(code).toMatchSnapshot()
@ -123,64 +123,66 @@ describe('compiler: integration tests', () => {
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(code, `id`))
consumer.originalPositionFor(getPositionInCode(code, `id`)),
).toMatchObject(getPositionInCode(source, `id`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
consumer.originalPositionFor(getPositionInCode(code, `"foo"`)),
).toMatchObject(getPositionInCode(source, `"foo"`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `class:`))
consumer.originalPositionFor(getPositionInCode(code, `class:`)),
).toMatchObject(getPositionInCode(source, `class=`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `bar`))
consumer.originalPositionFor(getPositionInCode(code, `bar`)),
).toMatchObject(getPositionInCode(source, `bar`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`))
consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`)),
).toMatchObject(getPositionInCode(source, `bar`, true))
expect(
consumer.originalPositionFor(getPositionInCode(code, `baz`))
consumer.originalPositionFor(getPositionInCode(code, `baz`)),
).toMatchObject(getPositionInCode(source, `baz`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `world`, true))
consumer.originalPositionFor(getPositionInCode(code, `world`, true)),
).toMatchObject(getPositionInCode(source, `world`, `world`))
expect(
consumer.originalPositionFor(
getPositionInCode(code, `_ctx.world`, `world`)
)
getPositionInCode(code, `_ctx.world`, `world`),
),
).toMatchObject(getPositionInCode(source, `world`, `world`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `burn()`))
consumer.originalPositionFor(getPositionInCode(code, `burn()`)),
).toMatchObject(getPositionInCode(source, `burn()`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `ok`))
consumer.originalPositionFor(getPositionInCode(code, `ok`)),
).toMatchObject(getPositionInCode(source, `ok`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`))
consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`)),
).toMatchObject(getPositionInCode(source, `ok`, true))
expect(
consumer.originalPositionFor(getPositionInCode(code, `list`))
consumer.originalPositionFor(getPositionInCode(code, `list`)),
).toMatchObject(getPositionInCode(source, `list`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `_ctx.list`, `list`))
consumer.originalPositionFor(
getPositionInCode(code, `_ctx.list`, `list`),
),
).toMatchObject(getPositionInCode(source, `list`, true))
expect(
consumer.originalPositionFor(getPositionInCode(code, `value`))
consumer.originalPositionFor(getPositionInCode(code, `value`)),
).toMatchObject(getPositionInCode(source, `value`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `index`))
consumer.originalPositionFor(getPositionInCode(code, `index`)),
).toMatchObject(getPositionInCode(source, `index`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `value + index`))
consumer.originalPositionFor(getPositionInCode(code, `value + index`)),
).toMatchObject(getPositionInCode(source, `value + index`))
})
@ -188,7 +190,7 @@ describe('compiler: integration tests', () => {
const { code, map } = compile(source, {
mode: 'module',
sourceMap: true,
filename: `foo.vue`
filename: `foo.vue`,
})
expect(code).toMatchSnapshot()
@ -198,64 +200,66 @@ describe('compiler: integration tests', () => {
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(code, `id`))
consumer.originalPositionFor(getPositionInCode(code, `id`)),
).toMatchObject(getPositionInCode(source, `id`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
consumer.originalPositionFor(getPositionInCode(code, `"foo"`)),
).toMatchObject(getPositionInCode(source, `"foo"`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `class:`))
consumer.originalPositionFor(getPositionInCode(code, `class:`)),
).toMatchObject(getPositionInCode(source, `class=`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `bar`))
consumer.originalPositionFor(getPositionInCode(code, `bar`)),
).toMatchObject(getPositionInCode(source, `bar`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`))
consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`)),
).toMatchObject(getPositionInCode(source, `bar`, true))
expect(
consumer.originalPositionFor(getPositionInCode(code, `baz`))
consumer.originalPositionFor(getPositionInCode(code, `baz`)),
).toMatchObject(getPositionInCode(source, `baz`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `world`, true))
consumer.originalPositionFor(getPositionInCode(code, `world`, true)),
).toMatchObject(getPositionInCode(source, `world`, `world`))
expect(
consumer.originalPositionFor(
getPositionInCode(code, `_ctx.world`, `world`)
)
getPositionInCode(code, `_ctx.world`, `world`),
),
).toMatchObject(getPositionInCode(source, `world`, `world`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `burn()`))
consumer.originalPositionFor(getPositionInCode(code, `burn()`)),
).toMatchObject(getPositionInCode(source, `burn()`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `ok`))
consumer.originalPositionFor(getPositionInCode(code, `ok`)),
).toMatchObject(getPositionInCode(source, `ok`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`))
consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`)),
).toMatchObject(getPositionInCode(source, `ok`, true))
expect(
consumer.originalPositionFor(getPositionInCode(code, `list`))
consumer.originalPositionFor(getPositionInCode(code, `list`)),
).toMatchObject(getPositionInCode(source, `list`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `_ctx.list`, `list`))
consumer.originalPositionFor(
getPositionInCode(code, `_ctx.list`, `list`),
),
).toMatchObject(getPositionInCode(source, `list`, true))
expect(
consumer.originalPositionFor(getPositionInCode(code, `value`))
consumer.originalPositionFor(getPositionInCode(code, `value`)),
).toMatchObject(getPositionInCode(source, `value`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `index`))
consumer.originalPositionFor(getPositionInCode(code, `index`)),
).toMatchObject(getPositionInCode(source, `index`))
expect(
consumer.originalPositionFor(getPositionInCode(code, `value + index`))
consumer.originalPositionFor(getPositionInCode(code, `value + index`)),
).toMatchObject(getPositionInCode(source, `value + index`))
})
})

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import { baseCompile } from '../src/compile'
import { PUSH_SCOPE_ID, POP_SCOPE_ID } from '../src/runtimeHelpers'
import { POP_SCOPE_ID, PUSH_SCOPE_ID } from '../src/runtimeHelpers'
import { PatchFlags } from '@vue/shared'
import { genFlagText } from './testUtils'
@ -18,7 +18,7 @@ describe('scopeId compiler support', () => {
test('should wrap default slot', () => {
const { code } = baseCompile(`<Child><div/></Child>`, {
mode: 'module',
scopeId: 'test'
scopeId: 'test',
})
expect(code).toMatch(`default: _withCtx(() => [`)
expect(code).toMatchSnapshot()
@ -33,8 +33,8 @@ describe('scopeId compiler support', () => {
`,
{
mode: 'module',
scopeId: 'test'
}
scopeId: 'test',
},
)
expect(code).toMatch(`foo: _withCtx(({ msg }) => [`)
expect(code).toMatch(`bar: _withCtx(() => [`)
@ -50,8 +50,8 @@ describe('scopeId compiler support', () => {
`,
{
mode: 'module',
scopeId: 'test'
}
scopeId: 'test',
},
)
expect(code).toMatch(/name: "foo",\s+fn: _withCtx\(/)
expect(code).toMatch(/name: i,\s+fn: _withCtx\(/)
@ -64,8 +64,8 @@ describe('scopeId compiler support', () => {
{
mode: 'module',
scopeId: 'test',
hoistStatic: true
}
hoistStatic: true,
},
)
expect(ast.helpers).toContain(PUSH_SCOPE_ID)
expect(ast.helpers).toContain(POP_SCOPE_ID)
@ -73,11 +73,11 @@ describe('scopeId compiler support', () => {
;[
`const _withScopeId = n => (_pushScopeId("test"),n=n(),_popScopeId(),n)`,
`const _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", ${genFlagText(
PatchFlags.HOISTED
PatchFlags.HOISTED,
)}))`,
`const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", ${genFlagText(
PatchFlags.HOISTED
)}))`
PatchFlags.HOISTED,
)}))`,
].forEach(c => expect(code).toMatch(c))
expect(code).toMatchSnapshot()
})

View File

@ -1,17 +1,17 @@
import {
NodeTypes,
ElementNode,
locStub,
Namespaces,
type ElementNode,
ElementTypes,
VNodeCall
Namespaces,
NodeTypes,
type VNodeCall,
locStub,
} from '../src'
import {
isString,
PatchFlags,
PatchFlagNames,
type PatchFlags,
type ShapeFlags,
isArray,
ShapeFlags
isString,
} from '@vue/shared'
const leadingBracketRE = /^\[/
@ -30,16 +30,16 @@ export function createObjectMatcher(obj: Record<string, any>) {
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: key.replace(bracketsRE, ''),
isStatic: !leadingBracketRE.test(key)
isStatic: !leadingBracketRE.test(key),
},
value: isString(obj[key])
? {
type: NodeTypes.SIMPLE_EXPRESSION,
content: obj[key].replace(bracketsRE, ''),
isStatic: !leadingBracketRE.test(obj[key])
isStatic: !leadingBracketRE.test(obj[key]),
}
: obj[key]
}))
: obj[key],
})),
}
}
@ -48,7 +48,7 @@ export function createElementWithCodegen(
props?: VNodeCall['props'],
children?: VNodeCall['children'],
patchFlag?: VNodeCall['patchFlag'],
dynamicProps?: VNodeCall['dynamicProps']
dynamicProps?: VNodeCall['dynamicProps'],
): ElementNode {
return {
type: NodeTypes.ELEMENT,
@ -69,15 +69,15 @@ export function createElementWithCodegen(
isBlock: false,
disableTracking: false,
isComponent: false,
loc: locStub
}
loc: locStub,
},
}
}
type Flags = PatchFlags | ShapeFlags
export function genFlagText(
flag: Flags | Flags[],
names: { [k: number]: string } = PatchFlagNames
names: { [k: number]: string } = PatchFlagNames,
) {
if (isArray(flag)) {
let f = 0

View File

@ -1,18 +1,18 @@
import { baseParse } from '../src/parser'
import { transform, NodeTransform } from '../src/transform'
import { type NodeTransform, transform } from '../src/transform'
import {
ElementNode,
type DirectiveNode,
type ElementNode,
type ExpressionNode,
NodeTypes,
DirectiveNode,
ExpressionNode,
VNodeCall
type VNodeCall,
} from '../src/ast'
import { ErrorCodes, createCompilerError } from '../src/errors'
import {
TO_DISPLAY_STRING,
CREATE_COMMENT,
FRAGMENT,
RENDER_SLOT,
CREATE_COMMENT
TO_DISPLAY_STRING,
} from '../src/runtimeHelpers'
import { transformIf } from '../src/transforms/vIf'
import { transformFor } from '../src/transforms/vFor'
@ -34,7 +34,7 @@ describe('compiler: transform', () => {
}
transform(ast, {
nodeTransforms: [plugin]
nodeTransforms: [plugin],
})
const div = ast.children[0] as ElementNode
@ -43,29 +43,29 @@ describe('compiler: transform', () => {
ast,
{
parent: null,
currentNode: ast
}
currentNode: ast,
},
])
expect(calls[1]).toMatchObject([
div,
{
parent: ast,
currentNode: div
}
currentNode: div,
},
])
expect(calls[2]).toMatchObject([
div.children[0],
{
parent: div,
currentNode: div.children[0]
}
currentNode: div.children[0],
},
])
expect(calls[3]).toMatchObject([
div.children[1],
{
parent: div,
currentNode: div.children[1]
}
currentNode: div.children[1],
},
])
})
@ -81,16 +81,16 @@ describe('compiler: transform', () => {
{
type: NodeTypes.TEXT,
content: 'hello',
isEmpty: false
}
]
})
isEmpty: false,
},
],
}),
)
}
}
const spy = vi.fn(plugin)
transform(ast, {
nodeTransforms: [spy]
nodeTransforms: [spy],
})
expect(ast.children.length).toBe(2)
@ -115,7 +115,7 @@ describe('compiler: transform', () => {
}
const spy = vi.fn(plugin)
transform(ast, {
nodeTransforms: [spy]
nodeTransforms: [spy],
})
expect(ast.children.length).toBe(2)
@ -143,7 +143,7 @@ describe('compiler: transform', () => {
}
const spy = vi.fn(plugin)
transform(ast, {
nodeTransforms: [spy]
nodeTransforms: [spy],
})
expect(ast.children.length).toBe(1)
@ -170,7 +170,7 @@ describe('compiler: transform', () => {
}
const spy = vi.fn(plugin)
transform(ast, {
nodeTransforms: [spy]
nodeTransforms: [spy],
})
expect(ast.children.length).toBe(1)
@ -194,7 +194,7 @@ describe('compiler: transform', () => {
}
}
transform(ast, {
nodeTransforms: [mock]
nodeTransforms: [mock],
})
expect(ast.hoists).toMatchObject(hoisted)
expect((ast as any).children[0].props[0].exp.content).toBe(`_hoisted_1`)
@ -211,13 +211,13 @@ describe('compiler: transform', () => {
transform(ast, {
filename: '/the/fileName.vue',
nodeTransforms: [plugin]
nodeTransforms: [plugin],
})
expect(calls.length).toBe(2)
expect(calls[1]).toMatchObject({
filename: '/the/fileName.vue',
selfName: 'FileName'
selfName: 'FileName',
})
})
@ -226,19 +226,19 @@ describe('compiler: transform', () => {
const loc = ast.children[0].loc
const plugin: NodeTransform = (node, context) => {
context.onError(
createCompilerError(ErrorCodes.X_INVALID_END_TAG, node.loc)
createCompilerError(ErrorCodes.X_INVALID_END_TAG, node.loc),
)
}
const spy = vi.fn()
transform(ast, {
nodeTransforms: [plugin],
onError: spy
onError: spy,
})
expect(spy.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_INVALID_END_TAG,
loc
}
loc,
},
])
})
@ -263,8 +263,8 @@ describe('compiler: transform', () => {
transformFor,
transformText,
transformSlotOutlet,
transformElement
]
transformElement,
],
})
return ast
}
@ -273,7 +273,7 @@ describe('compiler: transform', () => {
tag: VNodeCall['tag'],
props?: VNodeCall['props'],
children?: VNodeCall['children'],
patchFlag?: VNodeCall['patchFlag']
patchFlag?: VNodeCall['patchFlag'],
) {
return {
type: NodeTypes.VNODE_CALL,
@ -281,7 +281,7 @@ describe('compiler: transform', () => {
tag,
props,
children,
patchFlag
patchFlag,
}
}
@ -295,8 +295,8 @@ describe('compiler: transform', () => {
expect(ast.codegenNode).toMatchObject({
codegenNode: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT
}
callee: RENDER_SLOT,
},
})
})
@ -308,14 +308,14 @@ describe('compiler: transform', () => {
test('root v-if', () => {
const ast = transformWithCodegen(`<div v-if="ok" />`)
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.IF
type: NodeTypes.IF,
})
})
test('root v-for', () => {
const ast = transformWithCodegen(`<div v-for="i in list" />`)
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.FOR
type: NodeTypes.FOR,
})
})
@ -323,28 +323,28 @@ describe('compiler: transform', () => {
const ast = transformWithCodegen(`<div v-foo/>`)
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.VNODE_CALL,
directives: { type: NodeTypes.JS_ARRAY_EXPRESSION }
directives: { type: NodeTypes.JS_ARRAY_EXPRESSION },
})
})
test('single text', () => {
const ast = transformWithCodegen(`hello`)
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.TEXT
type: NodeTypes.TEXT,
})
})
test('single interpolation', () => {
const ast = transformWithCodegen(`{{ foo }}`)
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.INTERPOLATION
type: NodeTypes.INTERPOLATION,
})
})
test('single CompoundExpression', () => {
const ast = transformWithCodegen(`{{ foo }} bar baz`)
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION
type: NodeTypes.COMPOUND_EXPRESSION,
})
})
@ -356,10 +356,10 @@ describe('compiler: transform', () => {
undefined,
[
{ type: NodeTypes.ELEMENT, tag: `div` },
{ type: NodeTypes.ELEMENT, tag: `div` }
{ type: NodeTypes.ELEMENT, tag: `div` },
] as any,
genFlagText(PatchFlags.STABLE_FRAGMENT)
)
genFlagText(PatchFlags.STABLE_FRAGMENT),
),
)
})
@ -372,13 +372,13 @@ describe('compiler: transform', () => {
[
{ type: NodeTypes.COMMENT },
{ type: NodeTypes.ELEMENT, tag: `div` },
{ type: NodeTypes.COMMENT }
{ type: NodeTypes.COMMENT },
] as any,
genFlagText([
PatchFlags.STABLE_FRAGMENT,
PatchFlags.DEV_ROOT_FRAGMENT
])
)
PatchFlags.DEV_ROOT_FRAGMENT,
]),
),
)
})
})

View File

@ -1,19 +1,19 @@
import {
type CompilerOptions,
ConstantTypes,
type ElementNode,
type ForNode,
type IfNode,
NodeTypes,
type VNodeCall,
generate,
baseParse as parse,
transform,
NodeTypes,
generate,
CompilerOptions,
VNodeCall,
IfNode,
ElementNode,
ForNode,
ConstantTypes
} from '../../src'
import {
FRAGMENT,
NORMALIZE_CLASS,
RENDER_LIST,
NORMALIZE_CLASS
} from '../../src/runtimeHelpers'
import { transformElement } from '../../src/transforms/transformElement'
import { transformExpression } from '../../src/transforms/transformExpression'
@ -31,9 +31,9 @@ const hoistedChildrenArrayMatcher = (startIndex = 1, length = 1) => ({
type: NodeTypes.ELEMENT,
codegenNode: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_${startIndex + i}`
}
}))
content: `_hoisted_${startIndex + i}`,
},
})),
})
function transformWithHoist(template: string, options: CompilerOptions = {}) {
@ -45,17 +45,17 @@ function transformWithHoist(template: string, options: CompilerOptions = {}) {
transformFor,
...(options.prefixIdentifiers ? [transformExpression] : []),
transformElement,
transformText
transformText,
],
directiveTransforms: {
on: transformOn,
bind: transformBind
bind: transformBind,
},
...options
...options,
})
expect(ast.codegenNode).toMatchObject({
type: NodeTypes.VNODE_CALL,
isBlock: true
isBlock: true,
})
return ast
}
@ -67,14 +67,14 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(`<div/>`)
expect(root.hoists.length).toBe(0)
expect(root.codegenNode).toMatchObject({
tag: `"div"`
tag: `"div"`,
})
expect(generate(root).code).toMatchSnapshot()
})
test('hoist simple element', () => {
const root = transformWithHoist(
`<div><span class="inline">hello</span></div>`
`<div><span class="inline">hello</span></div>`,
)
expect(root.hoists).toMatchObject([
{
@ -83,15 +83,15 @@ describe('compiler: hoistStatic transform', () => {
props: createObjectMatcher({ class: 'inline' }),
children: {
type: NodeTypes.TEXT,
content: `hello`
}
content: `hello`,
},
},
hoistedChildrenArrayMatcher()
hoistedChildrenArrayMatcher(),
])
expect(root.codegenNode).toMatchObject({
tag: `"div"`,
props: undefined,
children: { content: `_hoisted_2` }
children: { content: `_hoisted_2` },
})
expect(generate(root).code).toMatchSnapshot()
})
@ -105,13 +105,13 @@ describe('compiler: hoistStatic transform', () => {
props: undefined,
children: [
{ type: NodeTypes.ELEMENT, tag: `span` },
{ type: NodeTypes.ELEMENT, tag: `span` }
]
{ type: NodeTypes.ELEMENT, tag: `span` },
],
},
hoistedChildrenArrayMatcher()
hoistedChildrenArrayMatcher(),
])
expect((root.codegenNode as VNodeCall).children).toMatchObject({
content: '_hoisted_2'
content: '_hoisted_2',
})
expect(generate(root).code).toMatchSnapshot()
})
@ -123,12 +123,12 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: undefined,
children: [{ type: NodeTypes.COMMENT, content: `comment` }]
children: [{ type: NodeTypes.COMMENT, content: `comment` }],
},
hoistedChildrenArrayMatcher()
hoistedChildrenArrayMatcher(),
])
expect((root.codegenNode as VNodeCall).children).toMatchObject({
content: `_hoisted_2`
content: `_hoisted_2`,
})
expect(generate(root).code).toMatchSnapshot()
})
@ -138,16 +138,16 @@ describe('compiler: hoistStatic transform', () => {
expect(root.hoists).toMatchObject([
{
type: NodeTypes.VNODE_CALL,
tag: `"span"`
tag: `"span"`,
},
{
type: NodeTypes.VNODE_CALL,
tag: `"div"`
tag: `"div"`,
},
hoistedChildrenArrayMatcher(1, 2)
hoistedChildrenArrayMatcher(1, 2),
])
expect((root.codegenNode as VNodeCall).children).toMatchObject({
content: '_hoisted_3'
content: '_hoisted_3',
})
expect(generate(root).code).toMatchSnapshot()
})
@ -160,9 +160,9 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.ELEMENT,
codegenNode: {
type: NodeTypes.VNODE_CALL,
tag: `_component_Comp`
}
}
tag: `_component_Comp`,
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
@ -177,17 +177,17 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: createObjectMatcher({
id: `[foo]`
id: `[foo]`,
}),
children: undefined,
patchFlag: genFlagText(PatchFlags.PROPS),
dynamicProps: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_1`,
isStatic: false
}
}
}
isStatic: false,
},
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
@ -199,14 +199,14 @@ describe('compiler: hoistStatic transform', () => {
{
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: createObjectMatcher({ key: 'foo' })
props: createObjectMatcher({ key: 'foo' }),
},
hoistedChildrenArrayMatcher()
hoistedChildrenArrayMatcher(),
])
expect(root.codegenNode).toMatchObject({
tag: `"div"`,
props: undefined,
children: { content: `_hoisted_2` }
children: { content: `_hoisted_2` },
})
expect(generate(root).code).toMatchSnapshot()
})
@ -221,10 +221,10 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: createObjectMatcher({
key: `[foo]`
})
}
}
key: `[foo]`,
}),
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
@ -239,12 +239,12 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: createObjectMatcher({
ref: `[foo]`
ref: `[foo]`,
}),
children: undefined,
patchFlag: genFlagText(PatchFlags.NEED_PATCH)
}
}
patchFlag: genFlagText(PatchFlags.NEED_PATCH),
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
@ -260,22 +260,22 @@ describe('compiler: hoistStatic transform', () => {
tag: `"div"`,
props: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_1`
content: `_hoisted_1`,
},
children: undefined,
patchFlag: genFlagText(PatchFlags.NEED_PATCH),
directives: {
type: NodeTypes.JS_ARRAY_EXPRESSION
}
}
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
test('hoist static props for elements with dynamic text children', () => {
const root = transformWithHoist(
`<div><div id="foo">{{ hello }}</div></div>`
`<div><div id="foo">{{ hello }}</div></div>`,
)
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
expect((root.codegenNode as VNodeCall).children).toMatchObject([
@ -286,9 +286,9 @@ describe('compiler: hoistStatic transform', () => {
tag: `"div"`,
props: { content: `_hoisted_1` },
children: { type: NodeTypes.INTERPOLATION },
patchFlag: genFlagText(PatchFlags.TEXT)
}
}
patchFlag: genFlagText(PatchFlags.TEXT),
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
@ -303,30 +303,30 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: { content: `_hoisted_1` },
children: [{ type: NodeTypes.ELEMENT, tag: `Comp` }]
}
}
children: [{ type: NodeTypes.ELEMENT, tag: `Comp` }],
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
test('should hoist v-if props/children if static', () => {
const root = transformWithHoist(
`<div><div v-if="ok" id="foo"><span/></div></div>`
`<div><div v-if="ok" id="foo"><span/></div></div>`,
)
expect(root.hoists).toMatchObject([
createObjectMatcher({
key: `[0]`, // key injected by v-if branch
id: 'foo'
id: 'foo',
}),
{
type: NodeTypes.VNODE_CALL,
tag: `"span"`
tag: `"span"`,
},
hoistedChildrenArrayMatcher(2)
hoistedChildrenArrayMatcher(2),
])
expect(
((root.children[0] as ElementNode).children[0] as IfNode).codegenNode
((root.children[0] as ElementNode).children[0] as IfNode).codegenNode,
).toMatchObject({
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
consequent: {
@ -334,25 +334,25 @@ describe('compiler: hoistStatic transform', () => {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: { content: `_hoisted_1` },
children: { content: `_hoisted_3` }
}
children: { content: `_hoisted_3` },
},
})
expect(generate(root).code).toMatchSnapshot()
})
test('should hoist v-for children if static', () => {
const root = transformWithHoist(
`<div><div v-for="i in list" id="foo"><span/></div></div>`
`<div><div v-for="i in list" id="foo"><span/></div></div>`,
)
expect(root.hoists).toMatchObject([
createObjectMatcher({
id: 'foo'
id: 'foo',
}),
{
type: NodeTypes.VNODE_CALL,
tag: `"span"`
tag: `"span"`,
},
hoistedChildrenArrayMatcher(2)
hoistedChildrenArrayMatcher(2),
])
const forBlockCodegen = (
(root.children[0] as ElementNode).children[0] as ForNode
@ -363,16 +363,16 @@ describe('compiler: hoistStatic transform', () => {
props: undefined,
children: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_LIST
callee: RENDER_LIST,
},
patchFlag: genFlagText(PatchFlags.UNKEYED_FRAGMENT)
patchFlag: genFlagText(PatchFlags.UNKEYED_FRAGMENT),
})
const innerBlockCodegen = forBlockCodegen!.children.arguments[1]
expect(innerBlockCodegen.returns).toMatchObject({
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: { content: `_hoisted_1` },
children: { content: `_hoisted_3` }
children: { content: `_hoisted_3` },
})
expect(generate(root).code).toMatchSnapshot()
})
@ -382,8 +382,8 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(
`<div><span>foo {{ 1 }} {{ true }}</span></div>`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(root.hoists).toMatchObject([
{
@ -391,18 +391,18 @@ describe('compiler: hoistStatic transform', () => {
tag: `"span"`,
props: undefined,
children: {
type: NodeTypes.COMPOUND_EXPRESSION
}
type: NodeTypes.COMPOUND_EXPRESSION,
},
},
hoistedChildrenArrayMatcher()
hoistedChildrenArrayMatcher(),
])
expect(root.codegenNode).toMatchObject({
tag: `"div"`,
props: undefined,
children: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_2`
}
content: `_hoisted_2`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -411,8 +411,8 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(
`<div><span :foo="0">{{ 1 }}</span></div>`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(root.hoists).toMatchObject([
@ -425,19 +425,19 @@ describe('compiler: hoistStatic transform', () => {
content: {
content: `1`,
isStatic: false,
constType: ConstantTypes.CAN_STRINGIFY
}
}
constType: ConstantTypes.CAN_STRINGIFY,
},
},
},
hoistedChildrenArrayMatcher()
hoistedChildrenArrayMatcher(),
])
expect(root.codegenNode).toMatchObject({
tag: `"div"`,
props: undefined,
children: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_2`
}
content: `_hoisted_2`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -446,8 +446,8 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(
`<div><span :class="{ foo: true }">{{ bar }}</span></div>`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(root.hoists).toMatchObject([
@ -458,7 +458,7 @@ describe('compiler: hoistStatic transform', () => {
key: {
content: `class`,
isStatic: true,
constType: ConstantTypes.CAN_STRINGIFY
constType: ConstantTypes.CAN_STRINGIFY,
},
value: {
type: NodeTypes.JS_CALL_EXPRESSION,
@ -467,13 +467,13 @@ describe('compiler: hoistStatic transform', () => {
{
content: `{ foo: true }`,
isStatic: false,
constType: ConstantTypes.CAN_STRINGIFY
}
]
}
}
]
}
constType: ConstantTypes.CAN_STRINGIFY,
},
],
},
},
],
},
])
expect(root.codegenNode).toMatchObject({
tag: `"div"`,
@ -486,20 +486,20 @@ describe('compiler: hoistStatic transform', () => {
tag: `"span"`,
props: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_1`
content: `_hoisted_1`,
},
children: {
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`,
isStatic: false,
constType: ConstantTypes.NOT_CONSTANT
}
constType: ConstantTypes.NOT_CONSTANT,
},
},
patchFlag: `1 /* TEXT */`
}
}
]
patchFlag: `1 /* TEXT */`,
},
},
],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -508,8 +508,8 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(
`<div><p v-for="o in list"><span>{{ o }}</span></p></div>`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(root.hoists.length).toBe(0)
@ -520,8 +520,8 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(
`<div><p v-for="o in list"><span>{{ o + 'foo' }}</span></p></div>`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(root.hoists.length).toBe(0)
@ -532,8 +532,8 @@ describe('compiler: hoistStatic transform', () => {
const root = transformWithHoist(
`<Comp v-slot="{ foo }">{{ foo }}</Comp>`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
expect(root.hoists.length).toBe(0)
@ -545,8 +545,8 @@ describe('compiler: hoistStatic transform', () => {
`<div><div><div @click="foo"/></div></div>`,
{
prefixIdentifiers: true,
cacheHandlers: true
}
cacheHandlers: true,
},
)
expect(root.cached).toBe(1)
@ -554,8 +554,8 @@ describe('compiler: hoistStatic transform', () => {
expect(
generate(root, {
mode: 'module',
prefixIdentifiers: true
}).code
prefixIdentifiers: true,
}).code,
).toMatchSnapshot()
})
@ -564,8 +564,8 @@ describe('compiler: hoistStatic transform', () => {
`<div><div><div :class="{}" @click="foo"/></div></div>`,
{
prefixIdentifiers: true,
cacheHandlers: true
}
cacheHandlers: true,
},
)
expect(root.cached).toBe(1)
@ -573,14 +573,14 @@ describe('compiler: hoistStatic transform', () => {
expect(
generate(root, {
mode: 'module',
prefixIdentifiers: true
}).code
prefixIdentifiers: true,
}).code,
).toMatchSnapshot()
})
test('should NOT hoist keyed template v-for with plain element child', () => {
const root = transformWithHoist(
`<div><template v-for="item in items" :key="item"><span/></template></div>`
`<div><template v-for="item in items" :key="item"><span/></template></div>`,
)
expect(root.hoists.length).toBe(0)
expect(generate(root).code).toMatchSnapshot()
@ -588,7 +588,7 @@ describe('compiler: hoistStatic transform', () => {
test('should NOT hoist SVG with directives', () => {
const root = transformWithHoist(
`<div><svg v-foo><path d="M2,3H5.5L12"/></svg></div>`
`<div><svg v-foo><path d="M2,3H5.5L12"/></svg></div>`,
)
expect(root.hoists.length).toBe(2)
expect(generate(root).code).toMatchSnapshot()
@ -596,13 +596,13 @@ describe('compiler: hoistStatic transform', () => {
test('clone hoisted array children in HMR mode', () => {
const root = transformWithHoist(`<div><span class="hi"></span></div>`, {
hmr: true
hmr: true,
})
expect(root.hoists.length).toBe(2)
expect(root.codegenNode).toMatchObject({
children: {
content: '[..._hoisted_2]'
}
content: '[..._hoisted_2]',
},
})
})
})

View File

@ -1,9 +1,9 @@
import {
type ElementNode,
type VNodeCall,
noopDirectiveTransform,
baseParse as parse,
transform,
ElementNode,
noopDirectiveTransform,
VNodeCall
} from '../../src'
import { transformElement } from '../../src/transforms/transformElement'
@ -13,8 +13,8 @@ describe('compiler: noop directive transform', () => {
transform(ast, {
nodeTransforms: [transformElement],
directiveTransforms: {
noop: noopDirectiveTransform
}
noop: noopDirectiveTransform,
},
})
const node = ast.children[0] as ElementNode
// As v-noop adds no properties the codegen should be identical to

View File

@ -1,14 +1,14 @@
import {
BindingTypes,
type CompilerOptions,
ConstantTypes,
type DirectiveNode,
type ElementNode,
type InterpolationNode,
NodeTypes,
baseCompile,
baseParse as parse,
transform,
ElementNode,
DirectiveNode,
NodeTypes,
CompilerOptions,
InterpolationNode,
ConstantTypes,
BindingTypes,
baseCompile
} from '../../src'
import { transformIf } from '../../src/transforms/vIf'
import { transformExpression } from '../../src/transforms/transformExpression'
@ -16,13 +16,13 @@ import { PatchFlagNames, PatchFlags } from '../../../shared/src'
function parseWithExpressionTransform(
template: string,
options: CompilerOptions = {}
options: CompilerOptions = {},
) {
const ast = parse(template, options)
transform(ast, {
prefixIdentifiers: true,
nodeTransforms: [transformIf, transformExpression],
...options
...options,
})
return ast.children[0]
}
@ -32,7 +32,7 @@ describe('compiler: expression transform', () => {
const node = parseWithExpressionTransform(`{{ foo }}`) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.foo`
content: `_ctx.foo`,
})
})
@ -40,34 +40,34 @@ describe('compiler: expression transform', () => {
const node = parseWithExpressionTransform(`{{}}`) as InterpolationNode
const node2 = parseWithExpressionTransform(`{{ }}`) as InterpolationNode
const node3 = parseWithExpressionTransform(
`<div>{{ }}</div>`
`<div>{{ }}</div>`,
) as ElementNode
const objectToBeMatched = {
type: NodeTypes.SIMPLE_EXPRESSION,
content: ``
content: ``,
}
expect(node.content).toMatchObject(objectToBeMatched)
expect(node2.content).toMatchObject(objectToBeMatched)
expect((node3.children[0] as InterpolationNode).content).toMatchObject(
objectToBeMatched
objectToBeMatched,
)
})
test('interpolation (children)', () => {
const el = parseWithExpressionTransform(
`<div>{{ foo }}</div>`
`<div>{{ foo }}</div>`,
) as ElementNode
const node = el.children[0] as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.foo`
content: `_ctx.foo`,
})
})
test('interpolation (complex)', () => {
const el = parseWithExpressionTransform(
`<div>{{ foo + bar(baz.qux) }}</div>`
`<div>{{ foo + bar(baz.qux) }}</div>`,
) as ElementNode
const node = el.children[0] as InterpolationNode
expect(node.content).toMatchObject({
@ -80,46 +80,46 @@ describe('compiler: expression transform', () => {
{ content: `_ctx.baz` },
`.`,
{ content: `qux` },
`)`
]
`)`,
],
})
})
test('directive value', () => {
const node = parseWithExpressionTransform(
`<div v-foo:arg="baz"/>`
`<div v-foo:arg="baz"/>`,
) as ElementNode
const arg = (node.props[0] as DirectiveNode).arg!
expect(arg).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `arg`
content: `arg`,
})
const exp = (node.props[0] as DirectiveNode).exp!
expect(exp).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.baz`
content: `_ctx.baz`,
})
})
test('dynamic directive arg', () => {
const node = parseWithExpressionTransform(
`<div v-foo:[arg]="baz"/>`
`<div v-foo:[arg]="baz"/>`,
) as ElementNode
const arg = (node.props[0] as DirectiveNode).arg!
expect(arg).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.arg`
content: `_ctx.arg`,
})
const exp = (node.props[0] as DirectiveNode).exp!
expect(exp).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.baz`
content: `_ctx.baz`,
})
})
test('should prefix complex expressions', () => {
const node = parseWithExpressionTransform(
`{{ foo(baz + 1, { key: kuz }) }}`
`{{ foo(baz + 1, { key: kuz }) }}`,
) as InterpolationNode
// should parse into compound expression
expect(node.content).toMatchObject({
@ -129,56 +129,56 @@ describe('compiler: expression transform', () => {
content: `_ctx.foo`,
loc: {
start: { offset: 3, line: 1, column: 4 },
end: { offset: 6, line: 1, column: 7 }
}
end: { offset: 6, line: 1, column: 7 },
},
},
`(`,
{
content: `_ctx.baz`,
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 10, line: 1, column: 11 }
}
end: { offset: 10, line: 1, column: 11 },
},
},
` + 1, { key: `,
{
content: `_ctx.kuz`,
loc: {
start: { offset: 23, line: 1, column: 24 },
end: { offset: 26, line: 1, column: 27 }
}
end: { offset: 26, line: 1, column: 27 },
},
},
` })`
]
` })`,
],
})
})
test('should not prefix whitelisted globals', () => {
const node = parseWithExpressionTransform(
`{{ Math.max(1, 2) }}`
`{{ Math.max(1, 2) }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: `Math` }, `.`, { content: `max` }, `(1, 2)`]
children: [{ content: `Math` }, `.`, { content: `max` }, `(1, 2)`],
})
expect(
(parseWithExpressionTransform(`{{ new Error() }}`) as InterpolationNode)
.content
.content,
).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: ['new ', { content: 'Error' }, '()']
children: ['new ', { content: 'Error' }, '()'],
})
})
test('should not prefix reserved literals', () => {
function assert(exp: string) {
const node = parseWithExpressionTransform(
`{{ ${exp} }}`
`{{ ${exp} }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: exp
content: exp,
})
}
assert(`true`)
@ -189,7 +189,7 @@ describe('compiler: expression transform', () => {
test('should not prefix id of a function declaration', () => {
const node = parseWithExpressionTransform(
`{{ function foo() { return bar } }}`
`{{ function foo() { return bar } }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -198,14 +198,14 @@ describe('compiler: expression transform', () => {
{ content: `foo` },
`() { return `,
{ content: `_ctx.bar` },
` }`
]
` }`,
],
})
})
test('should not prefix params of a function expression', () => {
const node = parseWithExpressionTransform(
`{{ foo => foo + bar }}`
`{{ foo => foo + bar }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -214,14 +214,14 @@ describe('compiler: expression transform', () => {
` => `,
{ content: `foo` },
` + `,
{ content: `_ctx.bar` }
]
{ content: `_ctx.bar` },
],
})
})
test('should prefix default value of a function expression param', () => {
const node = parseWithExpressionTransform(
`{{ (foo = baz) => foo + bar }}`
`{{ (foo = baz) => foo + bar }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -233,14 +233,14 @@ describe('compiler: expression transform', () => {
`) => `,
{ content: `foo` },
` + `,
{ content: `_ctx.bar` }
]
{ content: `_ctx.bar` },
],
})
})
test('should not prefix function param destructuring', () => {
const node = parseWithExpressionTransform(
`{{ ({ foo }) => foo + bar }}`
`{{ ({ foo }) => foo + bar }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -250,14 +250,14 @@ describe('compiler: expression transform', () => {
` }) => `,
{ content: `foo` },
` + `,
{ content: `_ctx.bar` }
]
{ content: `_ctx.bar` },
],
})
})
test('function params should not affect out of scope identifiers', () => {
const node = parseWithExpressionTransform(
`{{ { a: foo => foo, b: foo } }}`
`{{ { a: foo => foo, b: foo } }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -268,14 +268,14 @@ describe('compiler: expression transform', () => {
{ content: `foo` },
`, b: `,
{ content: `_ctx.foo` },
` }`
]
` }`,
],
})
})
test('should prefix default value of function param destructuring', () => {
const node = parseWithExpressionTransform(
`{{ ({ foo = bar }) => foo + bar }}`
`{{ ({ foo = bar }) => foo + bar }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -287,13 +287,13 @@ describe('compiler: expression transform', () => {
` }) => `,
{ content: `foo` },
` + `,
{ content: `_ctx.bar` }
]
{ content: `_ctx.bar` },
],
})
})
test('should not prefix an object property key', () => {
const node = parseWithExpressionTransform(
`{{ { foo() { baz() }, value: bar } }}`
`{{ { foo() { baz() }, value: bar } }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -302,24 +302,24 @@ describe('compiler: expression transform', () => {
{ content: `_ctx.baz` },
`() }, value: `,
{ content: `_ctx.bar` },
` }`
]
` }`,
],
})
})
test('should not duplicate object key with same name as value', () => {
const node = parseWithExpressionTransform(
`{{ { foo: foo } }}`
`{{ { foo: foo } }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ foo: `, { content: `_ctx.foo` }, ` }`]
children: [`{ foo: `, { content: `_ctx.foo` }, ` }`],
})
})
test('should prefix a computed object property key', () => {
const node = parseWithExpressionTransform(
`{{ { [foo]: bar } }}`
`{{ { [foo]: bar } }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -328,24 +328,24 @@ describe('compiler: expression transform', () => {
{ content: `_ctx.foo` },
`]: `,
{ content: `_ctx.bar` },
` }`
]
` }`,
],
})
})
test('should prefix object property shorthand value', () => {
const node = parseWithExpressionTransform(
`{{ { foo } }}`
`{{ { foo } }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ foo: `, { content: `_ctx.foo` }, ` }`]
children: [`{ foo: `, { content: `_ctx.foo` }, ` }`],
})
})
test('should not prefix id in a member expression', () => {
const node = parseWithExpressionTransform(
`{{ foo.bar.baz }}`
`{{ foo.bar.baz }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -354,14 +354,14 @@ describe('compiler: expression transform', () => {
`.`,
{ content: `bar` },
`.`,
{ content: `baz` }
]
{ content: `baz` },
],
})
})
test('should prefix computed id in a member expression', () => {
const node = parseWithExpressionTransform(
`{{ foo[bar][baz] }}`
`{{ foo[bar][baz] }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -371,8 +371,8 @@ describe('compiler: expression transform', () => {
{ content: `_ctx.bar` },
`][`,
{ content: '_ctx.baz' },
`]`
]
`]`,
],
})
})
@ -380,23 +380,23 @@ describe('compiler: expression transform', () => {
const onError = vi.fn()
parseWithExpressionTransform(`{{ a( }}`, { onError })
expect(onError.mock.calls[0][0].message).toMatch(
`Error parsing JavaScript expression: Unexpected token`
`Error parsing JavaScript expression: Unexpected token`,
)
})
test('should prefix in assignment', () => {
const node = parseWithExpressionTransform(
`{{ x = 1 }}`
`{{ x = 1 }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: `_ctx.x` }, ` = 1`]
children: [{ content: `_ctx.x` }, ` = 1`],
})
})
test('should prefix in assignment pattern', () => {
const node = parseWithExpressionTransform(
`{{ { x, y: [z] } = obj }}`
`{{ { x, y: [z] } = obj }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -406,47 +406,47 @@ describe('compiler: expression transform', () => {
`, y: [`,
{ content: `_ctx.z` },
`] } = `,
{ content: `_ctx.obj` }
]
{ content: `_ctx.obj` },
],
})
})
// #8295
test('should treat floating point number literals as constant', () => {
const node = parseWithExpressionTransform(
`{{ [1, 2.1] }}`
`{{ [1, 2.1] }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
constType: ConstantTypes.CAN_STRINGIFY
constType: ConstantTypes.CAN_STRINGIFY,
})
})
describe('ES Proposals support', () => {
test('bigInt', () => {
const node = parseWithExpressionTransform(
`{{ 13000n }}`
`{{ 13000n }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `13000n`,
isStatic: false,
constType: ConstantTypes.CAN_STRINGIFY
constType: ConstantTypes.CAN_STRINGIFY,
})
})
test('nullish coalescing', () => {
const node = parseWithExpressionTransform(
`{{ a ?? b }}`
`{{ a ?? b }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: `_ctx.a` }, ` ?? `, { content: `_ctx.b` }]
children: [{ content: `_ctx.a` }, ` ?? `, { content: `_ctx.b` }],
})
})
test('optional chaining', () => {
const node = parseWithExpressionTransform(
`{{ a?.b?.c }}`
`{{ a?.b?.c }}`,
) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -455,8 +455,8 @@ describe('compiler: expression transform', () => {
`?.`,
{ content: `b` },
`?.`,
{ content: `c` }
]
{ content: `c` },
],
})
})
@ -467,14 +467,18 @@ describe('compiler: expression transform', () => {
[
'pipelineOperator',
{
proposal: 'minimal'
}
]
]
proposal: 'minimal',
},
],
],
}) as InterpolationNode
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: `_ctx.a` }, ` |> `, { content: `_ctx.uppercase` }]
children: [
{ content: `_ctx.a` },
` |> `,
{ content: `_ctx.uppercase` },
],
})
})
})
@ -488,23 +492,23 @@ describe('compiler: expression transform', () => {
options: BindingTypes.OPTIONS,
reactive: BindingTypes.SETUP_REACTIVE_CONST,
literal: BindingTypes.LITERAL_CONST,
isNaN: BindingTypes.SETUP_REF
isNaN: BindingTypes.SETUP_REF,
}
function compileWithBindingMetadata(
template: string,
options?: CompilerOptions
options?: CompilerOptions,
) {
return baseCompile(template, {
prefixIdentifiers: true,
bindingMetadata,
...options
...options,
})
}
test('non-inline mode', () => {
const { code } = compileWithBindingMetadata(
`<div>{{ props }} {{ setup }} {{ data }} {{ options }} {{ isNaN }}</div>`
`<div>{{ props }} {{ setup }} {{ data }} {{ options }} {{ isNaN }}</div>`,
)
expect(code).toMatch(`$props.props`)
expect(code).toMatch(`$setup.setup`)
@ -521,7 +525,7 @@ describe('compiler: expression transform', () => {
for (const x in list) {
log(x)
}
}"/>`
}"/>`,
)
expect(code).not.toMatch(`_ctx.x`)
expect(code).toMatchSnapshot()
@ -533,7 +537,7 @@ describe('compiler: expression transform', () => {
for (const x of list) {
log(x)
}
}"/>`
}"/>`,
)
expect(code).not.toMatch(`_ctx.x`)
expect(code).toMatchSnapshot()
@ -545,7 +549,7 @@ describe('compiler: expression transform', () => {
for (let i = 0; i < list.length; i++) {
log(i)
}
}"/>`
}"/>`,
)
expect(code).not.toMatch(`_ctx.i`)
expect(code).toMatchSnapshot()
@ -554,7 +558,7 @@ describe('compiler: expression transform', () => {
test('inline mode', () => {
const { code } = compileWithBindingMetadata(
`<div>{{ props }} {{ setup }} {{ setupConst }} {{ data }} {{ options }} {{ isNaN }}</div>`,
{ inline: true }
{ inline: true },
)
expect(code).toMatch(`__props.props`)
expect(code).toMatch(`_unref(setup)`)
@ -567,12 +571,12 @@ describe('compiler: expression transform', () => {
test('literal const handling', () => {
const { code } = compileWithBindingMetadata(`<div>{{ literal }}</div>`, {
inline: true
inline: true,
})
expect(code).toMatch(`toDisplayString(literal)`)
// #7973 should skip patch for literal const
expect(code).not.toMatch(
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`,
)
})
@ -581,17 +585,17 @@ describe('compiler: expression transform', () => {
expect(code).toMatch(`toDisplayString($setup.literal)`)
// #7973 should skip patch for literal const
expect(code).not.toMatch(
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`,
)
})
test('reactive const handling', () => {
const { code } = compileWithBindingMetadata(`<div>{{ reactive }}</div>`, {
inline: true
inline: true,
})
// #7973 should not skip patch for reactive const
expect(code).toMatch(
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`,
)
})
})

View File

@ -1,10 +1,10 @@
import {
CompilerOptions,
type CompilerOptions,
type ElementNode,
ErrorCodes,
NodeTypes,
baseParse as parse,
transform,
ElementNode,
NodeTypes,
ErrorCodes
} from '../../src'
import { transformElement } from '../../src/transforms/transformElement'
import { transformOn } from '../../src/transforms/vOn'
@ -19,13 +19,13 @@ function parseWithSlots(template: string, options: CompilerOptions = {}) {
nodeTransforms: [
...(options.prefixIdentifiers ? [transformExpression] : []),
transformSlotOutlet,
transformElement
transformElement,
],
directiveTransforms: {
on: transformOn,
bind: transformBind
bind: transformBind,
},
...options
...options,
})
return ast
}
@ -36,7 +36,7 @@ describe('compiler: transform <slot> outlets', () => {
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
arguments: [`$slots`, `"default"`]
arguments: [`$slots`, `"default"`],
})
})
@ -45,7 +45,7 @@ describe('compiler: transform <slot> outlets', () => {
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
arguments: [`$slots`, `"foo"`]
arguments: [`$slots`, `"foo"`],
})
})
@ -59,15 +59,15 @@ describe('compiler: transform <slot> outlets', () => {
{
type: NodeTypes.SIMPLE_EXPRESSION,
content: `foo`,
isStatic: false
}
]
isStatic: false,
},
],
})
})
test('dynamically named slot outlet w/ prefixIdentifiers: true', () => {
const ast = parseWithSlots(`<slot :name="foo + bar" />`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
@ -80,23 +80,23 @@ describe('compiler: transform <slot> outlets', () => {
{
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.foo`,
isStatic: false
isStatic: false,
},
` + `,
{
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.bar`,
isStatic: false
}
]
}
]
isStatic: false,
},
],
},
],
})
})
test('default slot outlet with props', () => {
const ast = parseWithSlots(
`<slot foo="bar" :baz="qux" :foo-bar="foo-bar" />`
`<slot foo="bar" :baz="qux" :foo-bar="foo-bar" />`,
)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
@ -110,36 +110,36 @@ describe('compiler: transform <slot> outlets', () => {
{
key: {
content: `foo`,
isStatic: true
isStatic: true,
},
value: {
content: `bar`,
isStatic: true
}
isStatic: true,
},
},
{
key: {
content: `baz`,
isStatic: true
isStatic: true,
},
value: {
content: `qux`,
isStatic: false
}
isStatic: false,
},
},
{
key: {
content: `fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `foo-bar`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
@ -158,26 +158,26 @@ describe('compiler: transform <slot> outlets', () => {
{
key: {
content: `foo`,
isStatic: true
isStatic: true,
},
value: {
content: `bar`,
isStatic: true
}
isStatic: true,
},
},
{
key: {
content: `baz`,
isStatic: true
isStatic: true,
},
value: {
content: `qux`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
@ -196,26 +196,26 @@ describe('compiler: transform <slot> outlets', () => {
{
key: {
content: `foo`,
isStatic: true
isStatic: true,
},
value: {
content: `bar`,
isStatic: true
}
isStatic: true,
},
},
{
key: {
content: `baz`,
isStatic: true
isStatic: true,
},
value: {
content: `qux`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
@ -234,11 +234,11 @@ describe('compiler: transform <slot> outlets', () => {
returns: [
{
type: NodeTypes.ELEMENT,
tag: `div`
}
]
}
]
tag: `div`,
},
],
},
],
})
})
@ -257,11 +257,11 @@ describe('compiler: transform <slot> outlets', () => {
returns: [
{
type: NodeTypes.ELEMENT,
tag: `div`
}
]
}
]
tag: `div`,
},
],
},
],
})
})
@ -279,14 +279,14 @@ describe('compiler: transform <slot> outlets', () => {
{
key: {
content: `foo`,
isStatic: true
isStatic: true,
},
value: {
content: `bar`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
},
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
@ -294,11 +294,11 @@ describe('compiler: transform <slot> outlets', () => {
returns: [
{
type: NodeTypes.ELEMENT,
tag: `div`
}
]
}
]
tag: `div`,
},
],
},
],
})
})
@ -316,14 +316,14 @@ describe('compiler: transform <slot> outlets', () => {
{
key: {
content: `foo`,
isStatic: true
isStatic: true,
},
value: {
content: `bar`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
},
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
@ -331,11 +331,11 @@ describe('compiler: transform <slot> outlets', () => {
returns: [
{
type: NodeTypes.ELEMENT,
tag: `div`
}
]
}
]
tag: `div`,
},
],
},
],
})
})
@ -344,11 +344,11 @@ describe('compiler: transform <slot> outlets', () => {
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
arguments: [`$slots`, `"default"`, `{}`, `undefined`, `true`]
arguments: [`$slots`, `"default"`, `{}`, `undefined`, `true`],
})
const fallback = parseWithSlots(`<slot>fallback</slot>`, {
slotted: false,
scopeId: 'foo'
scopeId: 'foo',
})
const child = {
@ -357,14 +357,14 @@ describe('compiler: transform <slot> outlets', () => {
returns: [
{
type: NodeTypes.TEXT,
content: `fallback`
}
]
content: `fallback`,
},
],
}
expect((fallback.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
arguments: [`$slots`, `"default"`, `{}`, child, `true`]
arguments: [`$slots`, `"default"`, `{}`, child, `true`],
})
})
@ -379,14 +379,14 @@ describe('compiler: transform <slot> outlets', () => {
start: {
offset: index,
line: 1,
column: index + 1
column: index + 1,
},
end: {
offset: index + 5,
line: 1,
column: index + 6
}
}
column: index + 6,
},
},
})
})
})

View File

@ -1,11 +1,11 @@
import {
CompilerOptions,
baseParse as parse,
transform,
type CompilerOptions,
type ElementNode,
type ForNode,
NodeTypes,
generate,
ForNode,
ElementNode
baseParse as parse,
transform,
} from '../../src'
import { transformFor } from '../../src/transforms/vFor'
import { transformText } from '../../src/transforms/transformText'
@ -22,9 +22,9 @@ function transformWithTextOpt(template: string, options: CompilerOptions = {}) {
transformFor,
...(options.prefixIdentifiers ? [transformExpression] : []),
transformElement,
transformText
transformText,
],
...options
...options,
})
return ast
}
@ -35,8 +35,8 @@ describe('compiler: transform text', () => {
expect(root.children[0]).toMatchObject({
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -51,8 +51,8 @@ describe('compiler: transform text', () => {
` + `,
{ type: NodeTypes.TEXT, content: ` bar ` },
` + `,
{ type: NodeTypes.INTERPOLATION, content: { content: `baz` } }
]
{ type: NodeTypes.INTERPOLATION, content: { content: `baz` } },
],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -75,12 +75,12 @@ describe('compiler: transform text', () => {
` + `,
{ type: NodeTypes.TEXT, content: ` bar ` },
` + `,
{ type: NodeTypes.INTERPOLATION, content: { content: `baz` } }
]
{ type: NodeTypes.INTERPOLATION, content: { content: `baz` } },
],
},
genFlagText(PatchFlags.TEXT)
]
}
genFlagText(PatchFlags.TEXT),
],
},
})
expect(root.children[2].type).toBe(NodeTypes.ELEMENT)
expect(generate(root).code).toMatchSnapshot()
@ -99,11 +99,11 @@ describe('compiler: transform text', () => {
arguments: [
{
type: NodeTypes.TEXT,
content: `hello`
}
content: `hello`,
},
// should have no flag
]
}
],
},
})
expect(root.children[2].type).toBe(NodeTypes.ELEMENT)
expect(generate(root).code).toMatchSnapshot()
@ -111,7 +111,7 @@ describe('compiler: transform text', () => {
test('consecutive text mixed with elements', () => {
const root = transformWithTextOpt(
`<div/>{{ foo }} bar {{ baz }}<div/>hello<div/>`
`<div/>{{ foo }} bar {{ baz }}<div/>hello<div/>`,
)
expect(root.children.length).toBe(5)
expect(root.children[0].type).toBe(NodeTypes.ELEMENT)
@ -128,12 +128,12 @@ describe('compiler: transform text', () => {
` + `,
{ type: NodeTypes.TEXT, content: ` bar ` },
` + `,
{ type: NodeTypes.INTERPOLATION, content: { content: `baz` } }
]
{ type: NodeTypes.INTERPOLATION, content: { content: `baz` } },
],
},
genFlagText(PatchFlags.TEXT)
]
}
genFlagText(PatchFlags.TEXT),
],
},
})
expect(root.children[2].type).toBe(NodeTypes.ELEMENT)
expect(root.children[3]).toMatchObject({
@ -144,10 +144,10 @@ describe('compiler: transform text', () => {
arguments: [
{
type: NodeTypes.TEXT,
content: `hello`
}
]
}
content: `hello`,
},
],
},
})
expect(root.children[4].type).toBe(NodeTypes.ELEMENT)
expect(generate(root).code).toMatchSnapshot()
@ -155,21 +155,21 @@ describe('compiler: transform text', () => {
test('<template v-for>', () => {
const root = transformWithTextOpt(
`<template v-for="i in list">foo</template>`
`<template v-for="i in list">foo</template>`,
)
expect(root.children[0].type).toBe(NodeTypes.FOR)
const forNode = root.children[0] as ForNode
// should convert template v-for text children because they are inside
// fragments
expect(forNode.children[0]).toMatchObject({
type: NodeTypes.TEXT_CALL
type: NodeTypes.TEXT_CALL,
})
expect(generate(root).code).toMatchSnapshot()
})
test('with prefixIdentifiers: true', () => {
const root = transformWithTextOpt(`{{ foo }} bar {{ baz + qux }}`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(root.children.length).toBe(1)
expect(root.children[0]).toMatchObject({
@ -183,15 +183,15 @@ describe('compiler: transform text', () => {
type: NodeTypes.INTERPOLATION,
content: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: `_ctx.baz` }, ` + `, { content: `_ctx.qux` }]
}
}
]
children: [{ content: `_ctx.baz` }, ` + `, { content: `_ctx.qux` }],
},
},
],
})
expect(
generate(root, {
prefixIdentifiers: true
}).code
prefixIdentifiers: true,
}).code,
).toMatchSnapshot()
})
@ -210,12 +210,12 @@ describe('compiler: transform text', () => {
type: NodeTypes.INTERPOLATION,
content: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'foo'
}
content: 'foo',
},
},
genFlagText(PatchFlags.TEXT)
]
}
genFlagText(PatchFlags.TEXT),
],
},
})
expect(generate(root).code).toMatchSnapshot()
})

View File

@ -1,37 +1,37 @@
import {
type CallExpression,
type CompilerOptions,
type ElementNode,
ErrorCodes,
NodeTypes,
type ObjectExpression,
type VNodeCall,
baseParse as parse,
transform,
ElementNode,
ObjectExpression,
CompilerOptions,
ErrorCodes,
VNodeCall,
NodeTypes,
CallExpression
} from '../../src'
import { transformBind } from '../../src/transforms/vBind'
import { transformElement } from '../../src/transforms/transformElement'
import {
CAMELIZE,
NORMALIZE_PROPS,
helperNameMap,
NORMALIZE_PROPS
} from '../../src/runtimeHelpers'
import { transformExpression } from '../../src/transforms/transformExpression'
function parseWithVBind(
template: string,
options: CompilerOptions = {}
options: CompilerOptions = {},
): ElementNode {
const ast = parse(template)
transform(ast, {
nodeTransforms: [
...(options.prefixIdentifiers ? [transformExpression] : []),
transformElement
transformElement,
],
directiveTransforms: {
bind: transformBind
bind: transformBind,
},
...options
...options,
})
return ast.children[0] as ElementNode
}
@ -47,13 +47,13 @@ describe('compiler: transform v-bind', () => {
loc: {
start: {
line: 1,
column: 13
column: 13,
},
end: {
line: 1,
column: 15
}
}
column: 15,
},
},
},
value: {
content: `id`,
@ -61,14 +61,14 @@ describe('compiler: transform v-bind', () => {
loc: {
start: {
line: 1,
column: 17
column: 17,
},
end: {
line: 1,
column: 19
}
}
}
column: 19,
},
},
},
})
})
@ -81,17 +81,17 @@ describe('compiler: transform v-bind', () => {
isStatic: true,
loc: {
start: { line: 1, column: 13, offset: 12 },
end: { line: 1, column: 15, offset: 14 }
}
end: { line: 1, column: 15, offset: 14 },
},
},
value: {
content: `id`,
isStatic: false,
loc: {
start: { line: 1, column: 13, offset: 12 },
end: { line: 1, column: 15, offset: 14 }
}
}
end: { line: 1, column: 15, offset: 14 },
},
},
})
})
@ -101,12 +101,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `id`,
isStatic: true
isStatic: true,
},
value: {
content: `id`,
isStatic: false
}
isStatic: false,
},
})
})
@ -123,16 +123,16 @@ describe('compiler: transform v-bind', () => {
{
key: {
content: `id || ""`,
isStatic: false
isStatic: false,
},
value: {
content: `id`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
@ -145,23 +145,23 @@ describe('compiler: transform v-bind', () => {
loc: {
start: {
line: 1,
column: 6
column: 6,
},
end: {
line: 1,
column: 19
}
}
column: 19,
},
},
})
expect(props.properties[0]).toMatchObject({
key: {
content: `arg`,
isStatic: true
isStatic: true,
},
value: {
content: ``,
isStatic: true
}
isStatic: true,
},
})
})
@ -171,12 +171,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `id`,
isStatic: false
}
isStatic: false,
},
})
})
@ -186,12 +186,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false
}
isStatic: false,
},
})
})
@ -208,22 +208,22 @@ describe('compiler: transform v-bind', () => {
{
key: {
content: `_${helperNameMap[CAMELIZE]}(foo || "")`,
isStatic: false
isStatic: false,
},
value: {
content: `id`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
test('.camel modifier w/ dynamic arg + prefixIdentifiers', () => {
const node = parseWithVBind(`<div v-bind:[foo(bar)].camel="id"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
const props = (node.codegenNode as VNodeCall).props as CallExpression
expect(props).toMatchObject({
@ -243,17 +243,17 @@ describe('compiler: transform v-bind', () => {
{ content: `_ctx.bar` },
`)`,
`) || ""`,
`)`
]
`)`,
],
},
value: {
content: `_ctx.id`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
@ -263,12 +263,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `id`,
isStatic: false
}
isStatic: false,
},
})
})
@ -278,12 +278,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false
}
isStatic: false,
},
})
})
@ -300,22 +300,22 @@ describe('compiler: transform v-bind', () => {
{
key: {
content: '`.${fooBar || ""}`',
isStatic: false
isStatic: false,
},
value: {
content: `id`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
test('.prop modifier w/ dynamic arg + prefixIdentifiers', () => {
const node = parseWithVBind(`<div v-bind:[foo(bar)].prop="id"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
const props = (node.codegenNode as VNodeCall).props as CallExpression
expect(props).toMatchObject({
@ -335,17 +335,17 @@ describe('compiler: transform v-bind', () => {
{ content: `_ctx.bar` },
`)`,
`) || ""`,
`)`
]
`)`,
],
},
value: {
content: `_ctx.id`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
})
@ -355,12 +355,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `id`,
isStatic: false
}
isStatic: false,
},
})
})
@ -370,12 +370,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `.fooBar`,
isStatic: true
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false
}
isStatic: false,
},
})
})
@ -385,12 +385,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `^foo-bar`,
isStatic: true
isStatic: true,
},
value: {
content: `id`,
isStatic: false
}
isStatic: false,
},
})
})
@ -400,12 +400,12 @@ describe('compiler: transform v-bind', () => {
expect(props.properties[0]).toMatchObject({
key: {
content: `^foo-bar`,
isStatic: true
isStatic: true,
},
value: {
content: `fooBar`,
isStatic: false
}
isStatic: false,
},
})
})
})

View File

@ -7,23 +7,23 @@ import { transformElement } from '../../src/transforms/transformElement'
import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet'
import { transformExpression } from '../../src/transforms/transformExpression'
import {
ForNode,
ConstantTypes,
type ElementNode,
type ForCodegenNode,
type ForNode,
type InterpolationNode,
NodeTypes,
SimpleExpressionNode,
ElementNode,
InterpolationNode,
ForCodegenNode,
ConstantTypes
type SimpleExpressionNode,
} from '../../src/ast'
import { ErrorCodes } from '../../src/errors'
import { CompilerOptions, generate } from '../../src'
import { type CompilerOptions, generate } from '../../src'
import { FRAGMENT, RENDER_LIST, RENDER_SLOT } from '../../src/runtimeHelpers'
import { PatchFlags } from '@vue/shared'
import { createObjectMatcher, genFlagText } from '../testUtils'
function parseWithForTransform(
template: string,
options: CompilerOptions = {}
options: CompilerOptions = {},
) {
const ast = parse(template, options)
transform(ast, {
@ -32,16 +32,16 @@ function parseWithForTransform(
transformFor,
...(options.prefixIdentifiers ? [transformExpression] : []),
transformSlotOutlet,
transformElement
transformElement,
],
directiveTransforms: {
bind: transformBind
bind: transformBind,
},
...options
...options,
})
return {
root: ast,
node: ast.children[0] as ForNode & { codegenNode: ForCodegenNode }
node: ast.children[0] as ForNode & { codegenNode: ForCodegenNode },
}
}
@ -49,7 +49,7 @@ describe('compiler: v-for', () => {
describe('transform', () => {
test('number expression', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="index in 5" />'
'<span v-for="index in 5" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
@ -59,7 +59,7 @@ describe('compiler: v-for', () => {
test('value', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="(item) in items" />'
'<span v-for="(item) in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
@ -69,31 +69,31 @@ describe('compiler: v-for', () => {
test('object de-structured value', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="({ id, value }) in items" />'
'<span v-for="({ id, value }) in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
'{ id, value }'
'{ id, value }',
)
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('array de-structured value', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="([ id, value ]) in items" />'
'<span v-for="([ id, value ]) in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
'[ id, value ]'
'[ id, value ]',
)
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('value and key', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="(item, key) in items" />'
'<span v-for="(item, key) in items" />',
)
expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
@ -104,13 +104,13 @@ describe('compiler: v-for', () => {
test('value, key and index', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="(value, key, index) in items" />'
'<span v-for="(value, key, index) in items" />',
)
expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
'index',
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@ -118,12 +118,12 @@ describe('compiler: v-for', () => {
test('skipped key', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="(value,,index) in items" />'
'<span v-for="(value,,index) in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
'index',
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@ -131,12 +131,12 @@ describe('compiler: v-for', () => {
test('skipped value and key', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="(,,index) in items" />'
'<span v-for="(,,index) in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
'index',
)
expect(forNode.valueAlias).toBeUndefined()
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@ -144,7 +144,7 @@ describe('compiler: v-for', () => {
test('unbracketed value', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="item in items" />'
'<span v-for="item in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
@ -154,7 +154,7 @@ describe('compiler: v-for', () => {
test('unbracketed value and key', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="item, key in items" />'
'<span v-for="item, key in items" />',
)
expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
@ -165,13 +165,13 @@ describe('compiler: v-for', () => {
test('unbracketed value, key and index', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="value, key, index in items" />'
'<span v-for="value, key, index in items" />',
)
expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
'index',
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@ -179,12 +179,12 @@ describe('compiler: v-for', () => {
test('unbracketed skipped key', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for="value, , index in items" />'
'<span v-for="value, , index in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
'index',
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@ -192,12 +192,12 @@ describe('compiler: v-for', () => {
test('unbracketed skipped value and key', () => {
const { node: forNode } = parseWithForTransform(
'<span v-for=", , index in items" />'
'<span v-for=", , index in items" />',
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
'index',
)
expect(forNode.valueAlias).toBeUndefined()
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@ -212,8 +212,8 @@ describe('compiler: v-for', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_FOR_NO_EXPRESSION
})
code: ErrorCodes.X_V_FOR_NO_EXPRESSION,
}),
)
})
@ -224,8 +224,8 @@ describe('compiler: v-for', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION
})
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
}),
)
})
@ -236,8 +236,8 @@ describe('compiler: v-for', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION
})
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
}),
)
})
@ -248,8 +248,8 @@ describe('compiler: v-for', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION
})
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
}),
)
})
@ -260,8 +260,8 @@ describe('compiler: v-for', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION
})
code: ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
}),
)
})
@ -272,14 +272,14 @@ describe('compiler: v-for', () => {
<template v-for="item in items">
<div :key="item.id"/>
</template>`,
{ onError }
{ onError },
)
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT
})
code: ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT,
}),
)
// should not warn on nested v-for keys
@ -288,7 +288,7 @@ describe('compiler: v-for', () => {
<template v-for="item in items">
<div v-for="c in item.children" :key="c.id"/>
</template>`,
{ onError }
{ onError },
)
expect(onError).toHaveBeenCalledTimes(1)
})
@ -315,7 +315,7 @@ describe('compiler: v-for', () => {
expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
expect(forNode.source.loc.end.column).toBe(
itemsOffset + 1 + `items`.length
itemsOffset + 1 + `items`.length,
)
})
@ -339,7 +339,7 @@ describe('compiler: v-for', () => {
expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
expect(forNode.source.loc.end.column).toBe(
itemsOffset + 1 + `items`.length
itemsOffset + 1 + `items`.length,
)
})
@ -363,7 +363,7 @@ describe('compiler: v-for', () => {
expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
expect(forNode.source.loc.end.column).toBe(
itemsOffset + 1 + `items`.length
itemsOffset + 1 + `items`.length,
)
})
@ -405,7 +405,7 @@ describe('compiler: v-for', () => {
expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
expect(forNode.source.loc.end.column).toBe(
itemsOffset + 1 + `items`.length
itemsOffset + 1 + `items`.length,
)
})
@ -438,7 +438,7 @@ describe('compiler: v-for', () => {
expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
expect(forNode.source.loc.end.line).toBe(1)
expect(forNode.source.loc.end.column).toBe(
itemsOffset + 1 + `items`.length
itemsOffset + 1 + `items`.length,
)
})
})
@ -446,18 +446,18 @@ describe('compiler: v-for', () => {
describe('prefixIdentifiers: true', () => {
test('should prefix v-for source', () => {
const { node } = parseWithForTransform(`<div v-for="i in list"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(node.source).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.list`
content: `_ctx.list`,
})
})
test('should prefix v-for source w/ complex expression', () => {
const { node } = parseWithForTransform(
`<div v-for="i in list.concat([foo])"/>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(node.source).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -467,31 +467,31 @@ describe('compiler: v-for', () => {
{ content: `concat` },
`([`,
{ content: `_ctx.foo` },
`])`
]
`])`,
],
})
})
test('should not prefix v-for alias', () => {
const { node } = parseWithForTransform(
`<div v-for="i in list">{{ i }}{{ j }}</div>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `i`
content: `i`,
})
expect((div.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.j`
content: `_ctx.j`,
})
})
test('should not prefix v-for aliases (multiple)', () => {
const { node } = parseWithForTransform(
`<div v-for="(i, j, k) in list">{{ i + j + k }}{{ l }}</div>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
@ -501,23 +501,23 @@ describe('compiler: v-for', () => {
` + `,
{ content: `j` },
` + `,
{ content: `k` }
]
{ content: `k` },
],
})
expect((div.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.l`
content: `_ctx.l`,
})
})
test('should prefix id outside of v-for', () => {
const { node } = parseWithForTransform(
`<div><div v-for="i in list" />{{ i }}</div>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect((node.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.i`
content: `_ctx.i`,
})
})
@ -526,7 +526,7 @@ describe('compiler: v-for', () => {
`<div v-for="i in list">
<div v-for="i in list">{{ i + j }}</div>{{ i }}
</div>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
const outerDiv = node.children[0] as ElementNode
const innerFor = outerDiv.children[0] as ForNode
@ -534,7 +534,7 @@ describe('compiler: v-for', () => {
.children[0] as InterpolationNode
expect(innerExp.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: 'i' }, ` + `, { content: `_ctx.j` }]
children: [{ content: 'i' }, ` + `, { content: `_ctx.j` }],
})
// when an inner v-for shadows a variable of an outer v-for and exit,
@ -542,7 +542,7 @@ describe('compiler: v-for', () => {
const outerExp = outerDiv.children[1] as InterpolationNode
expect(outerExp.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `i`
content: `i`,
})
})
@ -551,7 +551,7 @@ describe('compiler: v-for', () => {
`<div v-for="({ foo = bar, baz: [qux = quux] }) in list">
{{ foo + bar + baz + qux + quux }}
</div>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(node.valueAlias!).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
@ -564,8 +564,8 @@ describe('compiler: v-for', () => {
{ content: `qux` },
` = `,
{ content: `_ctx.quux` },
`] }`
]
`] }`,
],
})
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
@ -579,17 +579,17 @@ describe('compiler: v-for', () => {
` + `,
{ content: `qux` },
` + `,
{ content: `_ctx.quux` }
]
{ content: `_ctx.quux` },
],
})
})
test('element v-for key expression prefixing', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<div v-for="item in items" :key="itemKey(item)">test</div>',
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
const innerBlock = codegenNode.children.arguments[1].returns
expect(innerBlock).toMatchObject({
@ -604,20 +604,20 @@ describe('compiler: v-for', () => {
`(`,
// should NOT prefix in scope variables
{ content: `item` },
`)`
]
}
})
`)`,
],
},
}),
})
})
// #2085
test('template v-for key expression prefixing', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="item in items" :key="itemKey(item)">test</template>',
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
const innerBlock = codegenNode.children.arguments[1].returns
expect(innerBlock).toMatchObject({
@ -632,19 +632,19 @@ describe('compiler: v-for', () => {
`(`,
// should NOT prefix in scope variables
{ content: `item` },
`)`
]
}
})
`)`,
],
},
}),
})
})
test('template v-for key no prefixing on attribute key', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="item in items" key="key">test</template>',
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
const innerBlock = codegenNode.children.arguments[1].returns
expect(innerBlock).toMatchObject({
@ -653,9 +653,9 @@ describe('compiler: v-for', () => {
props: createObjectMatcher({
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'key'
}
})
content: 'key',
},
}),
})
})
})
@ -665,7 +665,7 @@ describe('compiler: v-for', () => {
node: ForCodegenNode,
keyed: boolean = false,
customReturn: boolean = false,
disableTracking: boolean = true
disableTracking: boolean = true,
) {
expect(node).toMatchObject({
type: NodeTypes.VNODE_CALL,
@ -687,32 +687,34 @@ describe('compiler: v-for', () => {
? {}
: {
type: NodeTypes.VNODE_CALL,
isBlock: disableTracking
}
}
]
}
isBlock: disableTracking,
},
},
],
},
})
const renderListArgs = node.children.arguments
return {
source: renderListArgs[0] as SimpleExpressionNode,
params: (renderListArgs[1] as any).params,
returns: (renderListArgs[1] as any).returns,
innerVNodeCall: customReturn ? null : (renderListArgs[1] as any).returns
innerVNodeCall: customReturn
? null
: (renderListArgs[1] as any).returns,
}
}
test('basic v-for', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<span v-for="(item) in items" />')
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
params: [{ content: `item` }],
innerVNodeCall: {
tag: `"span"`
}
tag: `"span"`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -720,11 +722,11 @@ describe('compiler: v-for', () => {
test('value + key + index', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<span v-for="(item, key, index) in items" />')
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
params: [{ content: `item` }, { content: `key` }, { content: `index` }]
params: [{ content: `item` }, { content: `key` }, { content: `index` }],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -732,11 +734,11 @@ describe('compiler: v-for', () => {
test('skipped value', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<span v-for="(, key, index) in items" />')
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
params: [{ content: `_` }, { content: `key` }, { content: `index` }]
params: [{ content: `_` }, { content: `key` }, { content: `index` }],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -744,11 +746,11 @@ describe('compiler: v-for', () => {
test('skipped key', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<span v-for="(item,,index) in items" />')
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
params: [{ content: `item` }, { content: `__` }, { content: `index` }]
params: [{ content: `item` }, { content: `__` }, { content: `index` }],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -756,11 +758,11 @@ describe('compiler: v-for', () => {
test('skipped value & key', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<span v-for="(,,index) in items" />')
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
params: [{ content: `_` }, { content: `__` }, { content: `index` }]
params: [{ content: `_` }, { content: `__` }, { content: `index` }],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -768,9 +770,9 @@ describe('compiler: v-for', () => {
test('v-for with constant expression', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<p v-for="item in 10">{{item}}</p>', {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(
@ -778,8 +780,8 @@ describe('compiler: v-for', () => {
codegenNode,
false /* keyed */,
false /* customReturn */,
false /* disableTracking */
)
false /* disableTracking */,
),
).toMatchObject({
source: { content: `10`, constType: ConstantTypes.CAN_STRINGIFY },
params: [{ content: `item` }],
@ -793,11 +795,11 @@ describe('compiler: v-for', () => {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'item',
isStatic: false,
constType: ConstantTypes.NOT_CONSTANT
}
constType: ConstantTypes.NOT_CONSTANT,
},
},
patchFlag: genFlagText(PatchFlags.TEXT)
}
patchFlag: genFlagText(PatchFlags.TEXT),
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -805,9 +807,9 @@ describe('compiler: v-for', () => {
test('template v-for', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="item in items">hello<span/></template>'
'<template v-for="item in items">hello<span/></template>',
)
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
@ -818,10 +820,10 @@ describe('compiler: v-for', () => {
isBlock: true,
children: [
{ type: NodeTypes.TEXT, content: `hello` },
{ type: NodeTypes.ELEMENT, tag: `span` }
{ type: NodeTypes.ELEMENT, tag: `span` },
],
patchFlag: genFlagText(PatchFlags.STABLE_FRAGMENT)
}
patchFlag: genFlagText(PatchFlags.STABLE_FRAGMENT),
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -829,19 +831,19 @@ describe('compiler: v-for', () => {
test('template v-for w/ <slot/>', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="item in items"><slot/></template>'
'<template v-for="item in items"><slot/></template>',
)
expect(
assertSharedCodegen(codegenNode, false, true /* custom return */)
assertSharedCodegen(codegenNode, false, true /* custom return */),
).toMatchObject({
source: { content: `items` },
params: [{ content: `item` }],
returns: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT
}
callee: RENDER_SLOT,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -850,9 +852,9 @@ describe('compiler: v-for', () => {
test('template v-for key injection with single child', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="item in items" :key="item.id"><span :id="item.id" /></template>'
'<template v-for="item in items" :key="item.id"><span :id="item.id" /></template>',
)
expect(assertSharedCodegen(codegenNode, true)).toMatchObject({
source: { content: `items` },
@ -862,9 +864,9 @@ describe('compiler: v-for', () => {
tag: `"span"`,
props: createObjectMatcher({
key: '[item.id]',
id: '[item.id]'
})
}
id: '[item.id]',
}),
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -872,17 +874,17 @@ describe('compiler: v-for', () => {
test('v-for on <slot/>', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<slot v-for="item in items"></slot>')
expect(
assertSharedCodegen(codegenNode, false, true /* custom return */)
assertSharedCodegen(codegenNode, false, true /* custom return */),
).toMatchObject({
source: { content: `items` },
params: [{ content: `item` }],
returns: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT
}
callee: RENDER_SLOT,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -890,7 +892,7 @@ describe('compiler: v-for', () => {
test('keyed v-for', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<span v-for="(item) in items" :key="item" />')
expect(assertSharedCodegen(codegenNode, true)).toMatchObject({
source: { content: `items` },
@ -898,9 +900,9 @@ describe('compiler: v-for', () => {
innerVNodeCall: {
tag: `"span"`,
props: createObjectMatcher({
key: `[item]`
})
}
key: `[item]`,
}),
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -908,9 +910,9 @@ describe('compiler: v-for', () => {
test('keyed template v-for', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="item in items" :key="item">hello<span/></template>'
'<template v-for="item in items" :key="item">hello<span/></template>',
)
expect(assertSharedCodegen(codegenNode, true)).toMatchObject({
source: { content: `items` },
@ -918,14 +920,14 @@ describe('compiler: v-for', () => {
innerVNodeCall: {
tag: FRAGMENT,
props: createObjectMatcher({
key: `[item]`
key: `[item]`,
}),
children: [
{ type: NodeTypes.TEXT, content: `hello` },
{ type: NodeTypes.ELEMENT, tag: `span` }
{ type: NodeTypes.ELEMENT, tag: `span` },
],
patchFlag: genFlagText(PatchFlags.STABLE_FRAGMENT)
}
patchFlag: genFlagText(PatchFlags.STABLE_FRAGMENT),
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -933,7 +935,7 @@ describe('compiler: v-for', () => {
test('v-if + v-for', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(`<div v-if="ok" v-for="i in list"/>`)
expect(codegenNode).toMatchObject({
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
@ -941,7 +943,7 @@ describe('compiler: v-for', () => {
consequent: {
type: NodeTypes.VNODE_CALL,
props: createObjectMatcher({
key: `[0]`
key: `[0]`,
}),
isBlock: true,
disableTracking: true,
@ -957,12 +959,12 @@ describe('compiler: v-for', () => {
returns: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
isBlock: true
}
}
]
}
}
isBlock: true,
},
},
],
},
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -971,7 +973,7 @@ describe('compiler: v-for', () => {
test('v-if + v-for on <template>', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform(`<template v-if="ok" v-for="i in list"/>`)
expect(codegenNode).toMatchObject({
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
@ -979,7 +981,7 @@ describe('compiler: v-for', () => {
consequent: {
type: NodeTypes.VNODE_CALL,
props: createObjectMatcher({
key: `[0]`
key: `[0]`,
}),
isBlock: true,
disableTracking: true,
@ -995,12 +997,12 @@ describe('compiler: v-for', () => {
returns: {
type: NodeTypes.VNODE_CALL,
tag: FRAGMENT,
isBlock: true
}
}
]
}
}
isBlock: true,
},
},
],
},
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -1008,12 +1010,12 @@ describe('compiler: v-for', () => {
test('v-for on element with custom directive', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithForTransform('<div v-for="i in list" v-foo/>')
const { returns } = assertSharedCodegen(codegenNode, false, true)
expect(returns).toMatchObject({
type: NodeTypes.VNODE_CALL,
directives: { type: NodeTypes.JS_ARRAY_EXPRESSION }
directives: { type: NodeTypes.JS_ARRAY_EXPRESSION },
})
expect(generate(root).code).toMatchSnapshot()
})

View File

@ -4,26 +4,26 @@ import { transformIf } from '../../src/transforms/vIf'
import { transformElement } from '../../src/transforms/transformElement'
import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet'
import {
CommentNode,
ConditionalExpression,
ElementNode,
type CommentNode,
type ConditionalExpression,
type ElementNode,
ElementTypes,
IfBranchNode,
IfConditionalExpression,
IfNode,
type IfBranchNode,
type IfConditionalExpression,
type IfNode,
NodeTypes,
SimpleExpressionNode,
TextNode,
VNodeCall
type SimpleExpressionNode,
type TextNode,
type VNodeCall,
} from '../../src/ast'
import { ErrorCodes } from '../../src/errors'
import { CompilerOptions, generate, TO_HANDLERS } from '../../src'
import { type CompilerOptions, TO_HANDLERS, generate } from '../../src'
import {
CREATE_COMMENT,
FRAGMENT,
MERGE_PROPS,
NORMALIZE_PROPS,
RENDER_SLOT
RENDER_SLOT,
} from '../../src/runtimeHelpers'
import { createObjectMatcher } from '../testUtils'
@ -31,12 +31,12 @@ function parseWithIfTransform(
template: string,
options: CompilerOptions = {},
returnIndex: number = 0,
childrenLen: number = 1
childrenLen: number = 1,
) {
const ast = parse(template, options)
transform(ast, {
nodeTransforms: [transformIf, transformSlotOutlet, transformElement],
...options
...options,
})
if (!options.onError) {
expect(ast.children.length).toBe(childrenLen)
@ -48,7 +48,7 @@ function parseWithIfTransform(
root: ast,
node: ast.children[returnIndex] as IfNode & {
codegenNode: IfConditionalExpression
}
},
}
}
@ -59,7 +59,7 @@ describe('compiler: v-if', () => {
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(1)
expect((node.branches[0].condition as SimpleExpressionNode).content).toBe(
`ok`
`ok`,
)
expect(node.branches[0].children.length).toBe(1)
expect(node.branches[0].children[0].type).toBe(NodeTypes.ELEMENT)
@ -68,12 +68,12 @@ describe('compiler: v-if', () => {
test('template v-if', () => {
const { node } = parseWithIfTransform(
`<template v-if="ok"><div/>hello<p/></template>`
`<template v-if="ok"><div/>hello<p/></template>`,
)
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(1)
expect((node.branches[0].condition as SimpleExpressionNode).content).toBe(
`ok`
`ok`,
)
expect(node.branches[0].children.length).toBe(3)
expect(node.branches[0].children[0].type).toBe(NodeTypes.ELEMENT)
@ -89,16 +89,16 @@ describe('compiler: v-if', () => {
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(1)
expect((node.branches[0].children[0] as ElementNode).tag).toBe(
`Component`
`Component`,
)
expect((node.branches[0].children[0] as ElementNode).tagType).toBe(
ElementTypes.COMPONENT
ElementTypes.COMPONENT,
)
// #2058 since a component may fail to resolve and fallback to a plain
// element, it still needs to be made a block
expect(
((node.branches[0].children[0] as ElementNode)!
.codegenNode as VNodeCall)!.isBlock
.codegenNode as VNodeCall)!.isBlock,
).toBe(true)
})
@ -122,7 +122,7 @@ describe('compiler: v-if', () => {
test('v-if + v-else-if', () => {
const { node } = parseWithIfTransform(
`<div v-if="ok"/><p v-else-if="orNot"/>`
`<div v-if="ok"/><p v-else-if="orNot"/>`,
)
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(2)
@ -142,7 +142,7 @@ describe('compiler: v-if', () => {
test('v-if + v-else-if + v-else', () => {
const { node } = parseWithIfTransform(
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`,
)
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(3)
@ -202,11 +202,11 @@ describe('compiler: v-if', () => {
test('should prefix v-if condition', () => {
const { node } = parseWithIfTransform(`<div v-if="ok"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(node.branches[0].condition).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.ok`
content: `_ctx.ok`,
})
})
})
@ -219,32 +219,32 @@ describe('compiler: v-if', () => {
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: node1.loc
}
loc: node1.loc,
},
])
const { node: node2 } = parseWithIfTransform(
`<div/><div v-else/>`,
{ onError },
1
1,
)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: node2.loc
}
loc: node2.loc,
},
])
const { node: node3 } = parseWithIfTransform(
`<div/>foo<div v-else/>`,
{ onError },
2
2,
)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: node3.loc
}
loc: node3.loc,
},
])
})
@ -252,52 +252,52 @@ describe('compiler: v-if', () => {
const onError = vi.fn()
const { node: node1 } = parseWithIfTransform(`<div v-else-if="foo"/>`, {
onError
onError,
})
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: node1.loc
}
loc: node1.loc,
},
])
const { node: node2 } = parseWithIfTransform(
`<div/><div v-else-if="foo"/>`,
{ onError },
1
1,
)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: node2.loc
}
loc: node2.loc,
},
])
const { node: node3 } = parseWithIfTransform(
`<div/>foo<div v-else-if="foo"/>`,
{ onError },
2
2,
)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: node3.loc
}
loc: node3.loc,
},
])
const {
node: { branches }
node: { branches },
} = parseWithIfTransform(
`<div v-if="notOk"/><div v-else/><div v-else-if="ok"/>`,
{ onError },
0
0,
)
expect(onError.mock.calls[3]).toMatchObject([
{
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
loc: branches[branches.length - 1].loc
}
loc: branches[branches.length - 1].loc,
},
])
})
@ -306,21 +306,21 @@ describe('compiler: v-if', () => {
// dynamic
parseWithIfTransform(
`<div v-if="ok" :key="a + 1" /><div v-else :key="a + 1" />`,
{ onError }
{ onError },
)
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_V_IF_SAME_KEY
}
code: ErrorCodes.X_V_IF_SAME_KEY,
},
])
// static
parseWithIfTransform(`<div v-if="ok" key="1" /><div v-else key="1" />`, {
onError
onError,
})
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_V_IF_SAME_KEY
}
code: ErrorCodes.X_V_IF_SAME_KEY,
},
])
})
})
@ -329,63 +329,63 @@ describe('compiler: v-if', () => {
function assertSharedCodegen(
node: IfConditionalExpression,
depth: number = 0,
hasElse: boolean = false
hasElse: boolean = false,
) {
expect(node).toMatchObject({
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
test: {
content: `ok`
content: `ok`,
},
consequent: {
type: NodeTypes.VNODE_CALL,
isBlock: true
isBlock: true,
},
alternate:
depth < 1
? hasElse
? {
type: NodeTypes.VNODE_CALL,
isBlock: true
isBlock: true,
}
: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_COMMENT
callee: CREATE_COMMENT,
}
: {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
test: {
content: `orNot`
content: `orNot`,
},
consequent: {
type: NodeTypes.VNODE_CALL,
isBlock: true
isBlock: true,
},
alternate: hasElse
? {
type: NodeTypes.VNODE_CALL,
isBlock: true
isBlock: true,
}
: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_COMMENT
}
}
callee: CREATE_COMMENT,
},
},
})
}
test('basic v-if', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok"/>`)
assertSharedCodegen(codegenNode)
expect(codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
expect(codegenNode.alternate).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_COMMENT
callee: CREATE_COMMENT,
})
expect(generate(root).code).toMatchSnapshot()
})
@ -393,7 +393,7 @@ describe('compiler: v-if', () => {
test('template v-if', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<template v-if="ok"><div/>hello<p/></template>`)
assertSharedCodegen(codegenNode)
expect(codegenNode.consequent).toMatchObject({
@ -402,12 +402,12 @@ describe('compiler: v-if', () => {
children: [
{ type: NodeTypes.ELEMENT, tag: 'div' },
{ type: NodeTypes.TEXT, content: `hello` },
{ type: NodeTypes.ELEMENT, tag: 'p' }
]
{ type: NodeTypes.ELEMENT, tag: 'p' },
],
})
expect(codegenNode.alternate).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_COMMENT
callee: CREATE_COMMENT,
})
expect(generate(root).code).toMatchSnapshot()
})
@ -415,12 +415,12 @@ describe('compiler: v-if', () => {
test('template v-if w/ single <slot/> child', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<template v-if="ok"><slot/></template>`)
expect(codegenNode.consequent).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -428,12 +428,12 @@ describe('compiler: v-if', () => {
test('v-if on <slot/>', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<slot v-if="ok"></slot>`)
expect(codegenNode.consequent).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -441,16 +441,16 @@ describe('compiler: v-if', () => {
test('v-if + v-else', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok"/><p v-else/>`)
assertSharedCodegen(codegenNode, 0, true)
expect(codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
expect(codegenNode.alternate).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[1]` })
props: createObjectMatcher({ key: `[1]` }),
})
expect(generate(root).code).toMatchSnapshot()
})
@ -458,17 +458,17 @@ describe('compiler: v-if', () => {
test('v-if + v-else-if', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok"/><p v-else-if="orNot" />`)
assertSharedCodegen(codegenNode, 1)
expect(codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
const branch2 = codegenNode.alternate as ConditionalExpression
expect(branch2.consequent).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[1]` })
props: createObjectMatcher({ key: `[1]` }),
})
expect(generate(root).code).toMatchSnapshot()
})
@ -476,19 +476,19 @@ describe('compiler: v-if', () => {
test('v-if + v-else-if + v-else', () => {
const {
root,
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`,
)
assertSharedCodegen(codegenNode, 1, true)
expect(codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
const branch2 = codegenNode.alternate as ConditionalExpression
expect(branch2.consequent).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[1]` })
props: createObjectMatcher({ key: `[1]` }),
})
expect(branch2.alternate).toMatchObject({
tag: FRAGMENT,
@ -496,9 +496,9 @@ describe('compiler: v-if', () => {
children: [
{
type: NodeTypes.TEXT,
content: `fine`
}
]
content: `fine`,
},
],
})
expect(generate(root).code).toMatchSnapshot()
})
@ -508,7 +508,7 @@ describe('compiler: v-if', () => {
`<div v-if="ok"/><p v-if="orNot"/>`,
{},
0 /* returnIndex, just give the default value */,
2 /* childrenLen */
2 /* childrenLen */,
)
const ifNode = root.children[0] as IfNode & {
@ -516,14 +516,14 @@ describe('compiler: v-if', () => {
}
expect(ifNode.codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
const ifNode2 = root.children[1] as IfNode & {
codegenNode: IfConditionalExpression
}
expect(ifNode2.codegenNode.consequent).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[1]` })
props: createObjectMatcher({ key: `[1]` }),
})
expect(generate(root).code).toMatchSnapshot()
})
@ -533,41 +533,41 @@ describe('compiler: v-if', () => {
`<div v-if="ok"/><p v-else/><div v-if="another"/><p v-else-if="orNot"/><p v-else/>`,
{},
0 /* returnIndex, just give the default value */,
2 /* childrenLen */
2 /* childrenLen */,
)
const ifNode = root.children[0] as IfNode & {
codegenNode: IfConditionalExpression
}
expect(ifNode.codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
expect(ifNode.codegenNode.alternate).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[1]` })
props: createObjectMatcher({ key: `[1]` }),
})
const ifNode2 = root.children[1] as IfNode & {
codegenNode: IfConditionalExpression
}
expect(ifNode2.codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[2]` })
props: createObjectMatcher({ key: `[2]` }),
})
const branch = ifNode2.codegenNode.alternate as IfConditionalExpression
expect(branch.consequent).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[3]` })
props: createObjectMatcher({ key: `[3]` }),
})
expect(branch.alternate).toMatchObject({
tag: `"p"`,
props: createObjectMatcher({ key: `[4]` })
props: createObjectMatcher({ key: `[4]` }),
})
expect(generate(root).code).toMatchSnapshot()
})
test('key injection (only v-bind)', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok" v-bind="obj"/>`)
const branch1 = codegenNode.consequent as VNodeCall
expect(branch1.props).toMatchObject({
@ -577,15 +577,18 @@ describe('compiler: v-if', () => {
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: MERGE_PROPS,
arguments: [createObjectMatcher({ key: `[0]` }), { content: `obj` }]
}
]
arguments: [
createObjectMatcher({ key: `[0]` }),
{ content: `obj` },
],
},
],
})
})
test('key injection (before v-bind)', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok" id="foo" v-bind="obj"/>`)
const branch1 = codegenNode.consequent as VNodeCall
expect(branch1.props).toMatchObject({
@ -594,16 +597,16 @@ describe('compiler: v-if', () => {
arguments: [
createObjectMatcher({
key: '[0]',
id: 'foo'
id: 'foo',
}),
{ content: `obj` }
]
{ content: `obj` },
],
})
})
test('key injection (after v-bind)', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok" v-bind="obj" id="foo"/>`)
const branch1 = codegenNode.consequent as VNodeCall
expect(branch1.props).toMatchObject({
@ -613,15 +616,15 @@ describe('compiler: v-if', () => {
createObjectMatcher({ key: `[0]` }),
{ content: `obj` },
createObjectMatcher({
id: 'foo'
})
]
id: 'foo',
}),
],
})
})
test('key injection (w/ custom directive)', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok" v-foo />`)
const branch1 = codegenNode.consequent as VNodeCall
expect(branch1.directives).not.toBeUndefined()
@ -631,7 +634,7 @@ describe('compiler: v-if', () => {
// #6631
test('avoid duplicate keys', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(`<div v-if="ok" key="custom_key" v-bind="obj"/>`)
const branch1 = codegenNode.consequent as VNodeCall
expect(branch1.props).toMatchObject({
@ -639,31 +642,31 @@ describe('compiler: v-if', () => {
callee: MERGE_PROPS,
arguments: [
createObjectMatcher({
key: 'custom_key'
key: 'custom_key',
}),
{ content: `obj` }
]
{ content: `obj` },
],
})
})
test('with spaces between branches', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(
`<div v-if="ok"/> <div v-else-if="no"/> <div v-else/>`
`<div v-if="ok"/> <div v-else-if="no"/> <div v-else/>`,
)
expect(codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[0]` })
props: createObjectMatcher({ key: `[0]` }),
})
const branch = codegenNode.alternate as ConditionalExpression
expect(branch.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[1]` })
props: createObjectMatcher({ key: `[1]` }),
})
expect(branch.alternate).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: `[2]` })
props: createObjectMatcher({ key: `[2]` }),
})
})
@ -729,7 +732,7 @@ describe('compiler: v-if', () => {
<p/>
</template>
`,
{ comments: true }
{ comments: true },
)
__DEV__ = true
})
@ -737,21 +740,21 @@ describe('compiler: v-if', () => {
test('v-on with v-if', () => {
const {
node: { codegenNode }
node: { codegenNode },
} = parseWithIfTransform(
`<button v-on="{ click: clickEvent }" v-if="true">w/ v-if</button>`
`<button v-on="{ click: clickEvent }" v-if="true">w/ v-if</button>`,
)
expect((codegenNode.consequent as any).props.type).toBe(
NodeTypes.JS_CALL_EXPRESSION
NodeTypes.JS_CALL_EXPRESSION,
)
expect((codegenNode.consequent as any).props.callee).toBe(MERGE_PROPS)
expect(
(codegenNode.consequent as any).props.arguments[0].properties[0].value
.content
.content,
).toBe('0')
expect((codegenNode.consequent as any).props.arguments[1].callee).toBe(
TO_HANDLERS
TO_HANDLERS,
)
})
})

View File

@ -4,7 +4,7 @@ describe('compiler: v-memo transform', () => {
function compile(content: string) {
return baseCompile(`<div>${content}</div>`, {
mode: 'module',
prefixIdentifiers: true
prefixIdentifiers: true,
}).code
}
@ -12,8 +12,8 @@ describe('compiler: v-memo transform', () => {
expect(
baseCompile(`<div v-memo="[x]"></div>`, {
mode: 'module',
prefixIdentifiers: true
}).code
prefixIdentifiers: true,
}).code,
).toMatchSnapshot()
})
@ -29,8 +29,8 @@ describe('compiler: v-memo transform', () => {
expect(
compile(
`<div v-if="ok" v-memo="[x]"><span>foo</span>bar</div>
<Comp v-else v-memo="[x]"></Comp>`
)
<Comp v-else v-memo="[x]"></Comp>`,
),
).toMatchSnapshot()
})
@ -39,8 +39,8 @@ describe('compiler: v-memo transform', () => {
compile(
`<div v-for="{ x, y } in list" :key="x" v-memo="[x, y === z]">
<span>foobar</span>
</div>`
)
</div>`,
),
).toMatchSnapshot()
})
@ -49,8 +49,8 @@ describe('compiler: v-memo transform', () => {
compile(
`<template v-for="{ x, y } in list" :key="x" v-memo="[x, y === z]">
<span>foobar</span>
</template>`
)
</template>`,
),
).toMatchSnapshot()
})
})

View File

@ -1,17 +1,17 @@
import {
BindingTypes,
type CompilerOptions,
type ComponentNode,
type ElementNode,
type ForNode,
NORMALIZE_PROPS,
NodeTypes,
type ObjectExpression,
type PlainElementNode,
type VNodeCall,
generate,
baseParse as parse,
transform,
generate,
ElementNode,
ObjectExpression,
CompilerOptions,
ForNode,
PlainElementNode,
ComponentNode,
NodeTypes,
VNodeCall,
NORMALIZE_PROPS,
BindingTypes
} from '../../src'
import { ErrorCodes } from '../../src/errors'
import { transformModel } from '../../src/transforms/vModel'
@ -19,7 +19,7 @@ import { transformElement } from '../../src/transforms/transformElement'
import { transformExpression } from '../../src/transforms/transformExpression'
import { transformFor } from '../../src/transforms/vFor'
import { trackSlotScopes } from '../../src/transforms/vSlot'
import { CallExpression } from '@babel/types'
import type { CallExpression } from '@babel/types'
function parseWithVModel(template: string, options: CompilerOptions = {}) {
const ast = parse(template)
@ -29,13 +29,13 @@ function parseWithVModel(template: string, options: CompilerOptions = {}) {
transformFor,
transformExpression,
transformElement,
trackSlotScopes
trackSlotScopes,
],
directiveTransforms: {
...options.directiveTransforms,
model: transformModel
model: transformModel,
},
...options
...options,
})
return ast
@ -51,29 +51,29 @@ describe('compiler: transform v-model', () => {
expect(props[0]).toMatchObject({
key: {
content: 'modelValue',
isStatic: true
isStatic: true,
},
value: {
content: 'model',
isStatic: false
}
isStatic: false,
},
})
expect(props[1]).toMatchObject({
key: {
content: 'onUpdate:modelValue',
isStatic: true
isStatic: true,
},
value: {
children: [
'$event => ((',
{
content: 'model',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
') = $event)',
],
},
})
expect(generate(root).code).toMatchSnapshot()
@ -81,7 +81,7 @@ describe('compiler: transform v-model', () => {
test('simple expression (with prefixIdentifiers)', () => {
const root = parseWithVModel('<input v-model="model" />', {
prefixIdentifiers: true
prefixIdentifiers: true,
})
const node = root.children[0] as ElementNode
const props = ((node.codegenNode as VNodeCall).props as ObjectExpression)
@ -90,29 +90,29 @@ describe('compiler: transform v-model', () => {
expect(props[0]).toMatchObject({
key: {
content: 'modelValue',
isStatic: true
isStatic: true,
},
value: {
content: '_ctx.model',
isStatic: false
}
isStatic: false,
},
})
expect(props[1]).toMatchObject({
key: {
content: 'onUpdate:modelValue',
isStatic: true
isStatic: true,
},
value: {
children: [
'$event => ((',
{
content: '_ctx.model',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
') = $event)',
],
},
})
expect(generate(root, { mode: 'module' }).code).toMatchSnapshot()
@ -128,29 +128,29 @@ describe('compiler: transform v-model', () => {
expect(props[0]).toMatchObject({
key: {
content: 'modelValue',
isStatic: true
isStatic: true,
},
value: {
content: '\n model\n.\nfoo \n',
isStatic: false
}
isStatic: false,
},
})
expect(props[1]).toMatchObject({
key: {
content: 'onUpdate:modelValue',
isStatic: true
isStatic: true,
},
value: {
children: [
'$event => ((',
{
content: '\n model\n.\nfoo \n',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
') = $event)',
],
},
})
expect(generate(root).code).toMatchSnapshot()
@ -165,29 +165,29 @@ describe('compiler: transform v-model', () => {
expect(props[0]).toMatchObject({
key: {
content: 'modelValue',
isStatic: true
isStatic: true,
},
value: {
content: 'model[index]',
isStatic: false
}
isStatic: false,
},
})
expect(props[1]).toMatchObject({
key: {
content: 'onUpdate:modelValue',
isStatic: true
isStatic: true,
},
value: {
children: [
'$event => ((',
{
content: 'model[index]',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
') = $event)',
],
},
})
expect(generate(root).code).toMatchSnapshot()
@ -195,7 +195,7 @@ describe('compiler: transform v-model', () => {
test('compound expression (with prefixIdentifiers)', () => {
const root = parseWithVModel('<input v-model="model[index]" />', {
prefixIdentifiers: true
prefixIdentifiers: true,
})
const node = root.children[0] as ElementNode
const props = ((node.codegenNode as VNodeCall).props as ObjectExpression)
@ -204,28 +204,28 @@ describe('compiler: transform v-model', () => {
expect(props[0]).toMatchObject({
key: {
content: 'modelValue',
isStatic: true
isStatic: true,
},
value: {
children: [
{
content: '_ctx.model',
isStatic: false
isStatic: false,
},
'[',
{
content: '_ctx.index',
isStatic: false
isStatic: false,
},
']'
]
}
']',
],
},
})
expect(props[1]).toMatchObject({
key: {
content: 'onUpdate:modelValue',
isStatic: true
isStatic: true,
},
value: {
children: [
@ -234,19 +234,19 @@ describe('compiler: transform v-model', () => {
children: [
{
content: '_ctx.model',
isStatic: false
isStatic: false,
},
'[',
{
content: '_ctx.index',
isStatic: false
isStatic: false,
},
']'
]
']',
],
},
') = $event)'
]
}
') = $event)',
],
},
})
expect(generate(root, { mode: 'module' }).code).toMatchSnapshot()
@ -260,29 +260,29 @@ describe('compiler: transform v-model', () => {
expect(props[0]).toMatchObject({
key: {
content: 'foo-value',
isStatic: true
isStatic: true,
},
value: {
content: 'model',
isStatic: false
}
isStatic: false,
},
})
expect(props[1]).toMatchObject({
key: {
content: 'onUpdate:fooValue',
isStatic: true
isStatic: true,
},
value: {
children: [
'$event => ((',
{
content: 'model',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
') = $event)',
],
},
})
expect(generate(root).code).toMatchSnapshot()
@ -304,12 +304,12 @@ describe('compiler: transform v-model', () => {
{
key: {
content: 'value',
isStatic: false
isStatic: false,
},
value: {
content: 'model',
isStatic: false
}
isStatic: false,
},
},
{
key: {
@ -317,24 +317,24 @@ describe('compiler: transform v-model', () => {
'"onUpdate:" + ',
{
content: 'value',
isStatic: false
}
]
isStatic: false,
},
],
},
value: {
children: [
'$event => ((',
{
content: 'model',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
}
]
}
]
') = $event)',
],
},
},
],
},
],
})
expect(generate(root).code).toMatchSnapshot()
@ -342,7 +342,7 @@ describe('compiler: transform v-model', () => {
test('with dynamic argument (with prefixIdentifiers)', () => {
const root = parseWithVModel('<input v-model:[value]="model" />', {
prefixIdentifiers: true
prefixIdentifiers: true,
})
const node = root.children[0] as ElementNode
const props = (node.codegenNode as VNodeCall)
@ -358,12 +358,12 @@ describe('compiler: transform v-model', () => {
{
key: {
content: '_ctx.value',
isStatic: false
isStatic: false,
},
value: {
content: '_ctx.model',
isStatic: false
}
isStatic: false,
},
},
{
key: {
@ -371,24 +371,24 @@ describe('compiler: transform v-model', () => {
'"onUpdate:" + ',
{
content: '_ctx.value',
isStatic: false
}
]
isStatic: false,
},
],
},
value: {
children: [
'$event => ((',
{
content: '_ctx.model',
isStatic: false
isStatic: false,
},
') = $event)'
]
}
}
]
}
]
') = $event)',
],
},
},
],
},
],
})
expect(generate(root, { mode: 'module' }).code).toMatchSnapshot()
@ -397,7 +397,7 @@ describe('compiler: transform v-model', () => {
test('should cache update handler w/ cacheHandlers: true', () => {
const root = parseWithVModel('<input v-model="foo" />', {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
const codegen = (root.children[0] as PlainElementNode)
@ -405,7 +405,7 @@ describe('compiler: transform v-model', () => {
// should not list cached prop in dynamicProps
expect(codegen.dynamicProps).toBe(`["modelValue"]`)
expect((codegen.props as ObjectExpression).properties[1].value.type).toBe(
NodeTypes.JS_CACHE_EXPRESSION
NodeTypes.JS_CACHE_EXPRESSION,
)
})
@ -414,8 +414,8 @@ describe('compiler: transform v-model', () => {
'<input v-for="i in list" v-model="foo[i]" />',
{
prefixIdentifiers: true,
cacheHandlers: true
}
cacheHandlers: true,
},
)
expect(root.cached).toBe(0)
const codegen = (
@ -423,14 +423,14 @@ describe('compiler: transform v-model', () => {
).codegenNode as VNodeCall
expect(codegen.dynamicProps).toBe(`["modelValue", "onUpdate:modelValue"]`)
expect(
(codegen.props as ObjectExpression).properties[1].value.type
(codegen.props as ObjectExpression).properties[1].value.type,
).not.toBe(NodeTypes.JS_CACHE_EXPRESSION)
})
test('should not cache update handler if it inside v-once', () => {
const root = parseWithVModel('<div v-once><input v-model="foo" /></div>', {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).not.toBe(2)
expect(root.cached).toBe(1)
@ -440,8 +440,8 @@ describe('compiler: transform v-model', () => {
const root = parseWithVModel(
'<Comp v-slot="{ foo }"><input v-model="foo.bar"/></Comp>',
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
const codegen = (
(root.children[0] as ComponentNode).children[0] as PlainElementNode
@ -451,7 +451,7 @@ describe('compiler: transform v-model', () => {
test('should generate modelModifiers for component v-model', () => {
const root = parseWithVModel('<Comp v-model.trim.bar-baz="foo" />', {
prefixIdentifiers: true
prefixIdentifiers: true,
})
const vnodeCall = (root.children[0] as ComponentNode)
.codegenNode as VNodeCall
@ -462,9 +462,12 @@ describe('compiler: transform v-model', () => {
{ key: { content: `onUpdate:modelValue` } },
{
key: { content: 'modelModifiers' },
value: { content: `{ trim: true, "bar-baz": true }`, isStatic: false }
}
]
value: {
content: `{ trim: true, "bar-baz": true }`,
isStatic: false,
},
},
],
})
// should NOT include modelModifiers in dynamicPropNames because it's never
// gonna change
@ -475,8 +478,8 @@ describe('compiler: transform v-model', () => {
const root = parseWithVModel(
'<Comp v-model:foo.trim="foo" v-model:bar.number="bar" />',
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
const vnodeCall = (root.children[0] as ComponentNode)
.codegenNode as VNodeCall
@ -487,20 +490,20 @@ describe('compiler: transform v-model', () => {
{ key: { content: `onUpdate:foo` } },
{
key: { content: 'fooModifiers' },
value: { content: `{ trim: true }`, isStatic: false }
value: { content: `{ trim: true }`, isStatic: false },
},
{ key: { content: `bar` } },
{ key: { content: `onUpdate:bar` } },
{
key: { content: 'barModifiers' },
value: { content: `{ number: true }`, isStatic: false }
}
]
value: { content: `{ number: true }`, isStatic: false },
},
],
})
// should NOT include modelModifiers in dynamicPropNames because it's never
// gonna change
expect(vnodeCall.dynamicProps).toBe(
`["foo", "onUpdate:foo", "bar", "onUpdate:bar"]`
`["foo", "onUpdate:foo", "bar", "onUpdate:bar"]`,
)
})
@ -512,8 +515,8 @@ describe('compiler: transform v-model', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_NO_EXPRESSION
})
code: ErrorCodes.X_V_MODEL_NO_EXPRESSION,
}),
)
})
@ -524,8 +527,8 @@ describe('compiler: transform v-model', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION
})
code: ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION,
}),
)
})
@ -536,8 +539,8 @@ describe('compiler: transform v-model', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION
})
code: ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION,
}),
)
})
@ -552,14 +555,14 @@ describe('compiler: transform v-model', () => {
const onError = vi.fn()
parseWithVModel('<span v-for="i in list" v-model="i" />', {
onError,
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE
})
code: ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE,
}),
)
})
@ -568,15 +571,15 @@ describe('compiler: transform v-model', () => {
parseWithVModel('<div v-model="p" />', {
onError,
bindingMetadata: {
p: BindingTypes.PROPS
}
p: BindingTypes.PROPS,
},
})
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_ON_PROPS
})
code: ErrorCodes.X_V_MODEL_ON_PROPS,
}),
)
})
})

View File

@ -1,14 +1,14 @@
import {
baseParse as parse,
CompilerOptions,
ElementNode,
type CompilerOptions,
type ElementNode,
ErrorCodes,
TO_HANDLER_KEY,
helperNameMap,
NodeTypes,
ObjectExpression,
type ObjectExpression,
TO_HANDLER_KEY,
type VNodeCall,
helperNameMap,
baseParse as parse,
transform,
VNodeCall
} from '../../src'
import { transformOn } from '../../src/transforms/vOn'
import { transformElement } from '../../src/transforms/transformElement'
@ -19,13 +19,13 @@ function parseWithVOn(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms: [transformExpression, transformElement],
directiveTransforms: {
on: transformOn
on: transformOn,
},
...options
...options,
})
return {
root: ast,
node: ast.children[0] as ElementNode
node: ast.children[0] as ElementNode,
}
}
@ -41,13 +41,13 @@ describe('compiler: transform v-on', () => {
loc: {
start: {
line: 1,
column: 11
column: 11,
},
end: {
line: 1,
column: 16
}
}
column: 16,
},
},
},
value: {
content: `onClick`,
@ -55,16 +55,16 @@ describe('compiler: transform v-on', () => {
loc: {
start: {
line: 1,
column: 18
column: 18,
},
end: {
line: 1,
column: 25
}
}
}
}
]
column: 25,
},
},
},
},
],
})
})
@ -78,22 +78,22 @@ describe('compiler: transform v-on', () => {
children: [
`_${helperNameMap[TO_HANDLER_KEY]}(`,
{ content: `event` },
`)`
]
`)`,
],
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `handler`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
})
})
test('dynamic arg with prefixing', () => {
const { node } = parseWithVOn(`<div v-on:[event]="handler"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -103,22 +103,22 @@ describe('compiler: transform v-on', () => {
children: [
`_${helperNameMap[TO_HANDLER_KEY]}(`,
{ content: `_ctx.event` },
`)`
]
`)`,
],
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.handler`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
})
})
test('dynamic arg with complex exp prefixing', () => {
const { node } = parseWithVOn(`<div v-on:[event(foo)]="handler"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -131,16 +131,16 @@ describe('compiler: transform v-on', () => {
`(`,
{ content: `_ctx.foo` },
`)`,
`)`
]
`)`,
],
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.handler`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
})
})
@ -152,10 +152,10 @@ describe('compiler: transform v-on', () => {
key: { content: `onClick` },
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`$event => (`, { content: `i++` }, `)`]
}
}
]
children: [`$event => (`, { content: `i++` }, `)`],
},
},
],
})
})
@ -170,10 +170,10 @@ describe('compiler: transform v-on', () => {
// should wrap with `{` for multiple statements
// in this case the return value is discarded and the behavior is
// consistent with 2.x
children: [`$event => {`, { content: `foo();bar()` }, `}`]
}
}
]
children: [`$event => {`, { content: `foo();bar()` }, `}`],
},
},
],
})
})
@ -188,16 +188,16 @@ describe('compiler: transform v-on', () => {
// should wrap with `{` for multiple statements
// in this case the return value is discarded and the behavior is
// consistent with 2.x
children: [`$event => {`, { content: `\nfoo();\nbar()\n` }, `}`]
}
}
]
children: [`$event => {`, { content: `\nfoo();\nbar()\n` }, `}`],
},
},
],
})
})
test('inline statement w/ prefixIdentifiers: true', () => {
const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -214,20 +214,20 @@ describe('compiler: transform v-on', () => {
`(`,
// should NOT prefix $event
{ content: `$event` },
`)`
]
`)`,
],
},
`)`
]
}
}
]
`)`,
],
},
},
],
})
})
test('multiple inline statements w/ prefixIdentifiers: true', () => {
const { node } = parseWithVOn(`<div @click="foo($event);bar()"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -245,14 +245,14 @@ describe('compiler: transform v-on', () => {
{ content: `$event` },
`);`,
{ content: `_ctx.bar` },
`()`
]
`()`,
],
},
`}`
]
}
}
]
`}`,
],
},
},
],
})
})
@ -264,10 +264,10 @@ describe('compiler: transform v-on', () => {
key: { content: `onClick` },
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `$event => foo($event)`
}
}
]
content: `$event => foo($event)`,
},
},
],
})
})
@ -279,10 +279,10 @@ describe('compiler: transform v-on', () => {
key: { content: `onClick` },
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `(e: any): any => foo(e)`
}
}
]
content: `(e: any): any => foo(e)`,
},
},
],
})
})
@ -292,7 +292,7 @@ describe('compiler: transform v-on', () => {
$event => {
foo($event)
}
"/>`
"/>`,
)
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -304,10 +304,10 @@ describe('compiler: transform v-on', () => {
$event => {
foo($event)
}
`
}
}
]
`,
},
},
],
})
})
@ -317,7 +317,7 @@ describe('compiler: transform v-on', () => {
function($event) {
foo($event)
}
"/>`
"/>`,
)
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -329,10 +329,10 @@ describe('compiler: transform v-on', () => {
function($event) {
foo($event)
}
`
}
}
]
`,
},
},
],
})
})
@ -344,16 +344,16 @@ describe('compiler: transform v-on', () => {
key: { content: `onClick` },
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `a['b' + c]`
}
}
]
content: `a['b' + c]`,
},
},
],
})
})
test('complex member expression w/ prefixIdentifiers: true', () => {
const { node } = parseWithVOn(`<div @click="a['b' + c]"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -365,17 +365,17 @@ describe('compiler: transform v-on', () => {
{ content: `_ctx.a` },
`['b' + `,
{ content: `_ctx.c` },
`]`
]
}
}
]
`]`,
],
},
},
],
})
})
test('function expression w/ prefixIdentifiers: true', () => {
const { node } = parseWithVOn(`<div @click="e => foo(e)"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
@ -389,11 +389,11 @@ describe('compiler: transform v-on', () => {
{ content: `_ctx.foo` },
`(`,
{ content: `e` },
`)`
]
}
}
]
`)`,
],
},
},
],
})
})
@ -405,13 +405,13 @@ describe('compiler: transform v-on', () => {
loc: {
start: {
line: 1,
column: 6
column: 6,
},
end: {
line: 1,
column: 16
}
}
column: 16,
},
},
})
})
@ -427,13 +427,13 @@ describe('compiler: transform v-on', () => {
properties: [
{
key: {
content: `onFooBar`
content: `onFooBar`,
},
value: {
content: `onMount`
}
}
]
content: `onMount`,
},
},
],
})
})
@ -445,39 +445,39 @@ describe('compiler: transform v-on', () => {
loc: {
start: {
line: 1,
column: 11
column: 11,
},
end: {
line: 1,
column: 24
}
}
column: 24,
},
},
})
})
test('vue: prefixed events', () => {
const { node } = parseWithVOn(
`<div v-on:vue:mounted="onMount" @vue:before-update="onBeforeUpdate" />`
`<div v-on:vue:mounted="onMount" @vue:before-update="onBeforeUpdate" />`,
)
expect((node.codegenNode as VNodeCall).props).toMatchObject({
properties: [
{
key: {
content: `onVnodeMounted`
content: `onVnodeMounted`,
},
value: {
content: `onMount`
}
content: `onMount`,
},
},
{
key: {
content: `onVnodeBeforeUpdate`
content: `onVnodeBeforeUpdate`,
},
value: {
content: `onBeforeUpdate`
}
}
]
content: `onBeforeUpdate`,
},
},
],
})
})
@ -485,35 +485,35 @@ describe('compiler: transform v-on', () => {
test('empty handler', () => {
const { root, node } = parseWithVOn(`<div v-on:click.prevent />`, {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
const vnodeCall = node.codegenNode as VNodeCall
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `() => {}`
}
content: `() => {}`,
},
})
})
test('member expression handler', () => {
const { root, node } = parseWithVOn(`<div v-on:click="foo" />`, {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
const vnodeCall = node.codegenNode as VNodeCall
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
@ -522,23 +522,23 @@ describe('compiler: transform v-on', () => {
children: [
`(...args) => (`,
{ content: `_ctx.foo && _ctx.foo(...args)` },
`)`
]
}
`)`,
],
},
})
})
test('compound member expression handler', () => {
const { root, node } = parseWithVOn(`<div v-on:click="foo.bar" />`, {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
const vnodeCall = node.codegenNode as VNodeCall
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
@ -555,12 +555,12 @@ describe('compiler: transform v-on', () => {
{ content: `_ctx.foo` },
`.`,
{ content: `bar` },
`(...args)`
]
`(...args)`,
],
},
`)`
]
}
`)`,
],
},
})
})
@ -568,7 +568,7 @@ describe('compiler: transform v-on', () => {
const { root } = parseWithVOn(`<comp v-on:click="foo" />`, {
prefixIdentifiers: true,
cacheHandlers: true,
isNativeTag: tag => tag === 'div'
isNativeTag: tag => tag === 'div',
})
expect(root.cached).toBe(0)
})
@ -578,8 +578,8 @@ describe('compiler: transform v-on', () => {
`<div v-once><div v-on:click="foo"/></div>`,
{
prefixIdentifiers: true,
cacheHandlers: true
}
cacheHandlers: true,
},
)
expect(root.cached).not.toBe(2)
expect(root.cached).toBe(1)
@ -588,21 +588,21 @@ describe('compiler: transform v-on', () => {
test('inline function expression handler', () => {
const { root, node } = parseWithVOn(`<div v-on:click="() => foo()" />`, {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
const vnodeCall = node.codegenNode as VNodeCall
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`() => `, { content: `_ctx.foo` }, `()`]
}
children: [`() => `, { content: `_ctx.foo` }, `()`],
},
})
})
@ -611,22 +611,22 @@ describe('compiler: transform v-on', () => {
`<div v-on:click="async () => await foo()" />`,
{
prefixIdentifiers: true,
cacheHandlers: true
}
cacheHandlers: true,
},
)
expect(root.cached).toBe(1)
const vnodeCall = node.codegenNode as VNodeCall
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`async () => await `, { content: `_ctx.foo` }, `()`]
}
children: [`async () => await `, { content: `_ctx.foo` }, `()`],
},
})
})
@ -635,15 +635,15 @@ describe('compiler: transform v-on', () => {
`<div v-on:click="async function () { await foo() } " />`,
{
prefixIdentifiers: true,
cacheHandlers: true
}
cacheHandlers: true,
},
)
expect(root.cached).toBe(1)
const vnodeCall = node.codegenNode as VNodeCall
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
@ -652,16 +652,16 @@ describe('compiler: transform v-on', () => {
children: [
`async function () { await `,
{ content: `_ctx.foo` },
`() } `
]
}
`() } `,
],
},
})
})
test('inline statement handler', () => {
const { root, node } = parseWithVOn(`<div v-on:click="foo++" />`, {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
expect(root.cached).toBe(1)
@ -669,7 +669,7 @@ describe('compiler: transform v-on', () => {
// should not treat cached handler as dynamicProp, so no flags
expect(vnodeCall.patchFlag).toBeUndefined()
expect(
(vnodeCall.props as ObjectExpression).properties[0].value
(vnodeCall.props as ObjectExpression).properties[0].value,
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
@ -678,9 +678,9 @@ describe('compiler: transform v-on', () => {
children: [
`$event => (`,
{ children: [{ content: `_ctx.foo` }, `++`] },
`)`
]
}
`)`,
],
},
})
})
})

View File

@ -1,10 +1,10 @@
import {
baseParse as parse,
transform,
type CompilerOptions,
NodeTypes,
generate,
CompilerOptions,
getBaseTransformPreset
getBaseTransformPreset,
baseParse as parse,
transform,
} from '../../src'
import { RENDER_SLOT, SET_BLOCK_TRACKING } from '../../src/runtimeHelpers'
@ -14,7 +14,7 @@ function transformWithOnce(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms,
directiveTransforms,
...options
...options,
})
return ast
}
@ -29,8 +29,8 @@ describe('compiler: v-once transform', () => {
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
}
tag: `"div"`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -44,8 +44,8 @@ describe('compiler: v-once transform', () => {
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
}
tag: `"div"`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -59,8 +59,8 @@ describe('compiler: v-once transform', () => {
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `_component_Comp`
}
tag: `_component_Comp`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -74,8 +74,8 @@ describe('compiler: v-once transform', () => {
index: 0,
value: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT
}
callee: RENDER_SLOT,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -90,7 +90,7 @@ describe('compiler: v-once transform', () => {
// cached nodes should be ignored by hoistStatic transform
test('with hoistStatic: true', () => {
const root = transformWithOnce(`<div><div v-once /></div>`, {
hoistStatic: true
hoistStatic: true,
})
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
@ -100,8 +100,8 @@ describe('compiler: v-once transform', () => {
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
}
tag: `"div"`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
@ -119,14 +119,14 @@ describe('compiler: v-once transform', () => {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
consequent: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
tag: `"div"`,
},
alternate: {
type: NodeTypes.VNODE_CALL,
tag: `"p"`
}
}
}
tag: `"p"`,
},
},
},
})
})
@ -138,8 +138,8 @@ describe('compiler: v-once transform', () => {
type: NodeTypes.FOR,
// should cache the entire v-for expression, not just a single branch
codegenNode: {
type: NodeTypes.JS_CACHE_EXPRESSION
}
type: NodeTypes.JS_CACHE_EXPRESSION,
},
})
})
})

View File

@ -1,18 +1,18 @@
import {
CompilerOptions,
type CompilerOptions,
type ComponentNode,
type ElementNode,
ErrorCodes,
type ForNode,
NodeTypes,
type ObjectExpression,
type RenderSlotCall,
type SimpleExpressionNode,
type SlotsExpression,
type VNodeCall,
generate,
baseParse as parse,
transform,
generate,
ElementNode,
NodeTypes,
ErrorCodes,
ForNode,
ComponentNode,
VNodeCall,
SlotsExpression,
ObjectExpression,
SimpleExpressionNode,
RenderSlotCall
} from '../../src'
import { transformElement } from '../../src/transforms/transformElement'
import { transformOn } from '../../src/transforms/vOn'
@ -21,7 +21,7 @@ import { transformExpression } from '../../src/transforms/transformExpression'
import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet'
import {
trackSlotScopes,
trackVForSlotScopes
trackVForSlotScopes,
} from '../../src/transforms/vSlot'
import { CREATE_SLOTS, RENDER_LIST } from '../../src/runtimeHelpers'
import { createObjectMatcher, genFlagText } from '../testUtils'
@ -31,7 +31,7 @@ import { transformIf } from '../../src/transforms/vIf'
function parseWithSlots(template: string, options: CompilerOptions = {}) {
const ast = parse(template, {
whitespace: options.whitespace
whitespace: options.whitespace,
})
transform(ast, {
nodeTransforms: [
@ -42,13 +42,13 @@ function parseWithSlots(template: string, options: CompilerOptions = {}) {
: []),
transformSlotOutlet,
transformElement,
trackSlotScopes
trackSlotScopes,
],
directiveTransforms: {
on: transformOn,
bind: transformBind
bind: transformBind,
},
...options
...options,
})
return {
root: ast,
@ -56,7 +56,7 @@ function parseWithSlots(template: string, options: CompilerOptions = {}) {
ast.children[0].type === NodeTypes.ELEMENT
? ((ast.children[0].codegenNode as VNodeCall)
.children as SlotsExpression)
: null
: null,
}
}
@ -70,25 +70,25 @@ function createSlotMatcher(obj: Record<string, any>, isDynamic = false) {
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
isStatic: !/^\[/.test(key),
content: key.replace(/^\[|\]$/g, '')
content: key.replace(/^\[|\]$/g, ''),
},
value: obj[key]
value: obj[key],
} as any
})
.concat({
key: { content: `_` },
value: {
content: isDynamic ? `2 /* DYNAMIC */` : `1 /* STABLE */`,
isStatic: false
}
})
isStatic: false,
},
}),
}
}
describe('compiler: transform component slots', () => {
test('implicit default slot', () => {
const { root, slots } = parseWithSlots(`<Comp><div/></Comp>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(slots).toMatchObject(
createSlotMatcher({
@ -98,11 +98,11 @@ describe('compiler: transform component slots', () => {
returns: [
{
type: NodeTypes.ELEMENT,
tag: `div`
}
]
}
})
tag: `div`,
},
],
},
}),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -110,7 +110,7 @@ describe('compiler: transform component slots', () => {
test('on-component default slot', () => {
const { root, slots } = parseWithSlots(
`<Comp v-slot="{ foo }">{{ foo }}{{ bar }}</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject(
createSlotMatcher({
@ -118,24 +118,24 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
children: [`{ `, { content: `foo` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`
}
}
]
}
})
content: `_ctx.bar`,
},
},
],
},
}),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -143,7 +143,7 @@ describe('compiler: transform component slots', () => {
test('on component named slot', () => {
const { root, slots } = parseWithSlots(
`<Comp v-slot:named="{ foo }">{{ foo }}{{ bar }}</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject(
createSlotMatcher({
@ -151,24 +151,24 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
children: [`{ `, { content: `foo` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`
}
}
]
}
})
content: `_ctx.bar`,
},
},
],
},
}),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -183,7 +183,7 @@ describe('compiler: transform component slots', () => {
{{ foo }}{{ bar }}
</template>
</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject(
createSlotMatcher({
@ -191,45 +191,45 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
children: [`{ `, { content: `foo` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`
}
}
]
content: `_ctx.bar`,
},
},
],
},
two: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `bar` }, ` }`]
children: [`{ `, { content: `bar` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.foo`
}
content: `_ctx.foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `bar`
}
}
]
}
})
content: `bar`,
},
},
],
},
}),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -237,7 +237,7 @@ describe('compiler: transform component slots', () => {
test('on component dynamically named slot', () => {
const { root, slots } = parseWithSlots(
`<Comp v-slot:[named]="{ foo }">{{ foo }}{{ bar }}</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject(
createSlotMatcher(
@ -246,26 +246,26 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
children: [`{ `, { content: `foo` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`
}
}
]
}
content: `_ctx.bar`,
},
},
],
},
},
true
)
true,
),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -274,7 +274,7 @@ describe('compiler: transform component slots', () => {
const { root, slots } = parseWithSlots(
`<Comp>
<template #one>foo</template>bar<span/>
</Comp>`
</Comp>`,
)
expect(slots).toMatchObject(
createSlotMatcher({
@ -284,9 +284,9 @@ describe('compiler: transform component slots', () => {
returns: [
{
type: NodeTypes.TEXT,
content: `foo`
}
]
content: `foo`,
},
],
},
default: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
@ -294,15 +294,15 @@ describe('compiler: transform component slots', () => {
returns: [
{
type: NodeTypes.TEXT,
content: `bar`
content: `bar`,
},
{
type: NodeTypes.ELEMENT,
tag: `span`
}
]
}
})
tag: `span`,
},
],
},
}),
)
expect(generate(root).code).toMatchSnapshot()
})
@ -317,7 +317,7 @@ describe('compiler: transform component slots', () => {
{{ foo }}{{ bar }}
</template>
</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject(
createSlotMatcher(
@ -326,47 +326,47 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
children: [`{ `, { content: `foo` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`
}
}
]
content: `_ctx.bar`,
},
},
],
},
'[_ctx.two]': {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `bar` }, ` }`]
children: [`{ `, { content: `bar` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.foo`
}
content: `_ctx.foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `bar`
}
}
]
}
content: `bar`,
},
},
],
},
},
true
)
true,
),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -381,7 +381,7 @@ describe('compiler: transform component slots', () => {
{{ foo }}{{ bar }}{{ baz }}
</template>
</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject(
createSlotMatcher({
@ -389,7 +389,7 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
children: [`{ `, { content: `foo` }, ` }`],
},
returns: [
{
@ -404,63 +404,63 @@ describe('compiler: transform component slots', () => {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `bar` }, ` }`]
children: [`{ `, { content: `bar` }, ` }`],
},
returns: [
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `bar`
}
content: `bar`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.baz`
}
}
]
}
content: `_ctx.baz`,
},
},
],
},
},
true
true,
),
// nested slot should be forced dynamic, since scope variables
// are not tracked as dependencies of the slot.
patchFlag: genFlagText(PatchFlags.DYNAMIC_SLOTS)
}
patchFlag: genFlagText(PatchFlags.DYNAMIC_SLOTS),
},
},
// test scope
{
type: NodeTypes.TEXT,
content: ` `
content: ` `,
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `foo`
}
content: `foo`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.bar`
}
content: `_ctx.bar`,
},
},
{
type: NodeTypes.INTERPOLATION,
content: {
content: `_ctx.baz`
}
}
]
}
})
content: `_ctx.baz`,
},
},
],
},
}),
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -469,13 +469,13 @@ describe('compiler: transform component slots', () => {
const { root } = parseWithSlots(
`<div v-for="i in list">
<Comp v-slot="bar">foo</Comp>
</div>`
</div>`,
)
const div = ((root.children[0] as ForNode).children[0] as ElementNode)
.codegenNode as any
const comp = div.children[0]
expect(comp.codegenNode.patchFlag).toBe(
genFlagText(PatchFlags.DYNAMIC_SLOTS)
genFlagText(PatchFlags.DYNAMIC_SLOTS),
)
})
@ -504,14 +504,14 @@ describe('compiler: transform component slots', () => {
`<div v-for="i in list">
<Comp v-slot="bar">foo</Comp>
</div>`,
false
false,
)
assertDynamicSlots(
`<div v-for="i in list">
<Comp v-slot="bar">{{ i }}</Comp>
</div>`,
true
true,
)
// reference the component's own slot variable should not force dynamic slots
@ -519,14 +519,14 @@ describe('compiler: transform component slots', () => {
`<Comp v-slot="foo">
<Comp v-slot="bar">{{ bar }}</Comp>
</Comp>`,
false
false,
)
assertDynamicSlots(
`<Comp v-slot="foo">
<Comp v-slot="bar">{{ foo }}</Comp>
</Comp>`,
true
true,
)
// #2564
@ -534,14 +534,14 @@ describe('compiler: transform component slots', () => {
`<div v-for="i in list">
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
</div>`,
true
true,
)
assertDynamicSlots(
`<div v-for="i in list">
<Comp v-slot="bar"><button @click="fn()" /></Comp>
</div>`,
false
false,
)
})
@ -549,14 +549,14 @@ describe('compiler: transform component slots', () => {
const { root, slots } = parseWithSlots(
`<Comp>
<template #one v-if="ok">hello</template>
</Comp>`
</Comp>`,
)
expect(slots).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_SLOTS,
arguments: [
createObjectMatcher({
_: `[2 /* DYNAMIC */]`
_: `[2 /* DYNAMIC */]`,
}),
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
@ -568,21 +568,21 @@ describe('compiler: transform component slots', () => {
name: `one`,
fn: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
returns: [{ type: NodeTypes.TEXT, content: `hello` }]
returns: [{ type: NodeTypes.TEXT, content: `hello` }],
},
key: `0`
key: `0`,
}),
alternate: {
content: `undefined`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
expect((root as any).children[0].codegenNode.patchFlag).toMatch(
PatchFlags.DYNAMIC_SLOTS + ''
PatchFlags.DYNAMIC_SLOTS + '',
)
expect(generate(root).code).toMatchSnapshot()
})
@ -592,14 +592,14 @@ describe('compiler: transform component slots', () => {
`<Comp>
<template #one="props" v-if="ok">{{ props }}</template>
</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_SLOTS,
arguments: [
createObjectMatcher({
_: `[2 /* DYNAMIC */]`
_: `[2 /* DYNAMIC */]`,
}),
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
@ -615,23 +615,23 @@ describe('compiler: transform component slots', () => {
returns: [
{
type: NodeTypes.INTERPOLATION,
content: { content: `props` }
}
]
content: { content: `props` },
},
],
},
key: `0`
key: `0`,
}),
alternate: {
content: `undefined`,
isStatic: false
}
}
]
}
]
isStatic: false,
},
},
],
},
],
})
expect((root as any).children[0].codegenNode.patchFlag).toMatch(
PatchFlags.DYNAMIC_SLOTS + ''
PatchFlags.DYNAMIC_SLOTS + '',
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -642,14 +642,14 @@ describe('compiler: transform component slots', () => {
<template #one v-if="ok">foo</template>
<template #two="props" v-else-if="orNot">bar</template>
<template #one v-else>baz</template>
</Comp>`
</Comp>`,
)
expect(slots).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_SLOTS,
arguments: [
createObjectMatcher({
_: `[2 /* DYNAMIC */]`
_: `[2 /* DYNAMIC */]`,
}),
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
@ -662,9 +662,9 @@ describe('compiler: transform component slots', () => {
fn: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: undefined,
returns: [{ type: NodeTypes.TEXT, content: `foo` }]
returns: [{ type: NodeTypes.TEXT, content: `foo` }],
},
key: `0`
key: `0`,
}),
alternate: {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
@ -674,27 +674,27 @@ describe('compiler: transform component slots', () => {
fn: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: { content: `props` },
returns: [{ type: NodeTypes.TEXT, content: `bar` }]
returns: [{ type: NodeTypes.TEXT, content: `bar` }],
},
key: `1`
key: `1`,
}),
alternate: createObjectMatcher({
name: `one`,
fn: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: undefined,
returns: [{ type: NodeTypes.TEXT, content: `baz` }]
returns: [{ type: NodeTypes.TEXT, content: `baz` }],
},
key: `2`
})
}
}
]
}
]
key: `2`,
}),
},
},
],
},
],
})
expect((root as any).children[0].codegenNode.patchFlag).toMatch(
PatchFlags.DYNAMIC_SLOTS + ''
PatchFlags.DYNAMIC_SLOTS + '',
)
expect(generate(root).code).toMatchSnapshot()
})
@ -704,14 +704,14 @@ describe('compiler: transform component slots', () => {
`<Comp>
<template v-for="name in list" #[name]>{{ name }}</template>
</Comp>`,
{ prefixIdentifiers: true }
{ prefixIdentifiers: true },
)
expect(slots).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_SLOTS,
arguments: [
createObjectMatcher({
_: `[2 /* DYNAMIC */]`
_: `[2 /* DYNAMIC */]`,
}),
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
@ -731,20 +731,20 @@ describe('compiler: transform component slots', () => {
returns: [
{
type: NodeTypes.INTERPOLATION,
content: { content: `name`, isStatic: false }
}
]
}
})
}
]
}
]
}
]
content: { content: `name`, isStatic: false },
},
],
},
}),
},
],
},
],
},
],
})
expect((root as any).children[0].codegenNode.patchFlag).toMatch(
PatchFlags.DYNAMIC_SLOTS + ''
PatchFlags.DYNAMIC_SLOTS + '',
)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -755,13 +755,13 @@ describe('compiler: transform component slots', () => {
properties: [
{
key: { content: `default` },
value: { type: NodeTypes.JS_FUNCTION_EXPRESSION }
value: { type: NodeTypes.JS_FUNCTION_EXPRESSION },
},
{
key: { content: `_` },
value: { content: `3 /* FORWARDED */` }
}
]
value: { content: `3 /* FORWARDED */` },
},
],
}
test('<slot> tag only', () => {
const { slots } = parseWithSlots(`<Comp><slot/></Comp>`)
@ -780,7 +780,7 @@ describe('compiler: transform component slots', () => {
test('<slot> tag w/ template', () => {
const { slots } = parseWithSlots(
`<Comp><template #default><slot/></template></Comp>`
`<Comp><template #default><slot/></template></Comp>`,
)
expect(slots).toMatchObject(toMatch)
})
@ -793,7 +793,7 @@ describe('compiler: transform component slots', () => {
// # fix: #6900
test('consistent behavior of @xxx:modelValue and @xxx:model-value', () => {
const { root: rootUpper } = parseWithSlots(
`<div><slot @foo:modelValue="handler" /></div>`
`<div><slot @foo:modelValue="handler" /></div>`,
)
const slotNodeUpper = (rootUpper.codegenNode! as VNodeCall)
.children as ElementNode[]
@ -805,19 +805,19 @@ describe('compiler: transform component slots', () => {
{
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'onFoo:modelValue'
content: 'onFoo:modelValue',
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `handler`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
})
const { root } = parseWithSlots(
`<div><slot @foo:model-Value="handler" /></div>`
`<div><slot @foo:model-Value="handler" /></div>`,
)
const slotNode = (root.codegenNode! as VNodeCall)
.children as ElementNode[]
@ -828,15 +828,15 @@ describe('compiler: transform component slots', () => {
{
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'onFoo:modelValue'
content: 'onFoo:modelValue',
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `handler`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
})
})
})
@ -853,14 +853,14 @@ describe('compiler: transform component slots', () => {
start: {
offset: index,
line: 1,
column: index + 1
column: index + 1,
},
end: {
offset: index + 3,
line: 1,
column: index + 4
}
}
column: index + 4,
},
},
})
})
@ -875,14 +875,14 @@ describe('compiler: transform component slots', () => {
start: {
offset: index,
line: 1,
column: index + 1
column: index + 1,
},
end: {
offset: index + 4,
line: 1,
column: index + 5
}
}
column: index + 5,
},
},
})
})
@ -897,14 +897,14 @@ describe('compiler: transform component slots', () => {
start: {
offset: index,
line: 1,
column: index + 1
column: index + 1,
},
end: {
offset: index + 4,
line: 1,
column: index + 5
}
}
column: index + 5,
},
},
})
})
@ -919,14 +919,14 @@ describe('compiler: transform component slots', () => {
start: {
offset: index,
line: 1,
column: index + 1
column: index + 1,
},
end: {
offset: index + 6,
line: 1,
column: index + 7
}
}
column: index + 7,
},
},
})
})
})
@ -940,11 +940,11 @@ describe('compiler: transform component slots', () => {
</Comp>
`
const { root } = parseWithSlots(source, {
whitespace: 'preserve'
whitespace: 'preserve',
})
expect(
`Extraneous children found when component already has explicitly named default slot.`
`Extraneous children found when component already has explicitly named default slot.`,
).not.toHaveBeenWarned()
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -957,11 +957,11 @@ describe('compiler: transform component slots', () => {
</Comp>
`
const { root } = parseWithSlots(source, {
whitespace: 'preserve'
whitespace: 'preserve',
})
expect(
`Extraneous children found when component already has explicitly named default slot.`
`Extraneous children found when component already has explicitly named default slot.`,
).not.toHaveBeenWarned()
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
@ -974,7 +974,7 @@ describe('compiler: transform component slots', () => {
</Comp>
`
const { root } = parseWithSlots(source, {
whitespace: 'preserve'
whitespace: 'preserve',
})
// slots is vnodeCall's children as an ObjectExpression
@ -984,7 +984,7 @@ describe('compiler: transform component slots', () => {
// should be: header, footer, _ (no default)
expect(slots.length).toBe(3)
expect(
slots.some(p => (p.key as SimpleExpressionNode).content === 'default')
slots.some(p => (p.key as SimpleExpressionNode).content === 'default'),
).toBe(false)
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()

View File

@ -1,10 +1,10 @@
import { TransformContext } from '../src'
import { Position } from '../src/ast'
import type { TransformContext } from '../src'
import type { Position } from '../src/ast'
import {
advancePositionWithClone,
isMemberExpressionNode,
isMemberExpressionBrowser,
toValidAssetId
isMemberExpressionNode,
toValidAssetId,
} from '../src/utils'
function p(line: number, column: number, offset: number): Position {
@ -108,6 +108,6 @@ test('toValidAssetId', () => {
expect(toValidAssetId('div', 'filter')).toBe('_filter_div')
expect(toValidAssetId('foo-bar', 'component')).toBe('_component_foo_bar')
expect(toValidAssetId('test-测试-1', 'component')).toBe(
'_component_test_2797935797_1'
'_component_test_2797935797_1',
)
})

View File

@ -1,20 +1,20 @@
import { isString } from '@vue/shared'
import {
RENDER_SLOT,
CREATE_SLOTS,
RENDER_LIST,
OPEN_BLOCK,
FRAGMENT,
WITH_DIRECTIVES,
WITH_MEMO,
CREATE_VNODE,
CREATE_ELEMENT_VNODE,
CREATE_BLOCK,
CREATE_ELEMENT_BLOCK
CREATE_ELEMENT_BLOCK,
CREATE_ELEMENT_VNODE,
type CREATE_SLOTS,
CREATE_VNODE,
type FRAGMENT,
OPEN_BLOCK,
type RENDER_LIST,
type RENDER_SLOT,
WITH_DIRECTIVES,
type WITH_MEMO,
} from './runtimeHelpers'
import { PropsExpression } from './transforms/transformElement'
import { ImportItem, TransformContext } from './transform'
import { Node as BabelNode } from '@babel/types'
import type { PropsExpression } from './transforms/transformElement'
import type { ImportItem, TransformContext } from './transform'
import type { Node as BabelNode } from '@babel/types'
// Vue template is a platform-agnostic superset of HTML (syntax only).
// More namespaces can be declared by platform specific compilers.
@ -23,7 +23,7 @@ export type Namespace = number
export enum Namespaces {
HTML,
SVG,
MATH_ML
MATH_ML,
}
export enum NodeTypes {
@ -57,14 +57,14 @@ export enum NodeTypes {
JS_IF_STATEMENT,
JS_ASSIGNMENT_EXPRESSION,
JS_SEQUENCE_EXPRESSION,
JS_RETURN_STATEMENT
JS_RETURN_STATEMENT,
}
export enum ElementTypes {
ELEMENT,
COMPONENT,
SLOT,
TEMPLATE
TEMPLATE,
}
export interface Node {
@ -219,7 +219,7 @@ export enum ConstantTypes {
NOT_CONSTANT = 0,
CAN_SKIP_PATCH,
CAN_HOIST,
CAN_STRINGIFY
CAN_STRINGIFY,
}
export interface SimpleExpressionNode extends Node {
@ -495,7 +495,7 @@ export interface RenderSlotCall extends CallExpression {
string,
string | ExpressionNode,
PropsExpression | '{}',
TemplateChildNode[]
TemplateChildNode[],
]
}
@ -582,12 +582,12 @@ export interface ForIteratorExpression extends FunctionExpression {
export const locStub: SourceLocation = {
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 1, offset: 0 },
source: ''
source: '',
}
export function createRoot(
children: TemplateChildNode[],
source = ''
source = '',
): RootNode {
return {
type: NodeTypes.ROOT,
@ -601,7 +601,7 @@ export function createRoot(
cached: 0,
temps: 0,
codegenNode: undefined,
loc: locStub
loc: locStub,
}
}
@ -616,7 +616,7 @@ export function createVNodeCall(
isBlock: VNodeCall['isBlock'] = false,
disableTracking: VNodeCall['disableTracking'] = false,
isComponent: VNodeCall['isComponent'] = false,
loc = locStub
loc = locStub,
): VNodeCall {
if (context) {
if (isBlock) {
@ -641,41 +641,41 @@ export function createVNodeCall(
isBlock,
disableTracking,
isComponent,
loc
loc,
}
}
export function createArrayExpression(
elements: ArrayExpression['elements'],
loc: SourceLocation = locStub
loc: SourceLocation = locStub,
): ArrayExpression {
return {
type: NodeTypes.JS_ARRAY_EXPRESSION,
loc,
elements
elements,
}
}
export function createObjectExpression(
properties: ObjectExpression['properties'],
loc: SourceLocation = locStub
loc: SourceLocation = locStub,
): ObjectExpression {
return {
type: NodeTypes.JS_OBJECT_EXPRESSION,
loc,
properties
properties,
}
}
export function createObjectProperty(
key: Property['key'] | string,
value: Property['value']
value: Property['value'],
): Property {
return {
type: NodeTypes.JS_PROPERTY,
loc: locStub,
key: isString(key) ? createSimpleExpression(key, true) : key,
value
value,
}
}
@ -683,38 +683,38 @@ export function createSimpleExpression(
content: SimpleExpressionNode['content'],
isStatic: SimpleExpressionNode['isStatic'] = false,
loc: SourceLocation = locStub,
constType: ConstantTypes = ConstantTypes.NOT_CONSTANT
constType: ConstantTypes = ConstantTypes.NOT_CONSTANT,
): SimpleExpressionNode {
return {
type: NodeTypes.SIMPLE_EXPRESSION,
loc,
content,
isStatic,
constType: isStatic ? ConstantTypes.CAN_STRINGIFY : constType
constType: isStatic ? ConstantTypes.CAN_STRINGIFY : constType,
}
}
export function createInterpolation(
content: InterpolationNode['content'] | string,
loc: SourceLocation
loc: SourceLocation,
): InterpolationNode {
return {
type: NodeTypes.INTERPOLATION,
loc,
content: isString(content)
? createSimpleExpression(content, false, loc)
: content
: content,
}
}
export function createCompoundExpression(
children: CompoundExpressionNode['children'],
loc: SourceLocation = locStub
loc: SourceLocation = locStub,
): CompoundExpressionNode {
return {
type: NodeTypes.COMPOUND_EXPRESSION,
loc,
children
children,
}
}
@ -725,13 +725,13 @@ type InferCodegenNodeType<T> = T extends typeof RENDER_SLOT
export function createCallExpression<T extends CallExpression['callee']>(
callee: T,
args: CallExpression['arguments'] = [],
loc: SourceLocation = locStub
loc: SourceLocation = locStub,
): InferCodegenNodeType<T> {
return {
type: NodeTypes.JS_CALL_EXPRESSION,
loc,
callee,
arguments: args
arguments: args,
} as InferCodegenNodeType<T>
}
@ -740,7 +740,7 @@ export function createFunctionExpression(
returns: FunctionExpression['returns'] = undefined,
newline: boolean = false,
isSlot: boolean = false,
loc: SourceLocation = locStub
loc: SourceLocation = locStub,
): FunctionExpression {
return {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
@ -748,7 +748,7 @@ export function createFunctionExpression(
returns,
newline,
isSlot,
loc
loc,
}
}
@ -756,7 +756,7 @@ export function createConditionalExpression(
test: ConditionalExpression['test'],
consequent: ConditionalExpression['consequent'],
alternate: ConditionalExpression['alternate'],
newline = true
newline = true,
): ConditionalExpression {
return {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
@ -764,87 +764,87 @@ export function createConditionalExpression(
consequent,
alternate,
newline,
loc: locStub
loc: locStub,
}
}
export function createCacheExpression(
index: number,
value: JSChildNode,
isVNode: boolean = false
isVNode: boolean = false,
): CacheExpression {
return {
type: NodeTypes.JS_CACHE_EXPRESSION,
index,
value,
isVNode,
loc: locStub
loc: locStub,
}
}
export function createBlockStatement(
body: BlockStatement['body']
body: BlockStatement['body'],
): BlockStatement {
return {
type: NodeTypes.JS_BLOCK_STATEMENT,
body,
loc: locStub
loc: locStub,
}
}
export function createTemplateLiteral(
elements: TemplateLiteral['elements']
elements: TemplateLiteral['elements'],
): TemplateLiteral {
return {
type: NodeTypes.JS_TEMPLATE_LITERAL,
elements,
loc: locStub
loc: locStub,
}
}
export function createIfStatement(
test: IfStatement['test'],
consequent: IfStatement['consequent'],
alternate?: IfStatement['alternate']
alternate?: IfStatement['alternate'],
): IfStatement {
return {
type: NodeTypes.JS_IF_STATEMENT,
test,
consequent,
alternate,
loc: locStub
loc: locStub,
}
}
export function createAssignmentExpression(
left: AssignmentExpression['left'],
right: AssignmentExpression['right']
right: AssignmentExpression['right'],
): AssignmentExpression {
return {
type: NodeTypes.JS_ASSIGNMENT_EXPRESSION,
left,
right,
loc: locStub
loc: locStub,
}
}
export function createSequenceExpression(
expressions: SequenceExpression['expressions']
expressions: SequenceExpression['expressions'],
): SequenceExpression {
return {
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
expressions,
loc: locStub
loc: locStub,
}
}
export function createReturnStatement(
returns: ReturnStatement['returns']
returns: ReturnStatement['returns'],
): ReturnStatement {
return {
type: NodeTypes.JS_RETURN_STATEMENT,
returns,
loc: locStub
loc: locStub,
}
}
@ -858,7 +858,7 @@ export function getVNodeBlockHelper(ssr: boolean, isComponent: boolean) {
export function convertToBlock(
node: VNodeCall,
{ helper, removeHelper, inSSR }: TransformContext
{ helper, removeHelper, inSSR }: TransformContext,
) {
if (!node.isBlock) {
node.isBlock = true

View File

@ -1,12 +1,12 @@
// should only use types from @babel/types
// do not import runtime methods
import type {
BlockStatement,
Function,
Identifier,
Node,
Function,
ObjectProperty,
BlockStatement,
Program
Program,
} from '@babel/types'
import { walk } from 'estree-walker'
@ -17,11 +17,11 @@ export function walkIdentifiers(
parent: Node,
parentStack: Node[],
isReference: boolean,
isLocal: boolean
isLocal: boolean,
) => void,
includeAll = false,
parentStack: Node[] = [],
knownIds: Record<string, number> = Object.create(null)
knownIds: Record<string, number> = Object.create(null),
) {
if (__BROWSER__) {
return
@ -61,7 +61,7 @@ export function walkIdentifiers(
// walk function expressions and add its arguments to known identifiers
// so that we don't prefix them
walkFunctionParams(node, id =>
markScopeIdentifier(node, id, knownIds)
markScopeIdentifier(node, id, knownIds),
)
}
} else if (node.type === 'BlockStatement') {
@ -70,7 +70,7 @@ export function walkIdentifiers(
} else {
// #3445 record block-level local variables
walkBlockDeclarations(node, id =>
markScopeIdentifier(node, id, knownIds)
markScopeIdentifier(node, id, knownIds),
)
}
}
@ -85,14 +85,14 @@ export function walkIdentifiers(
}
}
}
}
},
})
}
export function isReferencedIdentifier(
id: Identifier,
parent: Node | null,
parentStack: Node[]
parentStack: Node[],
) {
if (__BROWSER__) {
return false
@ -127,7 +127,7 @@ export function isReferencedIdentifier(
export function isInDestructureAssignment(
parent: Node,
parentStack: Node[]
parentStack: Node[],
): boolean {
if (
parent &&
@ -148,7 +148,7 @@ export function isInDestructureAssignment(
export function walkFunctionParams(
node: Function,
onIdent: (id: Identifier) => void
onIdent: (id: Identifier) => void,
) {
for (const p of node.params) {
for (const id of extractIdentifiers(p)) {
@ -159,7 +159,7 @@ export function walkFunctionParams(
export function walkBlockDeclarations(
block: BlockStatement | Program,
onIdent: (node: Identifier) => void
onIdent: (node: Identifier) => void,
) {
for (const stmt of block.body) {
if (stmt.type === 'VariableDeclaration') {
@ -194,7 +194,7 @@ export function walkBlockDeclarations(
export function extractIdentifiers(
param: Node,
nodes: Identifier[] = []
nodes: Identifier[] = [],
): Identifier[] {
switch (param.type) {
case 'Identifier':
@ -248,7 +248,7 @@ function markKnownIds(name: string, knownIds: Record<string, number>) {
function markScopeIdentifier(
node: Node & { scopeIds?: Set<string> },
child: Identifier,
knownIds: Record<string, number>
knownIds: Record<string, number>,
) {
const { name } = child
if (node.scopeIds && node.scopeIds.has(name)) {
@ -453,7 +453,7 @@ export const TS_NODE_TYPES = [
'TSTypeAssertion', // (<number>foo)
'TSNonNullExpression', // foo!
'TSInstantiationExpression', // foo<string>
'TSSatisfiesExpression' // foo satisfies T
'TSSatisfiesExpression', // foo satisfies T
]
export function unwrapTSNode(node: Node): Node {

View File

@ -1,60 +1,60 @@
import { CodegenOptions } from './options'
import type { CodegenOptions } from './options'
import {
RootNode,
TemplateChildNode,
TextNode,
CommentNode,
ExpressionNode,
type ArrayExpression,
type AssignmentExpression,
type CacheExpression,
type CallExpression,
type CommentNode,
type CompoundExpressionNode,
type ConditionalExpression,
type ExpressionNode,
type FunctionExpression,
type IfStatement,
type InterpolationNode,
type JSChildNode,
NodeTypes,
JSChildNode,
CallExpression,
ArrayExpression,
ObjectExpression,
Position,
InterpolationNode,
CompoundExpressionNode,
SimpleExpressionNode,
FunctionExpression,
ConditionalExpression,
CacheExpression,
locStub,
SSRCodegenNode,
TemplateLiteral,
IfStatement,
AssignmentExpression,
ReturnStatement,
VNodeCall,
SequenceExpression,
type ObjectExpression,
type Position,
type ReturnStatement,
type RootNode,
type SSRCodegenNode,
type SequenceExpression,
type SimpleExpressionNode,
type TemplateChildNode,
type TemplateLiteral,
type TextNode,
type VNodeCall,
getVNodeBlockHelper,
getVNodeHelper
getVNodeHelper,
locStub,
} from './ast'
import { SourceMapGenerator, RawSourceMap } from 'source-map-js'
import { type RawSourceMap, SourceMapGenerator } from 'source-map-js'
import {
advancePositionWithMutation,
assert,
isSimpleIdentifier,
toValidAssetId
toValidAssetId,
} from './utils'
import { isString, isArray, isSymbol } from '@vue/shared'
import { isArray, isString, isSymbol } from '@vue/shared'
import {
helperNameMap,
TO_DISPLAY_STRING,
CREATE_COMMENT,
CREATE_ELEMENT_VNODE,
CREATE_STATIC,
CREATE_TEXT,
CREATE_VNODE,
OPEN_BLOCK,
POP_SCOPE_ID,
PUSH_SCOPE_ID,
RESOLVE_COMPONENT,
RESOLVE_DIRECTIVE,
RESOLVE_FILTER,
SET_BLOCK_TRACKING,
CREATE_COMMENT,
CREATE_TEXT,
PUSH_SCOPE_ID,
POP_SCOPE_ID,
WITH_DIRECTIVES,
CREATE_ELEMENT_VNODE,
OPEN_BLOCK,
CREATE_STATIC,
TO_DISPLAY_STRING,
WITH_CTX,
RESOLVE_FILTER
WITH_DIRECTIVES,
helperNameMap,
} from './runtimeHelpers'
import { ImportItem } from './transform'
import type { ImportItem } from './transform'
const PURE_ANNOTATION = `/*#__PURE__*/`
@ -73,7 +73,7 @@ enum NewlineType {
Start = 0,
End = -1,
None = -2,
Unknown = -3
Unknown = -3,
}
export interface CodegenContext
@ -107,8 +107,8 @@ function createCodegenContext(
ssrRuntimeModuleName = 'vue/server-renderer',
ssr = false,
isTS = false,
inSSR = false
}: CodegenOptions
inSSR = false,
}: CodegenOptions,
): CodegenContext {
const context: CodegenContext = {
mode,
@ -158,7 +158,7 @@ function createCodegenContext(
if (__TEST__ && code.includes('\n')) {
throw new Error(
`CodegenContext.push() called newlineIndex: none, but contains` +
`newlines: ${code.replace(/\n/g, '\\n')}`
`newlines: ${code.replace(/\n/g, '\\n')}`,
)
}
context.column += code.length
@ -175,7 +175,7 @@ function createCodegenContext(
) {
throw new Error(
`CodegenContext.push() called with newlineIndex: ${newlineIndex} ` +
`but does not conform: ${code.replace(/\n/g, '\\n')}`
`but does not conform: ${code.replace(/\n/g, '\\n')}`,
)
}
context.line++
@ -199,7 +199,7 @@ function createCodegenContext(
},
newline() {
newline(context.indentLevel)
}
},
}
function newline(n: number) {
@ -218,8 +218,8 @@ function createCodegenContext(
generatedLine: context.line,
generatedColumn: context.column - 1,
source: filename,
// @ts-ignore it is possible to be null
name
// @ts-expect-error it is possible to be null
name,
})
}
@ -237,7 +237,7 @@ export function generate(
ast: RootNode,
options: CodegenOptions & {
onContextCreated?: (context: CodegenContext) => void
} = {}
} = {},
): CodegenResult {
const context = createCodegenContext(ast, options)
if (options.onContextCreated) options.onContextCreated(context)
@ -249,7 +249,7 @@ export function generate(
deindent,
newline,
scopeId,
ssr
ssr,
} = context
const helpers = Array.from(ast.helpers)
@ -296,7 +296,7 @@ export function generate(
if (hasHelpers) {
push(
`const { ${helpers.map(aliasHelper).join(', ')} } = _Vue\n`,
NewlineType.End
NewlineType.End,
)
newline()
}
@ -354,7 +354,7 @@ export function generate(
ast,
code: context.code,
preamble: isSetupInlined ? preambleContext.code : ``,
map: context.map ? context.map.toJSON() : undefined
map: context.map ? context.map.toJSON() : undefined,
}
}
@ -366,7 +366,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
newline,
runtimeModuleName,
runtimeGlobalName,
ssrRuntimeModuleName
ssrRuntimeModuleName,
} = context
const VueBinding =
!__BROWSER__ && ssr
@ -381,7 +381,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
if (!__BROWSER__ && prefixIdentifiers) {
push(
`const { ${helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`,
NewlineType.End
NewlineType.End,
)
} else {
// "with" mode.
@ -396,7 +396,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
CREATE_ELEMENT_VNODE,
CREATE_COMMENT,
CREATE_TEXT,
CREATE_STATIC
CREATE_STATIC,
]
.filter(helper => helpers.includes(helper))
.map(aliasHelper)
@ -412,7 +412,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
`const { ${ast.ssrHelpers
.map(aliasHelper)
.join(', ')} } = require("${ssrRuntimeModuleName}")\n`,
NewlineType.End
NewlineType.End,
)
}
genHoists(ast.hoists, context)
@ -424,14 +424,14 @@ function genModulePreamble(
ast: RootNode,
context: CodegenContext,
genScopeId: boolean,
inline?: boolean
inline?: boolean,
) {
const {
push,
newline,
optimizeImports,
runtimeModuleName,
ssrRuntimeModuleName
ssrRuntimeModuleName,
} = context
if (genScopeId && ast.hoists.length) {
@ -452,20 +452,20 @@ function genModulePreamble(
`import { ${helpers
.map(s => helperNameMap[s])
.join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`,
NewlineType.End
NewlineType.End,
)
push(
`\n// Binding optimization for webpack code-split\nconst ${helpers
.map(s => `_${helperNameMap[s]} = ${helperNameMap[s]}`)
.join(', ')}\n`,
NewlineType.End
NewlineType.End,
)
} else {
push(
`import { ${helpers
.map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)
.join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`,
NewlineType.End
NewlineType.End,
)
}
}
@ -475,7 +475,7 @@ function genModulePreamble(
`import { ${ast.ssrHelpers
.map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)
.join(', ')} } from "${ssrRuntimeModuleName}"\n`,
NewlineType.End
NewlineType.End,
)
}
@ -495,14 +495,14 @@ function genModulePreamble(
function genAssets(
assets: string[],
type: 'component' | 'directive' | 'filter',
{ helper, push, newline, isTS }: CodegenContext
{ helper, push, newline, isTS }: CodegenContext,
) {
const resolver = helper(
__COMPAT__ && type === 'filter'
? RESOLVE_FILTER
: type === 'component'
? RESOLVE_COMPONENT
: RESOLVE_DIRECTIVE
: RESOLVE_DIRECTIVE,
)
for (let i = 0; i < assets.length; i++) {
let id = assets[i]
@ -514,7 +514,7 @@ function genAssets(
push(
`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${
maybeSelfReference ? `, true` : ``
})${isTS ? `!` : ``}`
})${isTS ? `!` : ``}`,
)
if (i < assets.length - 1) {
newline()
@ -535,8 +535,8 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
if (genScopeId) {
push(
`const _withScopeId = n => (${helper(
PUSH_SCOPE_ID
)}("${scopeId}"),n=n(),${helper(POP_SCOPE_ID)}(),n)`
PUSH_SCOPE_ID,
)}("${scopeId}"),n=n(),${helper(POP_SCOPE_ID)}(),n)`,
)
newline()
}
@ -548,7 +548,7 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
push(
`const _hoisted_${i + 1} = ${
needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : ``
}`
}`,
)
genNode(exp, context)
if (needScopeIdWrapper) {
@ -585,7 +585,7 @@ function isText(n: string | CodegenNode) {
function genNodeListAsArray(
nodes: (string | CodegenNode | TemplateChildNode[])[],
context: CodegenContext
context: CodegenContext,
) {
const multilines =
nodes.length > 3 ||
@ -601,7 +601,7 @@ function genNodeList(
nodes: (string | symbol | CodegenNode | TemplateChildNode[])[],
context: CodegenContext,
multilines: boolean = false,
comma: boolean = true
comma: boolean = true,
) {
const { push, newline } = context
for (let i = 0; i < nodes.length; i++) {
@ -641,7 +641,7 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) {
assert(
node.codegenNode != null,
`Codegen node is missing for element/if/for node. ` +
`Apply appropriate transforms first.`
`Apply appropriate transforms first.`,
)
genNode(node.codegenNode!, context)
break
@ -722,7 +722,7 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) {
function genText(
node: TextNode | SimpleExpressionNode,
context: CodegenContext
context: CodegenContext,
) {
context.push(JSON.stringify(node.content), NewlineType.Unknown, node)
}
@ -732,7 +732,7 @@ function genExpression(node: SimpleExpressionNode, context: CodegenContext) {
context.push(
isStatic ? JSON.stringify(content) : content,
NewlineType.Unknown,
node
node,
)
}
@ -746,7 +746,7 @@ function genInterpolation(node: InterpolationNode, context: CodegenContext) {
function genCompoundExpression(
node: CompoundExpressionNode,
context: CodegenContext
context: CodegenContext,
) {
for (let i = 0; i < node.children!.length; i++) {
const child = node.children![i]
@ -760,7 +760,7 @@ function genCompoundExpression(
function genExpressionAsPropertyKey(
node: ExpressionNode,
context: CodegenContext
context: CodegenContext,
) {
const { push } = context
if (node.type === NodeTypes.COMPOUND_EXPRESSION) {
@ -786,7 +786,7 @@ function genComment(node: CommentNode, context: CodegenContext) {
push(
`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`,
NewlineType.Unknown,
node
node,
)
}
@ -801,7 +801,7 @@ function genVNodeCall(node: VNodeCall, context: CodegenContext) {
directives,
isBlock,
disableTracking,
isComponent
isComponent,
} = node
if (directives) {
push(helper(WITH_DIRECTIVES) + `(`)
@ -818,7 +818,7 @@ function genVNodeCall(node: VNodeCall, context: CodegenContext) {
push(helper(callHelper) + `(`, NewlineType.None, node)
genNodeList(
genNullableArgs([tag, props, children, patchFlag, dynamicProps]),
context
context,
)
push(`)`)
if (isBlock) {
@ -887,7 +887,7 @@ function genArrayExpression(node: ArrayExpression, context: CodegenContext) {
function genFunctionExpression(
node: FunctionExpression,
context: CodegenContext
context: CodegenContext,
) {
const { push, indent, deindent } = context
const { params, returns, body, newline, isSlot } = node
@ -932,7 +932,7 @@ function genFunctionExpression(
function genConditionalExpression(
node: ConditionalExpression,
context: CodegenContext
context: CodegenContext,
) {
const { test, consequent, alternate, newline: needNewline } = node
const { push, indent, deindent, newline } = context
@ -1033,7 +1033,7 @@ function genIfStatement(node: IfStatement, context: CodegenContext) {
function genAssignmentExpression(
node: AssignmentExpression,
context: CodegenContext
context: CodegenContext,
) {
genNode(node.left, context)
context.push(` = `)
@ -1042,7 +1042,7 @@ function genAssignmentExpression(
function genSequenceExpression(
node: SequenceExpression,
context: CodegenContext
context: CodegenContext,
) {
context.push(`(`)
genNodeList(node.expressions, context)
@ -1051,7 +1051,7 @@ function genSequenceExpression(
function genReturnStatement(
{ returns }: ReturnStatement,
context: CodegenContext
context: CodegenContext,
) {
context.push(`return `)
if (isArray(returns)) {

View File

@ -1,7 +1,7 @@
import { SourceLocation } from '../ast'
import { CompilerError } from '../errors'
import { MergedParserOptions } from '../parser'
import { TransformContext } from '../transform'
import type { SourceLocation } from '../ast'
import type { CompilerError } from '../errors'
import type { MergedParserOptions } from '../parser'
import type { TransformContext } from '../transform'
export type CompilerCompatConfig = Partial<
Record<CompilerDeprecationTypes, boolean | 'suppress-warning'>
@ -21,7 +21,7 @@ export enum CompilerDeprecationTypes {
COMPILER_V_IF_V_FOR_PRECEDENCE = 'COMPILER_V_IF_V_FOR_PRECEDENCE',
COMPILER_NATIVE_TEMPLATE = 'COMPILER_NATIVE_TEMPLATE',
COMPILER_INLINE_TEMPLATE = 'COMPILER_INLINE_TEMPLATE',
COMPILER_FILTERS = 'COMPILER_FILTER'
COMPILER_FILTERS = 'COMPILER_FILTER',
}
type DeprecationData = {
@ -35,7 +35,7 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
`Platform-native elements with "is" prop will no longer be ` +
`treated as components in Vue 3 unless the "is" value is explicitly ` +
`prefixed with "vue:".`,
link: `https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html`
link: `https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html`,
},
[CompilerDeprecationTypes.COMPILER_V_BIND_SYNC]: {
@ -43,7 +43,7 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
`.sync modifier for v-bind has been removed. Use v-model with ` +
`argument instead. \`v-bind:${key}.sync\` should be changed to ` +
`\`v-model:${key}\`.`,
link: `https://v3-migration.vuejs.org/breaking-changes/v-model.html`
link: `https://v3-migration.vuejs.org/breaking-changes/v-model.html`,
},
[CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER]: {
@ -53,12 +53,12 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
`that appears before v-bind in the case of conflict. ` +
`To retain 2.x behavior, move v-bind to make it the first attribute. ` +
`You can also suppress this warning if the usage is intended.`,
link: `https://v3-migration.vuejs.org/breaking-changes/v-bind.html`
link: `https://v3-migration.vuejs.org/breaking-changes/v-bind.html`,
},
[CompilerDeprecationTypes.COMPILER_V_ON_NATIVE]: {
message: `.native modifier for v-on has been removed as is no longer necessary.`,
link: `https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html`
link: `https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html`,
},
[CompilerDeprecationTypes.COMPILER_V_IF_V_FOR_PRECEDENCE]: {
@ -68,18 +68,18 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
`access to v-for scope variables. It is best to avoid the ambiguity ` +
`with <template> tags or use a computed property that filters v-for ` +
`data source.`,
link: `https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html`
link: `https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html`,
},
[CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE]: {
message:
`<template> with no special directives will render as a native template ` +
`element instead of its inner content in Vue 3.`
`element instead of its inner content in Vue 3.`,
},
[CompilerDeprecationTypes.COMPILER_INLINE_TEMPLATE]: {
message: `"inline-template" has been removed in Vue 3.`,
link: `https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute.html`
link: `https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute.html`,
},
[CompilerDeprecationTypes.COMPILER_FILTERS]: {
@ -87,13 +87,13 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
`filters have been removed in Vue 3. ` +
`The "|" symbol will be treated as native JavaScript bitwise OR operator. ` +
`Use method calls or computed properties instead.`,
link: `https://v3-migration.vuejs.org/breaking-changes/filters.html`
}
link: `https://v3-migration.vuejs.org/breaking-changes/filters.html`,
},
}
function getCompatValue(
key: CompilerDeprecationTypes | 'MODE',
{ compatConfig }: MergedParserOptions | TransformContext
{ compatConfig }: MergedParserOptions | TransformContext,
) {
const value = compatConfig && compatConfig[key]
if (key === 'MODE') {
@ -105,7 +105,7 @@ function getCompatValue(
export function isCompatEnabled(
key: CompilerDeprecationTypes,
context: MergedParserOptions | TransformContext
context: MergedParserOptions | TransformContext,
) {
const mode = getCompatValue('MODE', context)
const value = getCompatValue(key, context)

View File

@ -1,17 +1,17 @@
import { RESOLVE_FILTER } from '../runtimeHelpers'
import {
ExpressionNode,
AttributeNode,
DirectiveNode,
type AttributeNode,
type DirectiveNode,
type ExpressionNode,
NodeTypes,
SimpleExpressionNode
type SimpleExpressionNode,
} from '../ast'
import {
CompilerDeprecationTypes,
isCompatEnabled,
warnDeprecation
warnDeprecation,
} from './compatConfig'
import { NodeTransform, TransformContext } from '../transform'
import type { NodeTransform, TransformContext } from '../transform'
import { toValidAssetId } from '../utils'
const validDivisionCharRE = /[\w).+\-_$\]]/
@ -162,7 +162,7 @@ function parseFilter(node: SimpleExpressionNode, context: TransformContext) {
warnDeprecation(
CompilerDeprecationTypes.COMPILER_FILTERS,
context,
node.loc
node.loc,
)
for (i = 0; i < filters.length; i++) {
expression = wrapFilter(expression, filters[i], context)
@ -174,7 +174,7 @@ function parseFilter(node: SimpleExpressionNode, context: TransformContext) {
function wrapFilter(
exp: string,
filter: string,
context: TransformContext
context: TransformContext,
): string {
context.helper(RESOLVE_FILTER)
const i = filter.indexOf('(')

View File

@ -1,9 +1,13 @@
import { CompilerOptions } from './options'
import type { CompilerOptions } from './options'
import { baseParse } from './parser'
import { transform, NodeTransform, DirectiveTransform } from './transform'
import { generate, CodegenResult } from './codegen'
import { RootNode } from './ast'
import { isString, extend } from '@vue/shared'
import {
type DirectiveTransform,
type NodeTransform,
transform,
} from './transform'
import { type CodegenResult, generate } from './codegen'
import type { RootNode } from './ast'
import { extend, isString } from '@vue/shared'
import { transformIf } from './transforms/vIf'
import { transformFor } from './transforms/vFor'
import { transformExpression } from './transforms/transformExpression'
@ -16,16 +20,16 @@ import { transformText } from './transforms/transformText'
import { transformOnce } from './transforms/vOnce'
import { transformModel } from './transforms/vModel'
import { transformFilter } from './compat/transformFilter'
import { defaultOnError, createCompilerError, ErrorCodes } from './errors'
import { ErrorCodes, createCompilerError, defaultOnError } from './errors'
import { transformMemo } from './transforms/vMemo'
export type TransformPreset = [
NodeTransform[],
Record<string, DirectiveTransform>
Record<string, DirectiveTransform>,
]
export function getBaseTransformPreset(
prefixIdentifiers?: boolean
prefixIdentifiers?: boolean,
): TransformPreset {
return [
[
@ -38,7 +42,7 @@ export function getBaseTransformPreset(
? [
// order is important
trackVForSlotScopes,
transformExpression
transformExpression,
]
: __BROWSER__ && __DEV__
? [transformExpression]
@ -46,13 +50,13 @@ export function getBaseTransformPreset(
transformSlotOutlet,
transformElement,
trackSlotScopes,
transformText
transformText,
],
{
on: transformOn,
bind: transformBind,
model: transformModel
}
model: transformModel,
},
]
}
@ -60,7 +64,7 @@ export function getBaseTransformPreset(
// @vue/compiler-dom can export `compile` while re-exporting everything else.
export function baseCompile(
source: string | RootNode,
options: CompilerOptions = {}
options: CompilerOptions = {},
): CodegenResult {
const onError = options.onError || defaultOnError
const isModuleMode = options.mode === 'module'
@ -83,7 +87,7 @@ export function baseCompile(
}
const resolvedOptions = extend({}, options, {
prefixIdentifiers
prefixIdentifiers,
})
const ast = isString(source) ? baseParse(source, resolvedOptions) : source
const [nodeTransforms, directiveTransforms] =
@ -101,14 +105,14 @@ export function baseCompile(
extend({}, resolvedOptions, {
nodeTransforms: [
...nodeTransforms,
...(options.nodeTransforms || []) // user transforms
...(options.nodeTransforms || []), // user transforms
],
directiveTransforms: extend(
{},
directiveTransforms,
options.directiveTransforms || {} // user transforms
)
})
options.directiveTransforms || {}, // user transforms
),
}),
)
return generate(ast, resolvedOptions)

View File

@ -1,4 +1,4 @@
import { SourceLocation } from './ast'
import type { SourceLocation } from './ast'
export interface CompilerError extends SyntaxError {
code: number | string
@ -25,7 +25,7 @@ export function createCompilerError<T extends number>(
code: T,
loc?: SourceLocation,
messages?: { [code: number]: string },
additionalMessage?: string
additionalMessage?: string,
): InferCompilerError<T> {
const msg =
__DEV__ || !__BROWSER__
@ -101,7 +101,7 @@ export enum ErrorCodes {
// Special value for higher-order compilers to pick up the last code
// to avoid collision of error codes. This should always be kept as the last
// item.
__EXTEND_POINT__
__EXTEND_POINT__,
}
export const errorMessages: Record<ErrorCodes, string> = {
@ -182,5 +182,5 @@ export const errorMessages: Record<ErrorCodes, string> = {
[ErrorCodes.X_SCOPE_ID_NOT_SUPPORTED]: `"scopeId" option is only supported in module mode.`,
// just to fulfill types
[ErrorCodes.__EXTEND_POINT__]: ``
[ErrorCodes.__EXTEND_POINT__]: ``,
}

View File

@ -8,7 +8,7 @@ export {
type CodegenOptions,
type HoistTransform,
type BindingMetadata,
BindingTypes
BindingTypes,
} from './options'
export { baseParse } from './parser'
export {
@ -19,7 +19,7 @@ export {
createStructuralDirectiveTransform,
type NodeTransform,
type StructuralDirectiveTransform,
type DirectiveTransform
type DirectiveTransform,
} from './transform'
export { generate, type CodegenContext, type CodegenResult } from './codegen'
export {
@ -27,7 +27,7 @@ export {
errorMessages,
createCompilerError,
type CoreCompilerError,
type CompilerError
type CompilerError,
} from './errors'
export * from './ast'
@ -45,20 +45,20 @@ export { processFor, createForLoopParams } from './transforms/vFor'
export {
transformExpression,
processExpression,
stringifyExpression
stringifyExpression,
} from './transforms/transformExpression'
export {
buildSlots,
type SlotFnBuilder,
trackVForSlotScopes,
trackSlotScopes
trackSlotScopes,
} from './transforms/vSlot'
export {
transformElement,
resolveComponentType,
buildProps,
buildDirectiveArgs,
type PropsExpression
type PropsExpression,
} from './transforms/transformElement'
export { processSlotOutlet } from './transforms/transformSlotOutlet'
export { getConstantType } from './transforms/hoistStatic'
@ -68,5 +68,5 @@ export { generateCodeFrame } from '@vue/shared'
export {
checkCompatEnabled,
warnDeprecation,
CompilerDeprecationTypes
CompilerDeprecationTypes,
} from './compat/compatConfig'

View File

@ -1,18 +1,18 @@
import {
import type {
ElementNode,
Namespace,
TemplateChildNode,
Namespaces,
ParentNode,
Namespaces
TemplateChildNode,
} from './ast'
import { CompilerError } from './errors'
import {
NodeTransform,
import type { CompilerError } from './errors'
import type {
DirectiveTransform,
TransformContext
NodeTransform,
TransformContext,
} from './transform'
import { CompilerCompatOptions } from './compat/compatConfig'
import { ParserPlugin } from '@babel/parser'
import type { CompilerCompatOptions } from './compat/compatConfig'
import type { ParserPlugin } from '@babel/parser'
export interface ErrorHandlingOptions {
onWarn?: (warning: CompilerError) => void
@ -66,7 +66,7 @@ export interface ParserOptions
getNamespace?: (
tag: string,
parent: ElementNode | undefined,
rootNamespace: Namespace
rootNamespace: Namespace,
) => Namespace
/**
* @default ['{{', '}}']
@ -102,7 +102,7 @@ export interface ParserOptions
export type HoistTransform = (
children: TemplateChildNode[],
context: TransformContext,
parent: ParentNode
parent: ParentNode,
) => void
export enum BindingTypes {
@ -148,7 +148,7 @@ export enum BindingTypes {
/**
* a literal constant, e.g. 'foo', 1, true
*/
LITERAL_CONST = 'literal-const'
LITERAL_CONST = 'literal-const',
}
export type BindingMetadata = {

View File

@ -1,20 +1,20 @@
import {
AttributeNode,
type AttributeNode,
ConstantTypes,
DirectiveNode,
ElementNode,
type DirectiveNode,
type ElementNode,
ElementTypes,
ForParseResult,
type ForParseResult,
Namespaces,
NodeTypes,
RootNode,
SimpleExpressionNode,
SourceLocation,
TemplateChildNode,
type RootNode,
type SimpleExpressionNode,
type SourceLocation,
type TemplateChildNode,
createRoot,
createSimpleExpression
createSimpleExpression,
} from './ast'
import { ParserOptions } from './options'
import type { ParserOptions } from './options'
import Tokenizer, {
CharCodes,
ParseMode,
@ -22,33 +22,33 @@ import Tokenizer, {
Sequences,
State,
isWhitespace,
toCharCodes
toCharCodes,
} from './tokenizer'
import {
CompilerCompatOptions,
type CompilerCompatOptions,
CompilerDeprecationTypes,
checkCompatEnabled,
isCompatEnabled,
warnDeprecation
warnDeprecation,
} from './compat/compatConfig'
import { NO, extend } from '@vue/shared'
import {
ErrorCodes,
createCompilerError,
defaultOnError,
defaultOnWarn
defaultOnWarn,
} from './errors'
import {
forAliasRE,
isCoreComponent,
isSimpleIdentifier,
isStaticArgOf
isStaticArgOf,
} from './utils'
import { decodeHTML } from 'entities/lib/decode.js'
import {
type ParserOptions as BabelOptions,
parse,
parseExpression,
type ParserOptions as BabelOptions
} from '@babel/parser'
type OptionalOptions =
@ -76,7 +76,7 @@ export const defaultParserOptions: MergedParserOptions = {
onError: defaultOnError,
onWarn: defaultOnWarn,
comments: __DEV__,
prefixIdentifiers: false
prefixIdentifiers: false,
}
let currentOptions: MergedParserOptions = defaultParserOptions
@ -129,7 +129,7 @@ const tokenizer = new Tokenizer(stack, {
addNode({
type: NodeTypes.INTERPOLATION,
content: createExp(exp, false, getLoc(innerStart, innerEnd)),
loc: getLoc(start, end)
loc: getLoc(start, end),
})
},
@ -143,7 +143,7 @@ const tokenizer = new Tokenizer(stack, {
props: [],
children: [],
loc: getLoc(start - 1, end),
codegenNode: undefined
codegenNode: undefined,
}
},
@ -191,7 +191,7 @@ const tokenizer = new Tokenizer(stack, {
name: getSlice(start, end),
nameLoc: getLoc(start, end),
value: undefined,
loc: getLoc(start)
loc: getLoc(start),
}
},
@ -216,7 +216,7 @@ const tokenizer = new Tokenizer(stack, {
name: raw,
nameLoc: getLoc(start, end),
value: undefined,
loc: getLoc(start)
loc: getLoc(start),
}
} else {
currentProp = {
@ -226,7 +226,7 @@ const tokenizer = new Tokenizer(stack, {
exp: undefined,
arg: undefined,
modifiers: raw === '.' ? ['prop'] : [],
loc: getLoc(start)
loc: getLoc(start),
}
if (name === 'pre') {
inVPre = tokenizer.inVPre = true
@ -254,7 +254,7 @@ const tokenizer = new Tokenizer(stack, {
isStatic ? arg : arg.slice(1, -1),
isStatic,
getLoc(start, end),
isStatic ? ConstantTypes.CAN_STRINGIFY : ConstantTypes.NOT_CONSTANT
isStatic ? ConstantTypes.CAN_STRINGIFY : ConstantTypes.NOT_CONSTANT,
)
}
},
@ -298,7 +298,7 @@ const tokenizer = new Tokenizer(stack, {
// check duplicate attrs
if (
currentOpenTag!.props.some(
p => (p.type === NodeTypes.DIRECTIVE ? p.rawName : p.name) === name
p => (p.type === NodeTypes.DIRECTIVE ? p.rawName : p.name) === name,
)
) {
emitError(ErrorCodes.DUPLICATE_ATTRIBUTE, start)
@ -314,7 +314,7 @@ const tokenizer = new Tokenizer(stack, {
if (__BROWSER__ && currentAttrValue.includes('&')) {
currentAttrValue = currentOptions.decodeEntities!(
currentAttrValue,
true
true,
)
}
@ -336,7 +336,7 @@ const tokenizer = new Tokenizer(stack, {
loc:
quote === QuoteType.Unquoted
? getLoc(currentAttrStartIndex, currentAttrEndIndex)
: getLoc(currentAttrStartIndex - 1, currentAttrEndIndex + 1)
: getLoc(currentAttrStartIndex - 1, currentAttrEndIndex + 1),
}
if (
tokenizer.inSFCRoot &&
@ -369,7 +369,7 @@ const tokenizer = new Tokenizer(stack, {
false,
getLoc(currentAttrStartIndex, currentAttrEndIndex),
ConstantTypes.NOT_CONSTANT,
expParseMode
expParseMode,
)
if (currentProp.name === 'for') {
currentProp.forParseResult = parseForExpression(currentProp.exp)
@ -384,7 +384,7 @@ const tokenizer = new Tokenizer(stack, {
CompilerDeprecationTypes.COMPILER_V_BIND_SYNC,
currentOptions,
currentProp.loc,
currentProp.rawName
currentProp.rawName,
)
) {
currentProp.name = 'model'
@ -408,7 +408,7 @@ const tokenizer = new Tokenizer(stack, {
addNode({
type: NodeTypes.COMMENT,
content: getSlice(start, end),
loc: getLoc(start - 4, end + 3)
loc: getLoc(start - 4, end + 3),
})
}
},
@ -426,7 +426,7 @@ const tokenizer = new Tokenizer(stack, {
case State.InterpolationClose:
emitError(
ErrorCodes.X_MISSING_INTERPOLATION_END,
tokenizer.sectionStart
tokenizer.sectionStart,
)
break
case State.InCommentLike:
@ -476,10 +476,10 @@ const tokenizer = new Tokenizer(stack, {
if ((stack[0] ? stack[0].ns : currentOptions.ns) === Namespaces.HTML) {
emitError(
ErrorCodes.UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME,
start - 1
start - 1,
)
}
}
},
})
// This regex doesn't cover the case if key or index aliases have destructuring,
@ -488,7 +488,7 @@ const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/
const stripParensRE = /^\(|\)$/g
function parseForExpression(
input: SimpleExpressionNode
input: SimpleExpressionNode,
): ForParseResult | undefined {
const loc = input.loc
const exp = input.content
@ -500,7 +500,7 @@ function parseForExpression(
const createAliasExpression = (
content: string,
offset: number,
asParam = false
asParam = false,
) => {
const start = loc.start.offset + offset
const end = start + content.length
@ -509,7 +509,7 @@ function parseForExpression(
false,
getLoc(start, end),
ConstantTypes.NOT_CONSTANT,
asParam ? ExpParseMode.Params : ExpParseMode.Normal
asParam ? ExpParseMode.Params : ExpParseMode.Normal,
)
}
@ -518,7 +518,7 @@ function parseForExpression(
value: undefined,
key: undefined,
index: undefined,
finalized: false
finalized: false,
}
let valueContent = LHS.trim().replace(stripParensRE, '').trim()
@ -545,9 +545,9 @@ function parseForExpression(
indexContent,
result.key
? keyOffset! + keyContent.length
: trimmedOffset + valueContent.length
: trimmedOffset + valueContent.length,
),
true
true,
)
}
}
@ -602,7 +602,7 @@ function onText(content: string, start: number, end: number) {
parent.children.push({
type: NodeTypes.TEXT,
content,
loc: getLoc(start, end)
loc: getLoc(start, end),
})
}
}
@ -625,7 +625,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
}
el.innerLoc!.source = getSlice(
el.innerLoc!.start.offset,
el.innerLoc!.end.offset
el.innerLoc!.end.offset,
)
}
@ -666,7 +666,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
__DEV__ &&
isCompatEnabled(
CompilerDeprecationTypes.COMPILER_V_IF_V_FOR_PRECEDENCE,
currentOptions
currentOptions,
)
) {
let hasIf = false
@ -684,7 +684,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
warnDeprecation(
CompilerDeprecationTypes.COMPILER_V_IF_V_FOR_PRECEDENCE,
currentOptions,
el.loc
el.loc,
)
break
}
@ -694,7 +694,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
if (
isCompatEnabled(
CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE,
currentOptions
currentOptions,
) &&
el.tag === 'template' &&
!isFragmentTemplate(el)
@ -703,7 +703,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
warnDeprecation(
CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE,
currentOptions,
el.loc
el.loc,
)
// unwrap
const parent = stack[0] || currentRoot
@ -712,14 +712,14 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
}
const inlineTemplateProp = props.find(
p => p.type === NodeTypes.ATTRIBUTE && p.name === 'inline-template'
p => p.type === NodeTypes.ATTRIBUTE && p.name === 'inline-template',
) as AttributeNode
if (
inlineTemplateProp &&
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_INLINE_TEMPLATE,
currentOptions,
inlineTemplateProp.loc
inlineTemplateProp.loc,
) &&
el.children.length
) {
@ -727,9 +727,9 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
type: NodeTypes.TEXT,
content: getSlice(
el.children[0].loc.start.offset,
el.children[el.children.length - 1].loc.end.offset
el.children[el.children.length - 1].loc.end.offset,
),
loc: inlineTemplateProp.loc
loc: inlineTemplateProp.loc,
}
}
}
@ -782,7 +782,7 @@ function isComponent({ tag, props }: ElementNode): boolean {
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
currentOptions,
p.loc
p.loc,
)
) {
return true
@ -796,7 +796,7 @@ function isComponent({ tag, props }: ElementNode): boolean {
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
currentOptions,
p.loc
p.loc,
)
) {
return true
@ -812,7 +812,7 @@ function isUpperCase(c: number) {
const windowsNewlineRE = /\r\n/g
function condenseWhitespace(
nodes: TemplateChildNode[],
tag?: string
tag?: string,
): TemplateChildNode[] {
const shouldCondense = currentOptions.whitespace !== 'preserve'
let removedWhitespace = false
@ -915,7 +915,7 @@ function getLoc(start: number, end?: number): SourceLocation {
// @ts-expect-error allow late attachment
end: end == null ? end : tokenizer.getPos(end),
// @ts-expect-error allow late attachment
source: end == null ? end : getSlice(start, end)
source: end == null ? end : getSlice(start, end),
}
}
@ -930,10 +930,10 @@ function dirToAttr(dir: DirectiveNode): AttributeNode {
name: dir.rawName!,
nameLoc: getLoc(
dir.loc.start.offset,
dir.loc.start.offset + dir.rawName!.length
dir.loc.start.offset + dir.rawName!.length,
),
value: undefined,
loc: dir.loc
loc: dir.loc,
}
if (dir.exp) {
// account for quotes
@ -947,7 +947,7 @@ function dirToAttr(dir: DirectiveNode): AttributeNode {
attr.value = {
type: NodeTypes.TEXT,
content: (dir.exp as SimpleExpressionNode).content,
loc
loc,
}
}
return attr
@ -957,7 +957,7 @@ enum ExpParseMode {
Normal,
Params,
Statements,
Skip
Skip,
}
function createExp(
@ -965,7 +965,7 @@ function createExp(
isStatic: SimpleExpressionNode['isStatic'] = false,
loc: SourceLocation,
constType: ConstantTypes = ConstantTypes.NOT_CONSTANT,
parseMode = ExpParseMode.Normal
parseMode = ExpParseMode.Normal,
) {
const exp = createSimpleExpression(content, isStatic, loc, constType)
if (
@ -982,7 +982,7 @@ function createExp(
try {
const plugins = currentOptions.expressionPlugins
const options: BabelOptions = {
plugins: plugins ? [...plugins, 'typescript'] : ['typescript']
plugins: plugins ? [...plugins, 'typescript'] : ['typescript'],
}
if (parseMode === ExpParseMode.Statements) {
// v-on with multi-inline-statements, pad 1 char
@ -1003,7 +1003,7 @@ function createExp(
function emitError(code: ErrorCodes, index: number, message?: string) {
currentOptions.onError(
createCompilerError(code, getLoc(index, index), undefined, message)
createCompilerError(code, getLoc(index, index), undefined, message),
)
}
@ -1026,7 +1026,7 @@ export function baseParse(input: string, options?: ParserOptions): RootNode {
let key: keyof ParserOptions
for (key in options) {
if (options[key] != null) {
// @ts-ignore
// @ts-expect-error
currentOptions[key] = options[key]
}
}
@ -1036,11 +1036,11 @@ export function baseParse(input: string, options?: ParserOptions): RootNode {
if (!__BROWSER__ && currentOptions.decodeEntities) {
console.warn(
`[@vue/compiler-core] decodeEntities option is passed but will be ` +
`ignored in non-browser builds.`
`ignored in non-browser builds.`,
)
} else if (__BROWSER__ && !currentOptions.decodeEntities) {
throw new Error(
`[@vue/compiler-core] decodeEntities option is required in browser builds.`
`[@vue/compiler-core] decodeEntities option is required in browser builds.`,
)
}
}

View File

@ -13,7 +13,7 @@ export const CREATE_TEXT = Symbol(__DEV__ ? `createTextVNode` : ``)
export const CREATE_STATIC = Symbol(__DEV__ ? `createStaticVNode` : ``)
export const RESOLVE_COMPONENT = Symbol(__DEV__ ? `resolveComponent` : ``)
export const RESOLVE_DYNAMIC_COMPONENT = Symbol(
__DEV__ ? `resolveDynamicComponent` : ``
__DEV__ ? `resolveDynamicComponent` : ``,
)
export const RESOLVE_DIRECTIVE = Symbol(__DEV__ ? `resolveDirective` : ``)
export const RESOLVE_FILTER = Symbol(__DEV__ ? `resolveFilter` : ``)
@ -81,7 +81,7 @@ export const helperNameMap: Record<symbol, string> = {
[UNREF]: `unref`,
[IS_REF]: `isRef`,
[WITH_MEMO]: `withMemo`,
[IS_MEMO_SAME]: `isMemoSame`
[IS_MEMO_SAME]: `isMemoSame`,
}
export function registerRuntimeHelpers(helpers: Record<symbol, string>) {

View File

@ -23,7 +23,7 @@ IN THE SOFTWARE.
*/
import { ErrorCodes } from './errors'
import { ElementNode, Position } from './ast'
import type { ElementNode, Position } from './ast'
/**
* Note: entities is a non-browser-build-only dependency.
@ -32,16 +32,16 @@ import { ElementNode, Position } from './ast'
* so that it can be properly treeshaken.
*/
import {
EntityDecoder,
DecodingMode,
EntityDecoder,
fromCodePoint,
htmlDecodeTree,
fromCodePoint
} from 'entities/lib/decode.js'
export enum ParseMode {
BASE,
HTML,
SFC
SFC,
}
export enum CharCodes {
@ -77,7 +77,7 @@ export enum CharCodes {
Colon = 0x3a, // ":"
At = 0x40, // "@"
LeftSquare = 91, // "["
RightSquare = 93 // "]"
RightSquare = 93, // "]"
}
const defaultDelimitersOpen = new Uint8Array([123, 123]) // "{{"
@ -134,7 +134,7 @@ export enum State {
InEntity,
InSFCRootTagName
InSFCRootTagName,
}
/**
@ -174,7 +174,7 @@ export enum QuoteType {
NoValue = 0,
Unquoted = 1,
Single = 2,
Double = 3
Double = 3,
}
export interface Callbacks {
@ -221,8 +221,8 @@ export const Sequences = {
StyleEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65]), // `</style`
TitleEnd: new Uint8Array([0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65]), // `</title`
TextareaEnd: new Uint8Array([
0x3c, 0x2f, 116, 101, 120, 116, 97, 114, 101, 97
]) // `</textarea
0x3c, 0x2f, 116, 101, 120, 116, 97, 114, 101, 97,
]), // `</textarea
}
export default class Tokenizer {
@ -256,11 +256,11 @@ export default class Tokenizer {
constructor(
private readonly stack: ElementNode[],
private readonly cbs: Callbacks
private readonly cbs: Callbacks,
) {
if (!__BROWSER__) {
this.entityDecoder = new EntityDecoder(htmlDecodeTree, (cp, consumed) =>
this.emitCodePoint(cp, consumed)
this.emitCodePoint(cp, consumed),
)
}
}
@ -299,7 +299,7 @@ export default class Tokenizer {
return {
column,
line,
offset: index
offset: index,
}
}
@ -647,7 +647,7 @@ export default class Tokenizer {
if ((__DEV__ || !__BROWSER__) && c === CharCodes.Eq) {
this.cbs.onerr(
ErrorCodes.UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME,
this.index
this.index,
)
}
this.handleAttrStart(c)
@ -694,7 +694,7 @@ export default class Tokenizer {
) {
this.cbs.onerr(
ErrorCodes.UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME,
this.index
this.index,
)
}
}
@ -733,7 +733,7 @@ export default class Tokenizer {
if (__DEV__ || !__BROWSER__) {
this.cbs.onerr(
ErrorCodes.X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END,
this.index
this.index,
)
}
}
@ -785,7 +785,7 @@ export default class Tokenizer {
this.sectionStart = -1
this.cbs.onattribend(
quote === CharCodes.DoubleQuote ? QuoteType.Double : QuoteType.Single,
this.index + 1
this.index + 1,
)
this.state = State.BeforeAttrName
} else if (!__BROWSER__ && c === CharCodes.Amp) {
@ -814,7 +814,7 @@ export default class Tokenizer {
) {
this.cbs.onerr(
ErrorCodes.UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE,
this.index
this.index,
)
} else if (!__BROWSER__ && c === CharCodes.Amp) {
this.startEntity()
@ -892,7 +892,7 @@ export default class Tokenizer {
this.entityDecoder!.startEntity(
this.baseState === State.Text || this.baseState === State.InRCDATA
? DecodingMode.Legacy
: DecodingMode.Attribute
: DecodingMode.Attribute,
)
}
}
@ -1156,7 +1156,7 @@ export default class Tokenizer {
this.cbs.onattribentity(
fromCodePoint(cp),
this.entityStart,
this.sectionStart
this.sectionStart,
)
} else {
if (this.sectionStart < this.entityStart) {
@ -1168,7 +1168,7 @@ export default class Tokenizer {
this.cbs.ontextentity(
fromCodePoint(cp),
this.entityStart,
this.sectionStart
this.sectionStart,
)
}
}

View File

@ -1,45 +1,45 @@
import { TransformOptions } from './options'
import type { TransformOptions } from './options'
import {
RootNode,
NodeTypes,
ParentNode,
TemplateChildNode,
ElementNode,
DirectiveNode,
Property,
ExpressionNode,
createSimpleExpression,
JSChildNode,
SimpleExpressionNode,
ElementTypes,
CacheExpression,
createCacheExpression,
TemplateLiteral,
createVNodeCall,
type ArrayExpression,
type CacheExpression,
ConstantTypes,
ArrayExpression,
convertToBlock
type DirectiveNode,
type ElementNode,
ElementTypes,
type ExpressionNode,
type JSChildNode,
NodeTypes,
type ParentNode,
type Property,
type RootNode,
type SimpleExpressionNode,
type TemplateChildNode,
type TemplateLiteral,
convertToBlock,
createCacheExpression,
createSimpleExpression,
createVNodeCall,
} from './ast'
import {
isString,
isArray,
NOOP,
PatchFlags,
PatchFlagNames,
EMPTY_OBJ,
NOOP,
PatchFlagNames,
PatchFlags,
camelize,
capitalize,
camelize
isArray,
isString,
} from '@vue/shared'
import { defaultOnError, defaultOnWarn } from './errors'
import {
TO_DISPLAY_STRING,
CREATE_COMMENT,
FRAGMENT,
TO_DISPLAY_STRING,
helperNameMap,
CREATE_COMMENT
} from './runtimeHelpers'
import { isVSlot } from './utils'
import { hoistStatic, isSingleElementRoot } from './transforms/hoistStatic'
import { CompilerCompatOptions } from './compat/compatConfig'
import type { CompilerCompatOptions } from './compat/compatConfig'
// There are two types of transforms:
//
@ -48,7 +48,7 @@ import { CompilerCompatOptions } from './compat/compatConfig'
// replace or remove the node being processed.
export type NodeTransform = (
node: RootNode | TemplateChildNode,
context: TransformContext
context: TransformContext,
) => void | (() => void) | (() => void)[]
// - DirectiveTransform:
@ -60,7 +60,7 @@ export type DirectiveTransform = (
context: TransformContext,
// a platform specific compiler can import the base transform and augment
// it by passing in this optional argument.
augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult
augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult,
) => DirectiveTransformResult
export interface DirectiveTransformResult {
@ -74,7 +74,7 @@ export interface DirectiveTransformResult {
export type StructuralDirectiveTransform = (
node: ElementNode,
dir: DirectiveNode,
context: TransformContext
context: TransformContext,
) => void | (() => void)
export interface ImportItem {
@ -145,8 +145,8 @@ export function createTransformContext(
isTS = false,
onError = defaultOnError,
onWarn = defaultOnWarn,
compatConfig
}: TransformOptions
compatConfig,
}: TransformOptions,
): TransformContext {
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
const context: TransformContext = {
@ -190,7 +190,7 @@ export function createTransformContext(
vFor: 0,
vSlot: 0,
vPre: 0,
vOnce: 0
vOnce: 0,
},
parent: null,
currentNode: root,
@ -287,14 +287,14 @@ export function createTransformContext(
`_hoisted_${context.hoists.length}`,
false,
exp.loc,
ConstantTypes.CAN_HOIST
ConstantTypes.CAN_HOIST,
)
identifier.hoisted = exp
return identifier
},
cache(exp, isVNode = false) {
return createCacheExpression(context.cached++, exp, isVNode)
}
},
}
if (__COMPAT__) {
@ -383,7 +383,7 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
undefined,
true,
undefined,
false /* isComponent */
false /* isComponent */,
)
} else {
// no children = noop. codegen will return null.
@ -392,7 +392,7 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
export function traverseChildren(
parent: ParentNode,
context: TransformContext
context: TransformContext,
) {
let i = 0
const nodeRemoved = () => {
@ -410,7 +410,7 @@ export function traverseChildren(
export function traverseNode(
node: RootNode | TemplateChildNode,
context: TransformContext
context: TransformContext,
) {
context.currentNode = node
// apply transform plugins
@ -473,7 +473,7 @@ export function traverseNode(
export function createStructuralDirectiveTransform(
name: string | RegExp,
fn: StructuralDirectiveTransform
fn: StructuralDirectiveTransform,
): NodeTransform {
const matches = isString(name)
? (n: string) => n === name

View File

@ -1,30 +1,30 @@
import {
type CallExpression,
type ComponentNode,
ConstantTypes,
RootNode,
NodeTypes,
TemplateChildNode,
SimpleExpressionNode,
ElementTypes,
PlainElementNode,
ComponentNode,
TemplateNode,
VNodeCall,
ParentNode,
JSChildNode,
CallExpression,
type JSChildNode,
NodeTypes,
type ParentNode,
type PlainElementNode,
type RootNode,
type SimpleExpressionNode,
type TemplateChildNode,
type TemplateNode,
type VNodeCall,
createArrayExpression,
getVNodeBlockHelper,
getVNodeHelper
getVNodeHelper,
} from '../ast'
import { TransformContext } from '../transform'
import { PatchFlags, isString, isSymbol, isArray } from '@vue/shared'
import type { TransformContext } from '../transform'
import { PatchFlags, isArray, isString, isSymbol } from '@vue/shared'
import { isSlotOutlet } from '../utils'
import {
OPEN_BLOCK,
GUARD_REACTIVE_PROPS,
NORMALIZE_CLASS,
NORMALIZE_PROPS,
NORMALIZE_STYLE
NORMALIZE_STYLE,
OPEN_BLOCK,
} from '../runtimeHelpers'
export function hoistStatic(root: RootNode, context: TransformContext) {
@ -33,13 +33,13 @@ export function hoistStatic(root: RootNode, context: TransformContext) {
context,
// Root node is unfortunately non-hoistable due to potential parent
// fallthrough attributes.
isSingleElementRoot(root, root.children[0])
isSingleElementRoot(root, root.children[0]),
)
}
export function isSingleElementRoot(
root: RootNode,
child: TemplateChildNode
child: TemplateChildNode,
): child is PlainElementNode | ComponentNode | TemplateNode {
const { children } = root
return (
@ -52,7 +52,7 @@ export function isSingleElementRoot(
function walk(
node: ParentNode,
context: TransformContext,
doNotHoistNode: boolean = false
doNotHoistNode: boolean = false,
) {
const { children } = node
const originalCount = children.length
@ -120,7 +120,7 @@ function walk(
walk(
child.branches[i],
context,
child.branches[i].children.length === 1
child.branches[i].children.length === 1,
)
}
}
@ -141,7 +141,7 @@ function walk(
isArray(node.codegenNode.children)
) {
const hoisted = context.hoist(
createArrayExpression(node.codegenNode.children)
createArrayExpression(node.codegenNode.children),
)
// #6978, #7138, #7114
// a hoisted children array inside v-for can caused HMR errors since
@ -155,7 +155,7 @@ function walk(
export function getConstantType(
node: TemplateChildNode | SimpleExpressionNode,
context: TransformContext
context: TransformContext,
): ConstantTypes {
const { constantCache } = context
switch (node.type) {
@ -244,7 +244,7 @@ export function getConstantType(
context.removeHelper(OPEN_BLOCK)
context.removeHelper(
getVNodeBlockHelper(context.inSSR, codegenNode.isComponent)
getVNodeBlockHelper(context.inSSR, codegenNode.isComponent),
)
codegenNode.isBlock = false
context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent))
@ -296,12 +296,12 @@ const allowHoistedHelperSet = new Set([
NORMALIZE_CLASS,
NORMALIZE_STYLE,
NORMALIZE_PROPS,
GUARD_REACTIVE_PROPS
GUARD_REACTIVE_PROPS,
])
function getConstantTypeOfHelperCall(
value: CallExpression,
context: TransformContext
context: TransformContext,
): ConstantTypes {
if (
value.type === NodeTypes.JS_CALL_EXPRESSION &&
@ -321,7 +321,7 @@ function getConstantTypeOfHelperCall(
function getGeneratedPropsConstantType(
node: PlainElementNode,
context: TransformContext
context: TransformContext,
): ConstantTypes {
let returnType = ConstantTypes.CAN_STRINGIFY
const props = getNodeProps(node)

View File

@ -1,3 +1,3 @@
import { DirectiveTransform } from '../transform'
import type { DirectiveTransform } from '../transform'
export const noopDirectiveTransform: DirectiveTransform = () => ({ props: [] })

View File

@ -1,68 +1,68 @@
import { NodeTransform, TransformContext } from '../transform'
import type { NodeTransform, TransformContext } from '../transform'
import {
NodeTypes,
type ArrayExpression,
type CallExpression,
type ComponentNode,
ConstantTypes,
type DirectiveArguments,
type DirectiveNode,
type ElementNode,
ElementTypes,
CallExpression,
ObjectExpression,
ElementNode,
DirectiveNode,
ExpressionNode,
ArrayExpression,
createCallExpression,
type ExpressionNode,
type JSChildNode,
NodeTypes,
type ObjectExpression,
type Property,
type TemplateTextChildNode,
type VNodeCall,
createArrayExpression,
createCallExpression,
createObjectExpression,
createObjectProperty,
createSimpleExpression,
createObjectExpression,
Property,
ComponentNode,
VNodeCall,
TemplateTextChildNode,
DirectiveArguments,
createVNodeCall,
ConstantTypes,
JSChildNode
} from '../ast'
import {
PatchFlags,
PatchFlagNames,
isSymbol,
isOn,
isObject,
isReservedProp,
capitalize,
PatchFlags,
camelize,
isBuiltInDirective
capitalize,
isBuiltInDirective,
isObject,
isOn,
isReservedProp,
isSymbol,
} from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import { ErrorCodes, createCompilerError } from '../errors'
import {
RESOLVE_DIRECTIVE,
RESOLVE_COMPONENT,
RESOLVE_DYNAMIC_COMPONENT,
GUARD_REACTIVE_PROPS,
KEEP_ALIVE,
MERGE_PROPS,
NORMALIZE_CLASS,
NORMALIZE_STYLE,
NORMALIZE_PROPS,
TO_HANDLERS,
TELEPORT,
KEEP_ALIVE,
NORMALIZE_STYLE,
RESOLVE_COMPONENT,
RESOLVE_DIRECTIVE,
RESOLVE_DYNAMIC_COMPONENT,
SUSPENSE,
TELEPORT,
TO_HANDLERS,
UNREF,
GUARD_REACTIVE_PROPS
} from '../runtimeHelpers'
import {
toValidAssetId,
findProp,
isCoreComponent,
isStaticArgOf,
isStaticExp
isStaticExp,
toValidAssetId,
} from '../utils'
import { buildSlots } from './vSlot'
import { getConstantType } from './hoistStatic'
import { BindingTypes } from '../options'
import {
checkCompatEnabled,
CompilerDeprecationTypes,
isCompatEnabled
checkCompatEnabled,
isCompatEnabled,
} from '../compat/compatConfig'
// some directive transforms (e.g. v-model) may return a symbol for runtime
@ -125,7 +125,7 @@ export const transformElement: NodeTransform = (node, context) => {
context,
undefined,
isComponent,
isDynamicComponent
isDynamicComponent,
)
vnodeProps = propsBuildResult.props
patchFlag = propsBuildResult.patchFlag
@ -134,7 +134,7 @@ export const transformElement: NodeTransform = (node, context) => {
vnodeDirectives =
directives && directives.length
? (createArrayExpression(
directives.map(dir => buildDirectiveArgs(dir, context))
directives.map(dir => buildDirectiveArgs(dir, context)),
) as DirectiveArguments)
: undefined
@ -160,8 +160,8 @@ export const transformElement: NodeTransform = (node, context) => {
createCompilerError(ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN, {
start: node.children[0].loc.start,
end: node.children[node.children.length - 1].loc.end,
source: ''
})
source: '',
}),
)
}
}
@ -239,7 +239,7 @@ export const transformElement: NodeTransform = (node, context) => {
!!shouldUseBlock,
false /* disableTracking */,
isComponent,
node.loc
node.loc,
)
}
}
@ -247,7 +247,7 @@ export const transformElement: NodeTransform = (node, context) => {
export function resolveComponentType(
node: ComponentNode,
context: TransformContext,
ssr = false
ssr = false,
) {
let { tag } = node
@ -260,7 +260,7 @@ export function resolveComponentType(
(__COMPAT__ &&
isCompatEnabled(
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
context
context,
))
) {
const exp =
@ -269,7 +269,7 @@ export function resolveComponentType(
: isProp.exp
if (exp) {
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
exp
exp,
])
}
} else if (
@ -388,7 +388,7 @@ export function buildProps(
props: ElementNode['props'] = node.props,
isComponent: boolean,
isDynamicComponent: boolean,
ssr = false
ssr = false,
): {
props: PropsExpression | undefined
directives: DirectiveNode[]
@ -416,7 +416,7 @@ export function buildProps(
const pushMergeArg = (arg?: PropsExpression) => {
if (properties.length) {
mergeArgs.push(
createObjectExpression(dedupeProperties(properties), elementLoc)
createObjectExpression(dedupeProperties(properties), elementLoc),
)
properties = []
}
@ -496,8 +496,8 @@ export function buildProps(
properties.push(
createObjectProperty(
createSimpleExpression('ref_for', true),
createSimpleExpression('true')
)
createSimpleExpression('true'),
),
)
}
// in inline mode there is no setupState object, so we can't use string
@ -514,8 +514,8 @@ export function buildProps(
properties.push(
createObjectProperty(
createSimpleExpression('ref_key', true),
createSimpleExpression(value.content, true, value.loc)
)
createSimpleExpression(value.content, true, value.loc),
),
)
}
}
@ -528,7 +528,7 @@ export function buildProps(
(__COMPAT__ &&
isCompatEnabled(
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
context
context,
)))
) {
continue
@ -539,9 +539,9 @@ export function buildProps(
createSimpleExpression(
value ? value.content : '',
isStatic,
value ? value.loc : loc
)
)
value ? value.loc : loc,
),
),
)
} else {
// directives
@ -553,7 +553,7 @@ export function buildProps(
if (name === 'slot') {
if (!isComponent) {
context.onError(
createCompilerError(ErrorCodes.X_V_SLOT_MISPLACED, loc)
createCompilerError(ErrorCodes.X_V_SLOT_MISPLACED, loc),
)
}
continue
@ -571,7 +571,7 @@ export function buildProps(
(__COMPAT__ &&
isCompatEnabled(
CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT,
context
context,
))))
) {
continue
@ -595,8 +595,8 @@ export function buildProps(
properties.push(
createObjectProperty(
createSimpleExpression('ref_for', true),
createSimpleExpression('true')
)
createSimpleExpression('true'),
),
)
}
@ -634,7 +634,7 @@ export function buildProps(
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER,
context,
loc
loc,
)
}
}
@ -642,7 +642,7 @@ export function buildProps(
if (
isCompatEnabled(
CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER,
context
context,
)
) {
mergeArgs.unshift(exp)
@ -657,7 +657,7 @@ export function buildProps(
type: NodeTypes.JS_CALL_EXPRESSION,
loc,
callee: context.helper(TO_HANDLERS),
arguments: isComponent ? [exp] : [exp, `true`]
arguments: isComponent ? [exp] : [exp, `true`],
})
}
} else {
@ -666,8 +666,8 @@ export function buildProps(
isVBind
? ErrorCodes.X_V_BIND_NO_EXPRESSION
: ErrorCodes.X_V_ON_NO_EXPRESSION,
loc
)
loc,
),
)
}
continue
@ -716,7 +716,7 @@ export function buildProps(
propsExpression = createCallExpression(
context.helper(MERGE_PROPS),
mergeArgs,
elementLoc
elementLoc,
)
} else {
// single v-bind with nothing else - no need for a mergeProps call
@ -725,7 +725,7 @@ export function buildProps(
} else if (properties.length) {
propsExpression = createObjectExpression(
dedupeProperties(properties),
elementLoc
elementLoc,
)
}
@ -785,7 +785,7 @@ export function buildProps(
if (classProp && !isStaticExp(classProp.value)) {
classProp.value = createCallExpression(
context.helper(NORMALIZE_CLASS),
[classProp.value]
[classProp.value],
)
}
if (
@ -801,14 +801,14 @@ export function buildProps(
) {
styleProp.value = createCallExpression(
context.helper(NORMALIZE_STYLE),
[styleProp.value]
[styleProp.value],
)
}
} else {
// dynamic key binding, wrap with `normalizeProps`
propsExpression = createCallExpression(
context.helper(NORMALIZE_PROPS),
[propsExpression]
[propsExpression],
)
}
break
@ -821,9 +821,9 @@ export function buildProps(
context.helper(NORMALIZE_PROPS),
[
createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [
propsExpression
])
]
propsExpression,
]),
],
)
break
}
@ -834,7 +834,7 @@ export function buildProps(
directives: runtimeDirectives,
patchFlag,
dynamicPropNames,
shouldUseBlock
shouldUseBlock,
}
}
@ -875,14 +875,14 @@ function mergeAsArray(existing: Property, incoming: Property) {
} else {
existing.value = createArrayExpression(
[existing.value, incoming.value],
existing.loc
existing.loc,
)
}
}
export function buildDirectiveArgs(
dir: DirectiveNode,
context: TransformContext
context: TransformContext,
): ArrayExpression {
const dirArgs: ArrayExpression['elements'] = []
const runtime = directiveImportMap.get(dir)
@ -922,10 +922,10 @@ export function buildDirectiveArgs(
dirArgs.push(
createObjectExpression(
dir.modifiers.map(modifier =>
createObjectProperty(modifier, trueExpression)
createObjectProperty(modifier, trueExpression),
),
loc
)
loc,
),
)
}
return createArrayExpression(dirArgs, dir.loc)

View File

@ -7,36 +7,36 @@
// - This transform is only applied in non-browser builds because it relies on
// an additional JavaScript parser. In the browser, there is no source-map
// support and the code is wrapped in `with (this) { ... }`.
import { NodeTransform, TransformContext } from '../transform'
import type { NodeTransform, TransformContext } from '../transform'
import {
type CompoundExpressionNode,
ConstantTypes,
type ExpressionNode,
NodeTypes,
createSimpleExpression,
ExpressionNode,
SimpleExpressionNode,
CompoundExpressionNode,
type SimpleExpressionNode,
createCompoundExpression,
ConstantTypes
createSimpleExpression,
} from '../ast'
import {
isInDestructureAssignment,
isStaticProperty,
isStaticPropertyKey,
walkIdentifiers
walkIdentifiers,
} from '../babelUtils'
import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
import {
isGloballyAllowed,
makeMap,
genPropsAccessExp,
hasOwn,
isGloballyAllowed,
isString,
genPropsAccessExp
makeMap,
} from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import {
Node,
Identifier,
import { ErrorCodes, createCompilerError } from '../errors'
import type {
AssignmentExpression,
UpdateExpression
Identifier,
Node,
UpdateExpression,
} from '@babel/types'
import { validateBrowserExpression } from '../validateExpression'
import { parse } from '@babel/parser'
@ -53,7 +53,7 @@ export const transformExpression: NodeTransform = (node, context) => {
if (node.type === NodeTypes.INTERPOLATION) {
node.content = processExpression(
node.content as SimpleExpressionNode,
context
context,
)
} else if (node.type === NodeTypes.ELEMENT) {
// handle directives on element
@ -74,7 +74,7 @@ export const transformExpression: NodeTransform = (node, context) => {
exp,
context,
// slot args must be processed as function params
dir.name === 'slot'
dir.name === 'slot',
)
}
if (arg && arg.type === NodeTypes.SIMPLE_EXPRESSION && !arg.isStatic) {
@ -104,7 +104,7 @@ export function processExpression(
asParams = false,
// v-on handler values may contain multiple statements
asRawStatements = false,
localVars: Record<string, number> = Object.create(context.identifiers)
localVars: Record<string, number> = Object.create(context.identifiers),
): ExpressionNode {
if (__BROWSER__) {
if (__DEV__) {
@ -163,8 +163,8 @@ export function processExpression(
context,
false,
false,
knownIds
)
knownIds,
),
)
return `${context.helperString(IS_REF)}(${raw})${
context.isTS ? ` //@ts-ignore\n` : ``
@ -267,7 +267,7 @@ export function processExpression(
: `(${rawExp})${asParams ? `=>{}` : ``}`
try {
ast = parse(source, {
plugins: context.expressionPlugins
plugins: context.expressionPlugins,
}).program
} catch (e: any) {
context.onError(
@ -275,8 +275,8 @@ export function processExpression(
ErrorCodes.X_INVALID_EXPRESSION,
node.loc,
undefined,
e.message
)
e.message,
),
)
return node
}
@ -320,7 +320,7 @@ export function processExpression(
},
true, // invoke on ALL identifiers
parentStack,
knownIds
knownIds,
)
// We break up the compound expression into an array of strings and sub
@ -346,10 +346,12 @@ export function processExpression(
{
start: advancePositionWithClone(node.loc.start, source, start),
end: advancePositionWithClone(node.loc.start, source, end),
source
source,
},
id.isConstant ? ConstantTypes.CAN_STRINGIFY : ConstantTypes.NOT_CONSTANT
)
id.isConstant
? ConstantTypes.CAN_STRINGIFY
: ConstantTypes.NOT_CONSTANT,
),
)
if (i === ids.length - 1 && end < rawExp.length) {
children.push(rawExp.slice(end))

View File

@ -1,15 +1,15 @@
import { NodeTransform, TransformContext } from '../transform'
import type { NodeTransform, TransformContext } from '../transform'
import {
type CallExpression,
type ExpressionNode,
NodeTypes,
CallExpression,
type SlotOutletNode,
createCallExpression,
ExpressionNode,
SlotOutletNode,
createFunctionExpression
createFunctionExpression,
} from '../ast'
import { isSlotOutlet, isStaticArgOf, isStaticExp } from '../utils'
import { buildProps, PropsExpression } from './transformElement'
import { createCompilerError, ErrorCodes } from '../errors'
import { type PropsExpression, buildProps } from './transformElement'
import { ErrorCodes, createCompilerError } from '../errors'
import { RENDER_SLOT } from '../runtimeHelpers'
import { camelize } from '@vue/shared'
@ -23,7 +23,7 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
slotName,
'{}',
'undefined',
'true'
'true',
]
let expectedLen = 2
@ -45,7 +45,7 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
node.codegenNode = createCallExpression(
context.helper(RENDER_SLOT),
slotArgs,
loc
loc,
)
}
}
@ -57,7 +57,7 @@ interface SlotOutletProcessResult {
export function processSlotOutlet(
node: SlotOutletNode,
context: TransformContext
context: TransformContext,
): SlotOutletProcessResult {
let slotName: string | ExpressionNode = `"default"`
let slotProps: PropsExpression | undefined = undefined
@ -92,7 +92,7 @@ export function processSlotOutlet(
context,
nonNameProps,
false,
false
false,
)
slotProps = props
@ -100,14 +100,14 @@ export function processSlotOutlet(
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
directives[0].loc
)
directives[0].loc,
),
)
}
}
return {
slotName,
slotProps
slotProps,
}
}

View File

@ -1,16 +1,16 @@
import { NodeTransform } from '../transform'
import type { NodeTransform } from '../transform'
import {
NodeTypes,
CompoundExpressionNode,
createCallExpression,
CallExpression,
ElementTypes,
type CallExpression,
type CompoundExpressionNode,
ConstantTypes,
createCompoundExpression
ElementTypes,
NodeTypes,
createCallExpression,
createCompoundExpression,
} from '../ast'
import { isText } from '../utils'
import { CREATE_TEXT } from '../runtimeHelpers'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { PatchFlagNames, PatchFlags } from '@vue/shared'
import { getConstantType } from './hoistStatic'
// Merge adjacent text nodes and expressions into a single expression
@ -39,7 +39,7 @@ export const transformText: NodeTransform = (node, context) => {
if (!currentContainer) {
currentContainer = children[i] = createCompoundExpression(
[child],
child.loc
child.loc,
)
}
// merge adjacent text node into current
@ -72,7 +72,7 @@ export const transformText: NodeTransform = (node, context) => {
!node.props.find(
p =>
p.type === NodeTypes.DIRECTIVE &&
!context.directiveTransforms[p.name]
!context.directiveTransforms[p.name],
) &&
// in compat mode, <template> tags with no special directives
// will be rendered as a fragment so its children must be
@ -100,7 +100,7 @@ export const transformText: NodeTransform = (node, context) => {
) {
callArgs.push(
PatchFlags.TEXT +
(__DEV__ ? ` /* ${PatchFlagNames[PatchFlags.TEXT]} */` : ``)
(__DEV__ ? ` /* ${PatchFlagNames[PatchFlags.TEXT]} */` : ``),
)
}
children[i] = {
@ -109,8 +109,8 @@ export const transformText: NodeTransform = (node, context) => {
loc: child.loc,
codegenNode: createCallExpression(
context.helper(CREATE_TEXT),
callArgs
)
callArgs,
),
}
}
}

View File

@ -1,11 +1,11 @@
import { DirectiveTransform } from '../transform'
import type { DirectiveTransform } from '../transform'
import {
type ExpressionNode,
NodeTypes,
createObjectProperty,
createSimpleExpression,
ExpressionNode,
NodeTypes
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { ErrorCodes, createCompilerError } from '../errors'
import { camelize } from '@vue/shared'
import { CAMELIZE } from '../runtimeHelpers'
import { processExpression } from './transformExpression'
@ -63,12 +63,12 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
) {
context.onError(createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc))
return {
props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]
props: [createObjectProperty(arg, createSimpleExpression('', true, loc))],
}
}
return {
props: [createObjectProperty(arg, exp)]
props: [createObjectProperty(arg, exp)],
}
}

View File

@ -1,52 +1,52 @@
import {
type TransformContext,
createStructuralDirectiveTransform,
TransformContext
} from '../transform'
import {
type BlockCodegenNode,
ConstantTypes,
type DirectiveNode,
type ElementNode,
type ExpressionNode,
type ForCodegenNode,
type ForIteratorExpression,
type ForNode,
type ForParseResult,
type ForRenderListExpression,
NodeTypes,
ExpressionNode,
createSimpleExpression,
SimpleExpressionNode,
type PlainElementNode,
type RenderSlotCall,
type SimpleExpressionNode,
type SlotOutletNode,
type VNodeCall,
createBlockStatement,
createCallExpression,
createCompoundExpression,
createFunctionExpression,
createObjectExpression,
createObjectProperty,
ForCodegenNode,
RenderSlotCall,
SlotOutletNode,
ElementNode,
DirectiveNode,
ForNode,
PlainElementNode,
createSimpleExpression,
createVNodeCall,
VNodeCall,
ForRenderListExpression,
BlockCodegenNode,
ForIteratorExpression,
ConstantTypes,
createBlockStatement,
createCompoundExpression,
getVNodeBlockHelper,
getVNodeHelper,
ForParseResult
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { ErrorCodes, createCompilerError } from '../errors'
import {
findDir,
findProp,
isTemplateNode,
isSlotOutlet,
injectProp,
findDir
isSlotOutlet,
isTemplateNode,
} from '../utils'
import {
RENDER_LIST,
OPEN_BLOCK,
FRAGMENT,
IS_MEMO_SAME
IS_MEMO_SAME,
OPEN_BLOCK,
RENDER_LIST,
} from '../runtimeHelpers'
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { PatchFlagNames, PatchFlags } from '@vue/shared'
export const transformFor = createStructuralDirectiveTransform(
'for',
@ -56,7 +56,7 @@ export const transformFor = createStructuralDirectiveTransform(
// create the loop render function expression now, and add the
// iterator on exit after all children have been traversed
const renderExp = createCallExpression(helper(RENDER_LIST), [
forNode.source
forNode.source,
]) as ForRenderListExpression
const isTemplate = isTemplateNode(node)
const memo = findDir(node, 'memo')
@ -76,13 +76,13 @@ export const transformFor = createStructuralDirectiveTransform(
if (memo) {
memo.exp = processExpression(
memo.exp! as SimpleExpressionNode,
context
context,
)
}
if (keyProperty && keyProp!.type !== NodeTypes.ATTRIBUTE) {
keyProperty.value = processExpression(
keyProperty.value as SimpleExpressionNode,
context
context,
)
}
}
@ -108,7 +108,7 @@ export const transformFor = createStructuralDirectiveTransform(
true /* isBlock */,
!isStableFragment /* disableTracking */,
false /* isComponent */,
node.loc
node.loc,
) as ForCodegenNode
return () => {
@ -125,8 +125,8 @@ export const transformFor = createStructuralDirectiveTransform(
context.onError(
createCompilerError(
ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT,
key.loc
)
key.loc,
),
)
return true
}
@ -169,7 +169,7 @@ export const transformFor = createStructuralDirectiveTransform(
undefined,
true,
undefined,
false /* isComponent */
false /* isComponent */,
)
} else {
// Normal element v-for. Directly use the child's codegenNode
@ -184,12 +184,12 @@ export const transformFor = createStructuralDirectiveTransform(
// switch from block to vnode
removeHelper(OPEN_BLOCK)
removeHelper(
getVNodeBlockHelper(context.inSSR, childBlock.isComponent)
getVNodeBlockHelper(context.inSSR, childBlock.isComponent),
)
} else {
// switch from vnode to block
removeHelper(
getVNodeHelper(context.inSSR, childBlock.isComponent)
getVNodeHelper(context.inSSR, childBlock.isComponent),
)
}
}
@ -205,8 +205,8 @@ export const transformFor = createStructuralDirectiveTransform(
if (memo) {
const loop = createFunctionExpression(
createForLoopParams(forNode.parseResult, [
createSimpleExpression(`_cached`)
])
createSimpleExpression(`_cached`),
]),
)
loop.body = createBlockStatement([
createCompoundExpression([`const _memo = (`, memo.exp!, `)`]),
@ -214,30 +214,30 @@ export const transformFor = createStructuralDirectiveTransform(
`if (_cached`,
...(keyExp ? [` && _cached.key === `, keyExp] : []),
` && ${context.helperString(
IS_MEMO_SAME
)}(_cached, _memo)) return _cached`
IS_MEMO_SAME,
)}(_cached, _memo)) return _cached`,
]),
createCompoundExpression([`const _item = `, childBlock as any]),
createSimpleExpression(`_item.memo = _memo`),
createSimpleExpression(`return _item`)
createSimpleExpression(`return _item`),
])
renderExp.arguments.push(
loop as ForIteratorExpression,
createSimpleExpression(`_cache`),
createSimpleExpression(String(context.cached++))
createSimpleExpression(String(context.cached++)),
)
} else {
renderExp.arguments.push(
createFunctionExpression(
createForLoopParams(forNode.parseResult),
childBlock,
true /* force newline */
) as ForIteratorExpression
true /* force newline */,
) as ForIteratorExpression,
)
}
}
})
}
},
)
// target-agnostic transform used for both Client and SSR
@ -245,11 +245,11 @@ export function processFor(
node: ElementNode,
dir: DirectiveNode,
context: TransformContext,
processCodegen?: (forNode: ForNode) => (() => void) | undefined
processCodegen?: (forNode: ForNode) => (() => void) | undefined,
) {
if (!dir.exp) {
context.onError(
createCompilerError(ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc)
createCompilerError(ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc),
)
return
}
@ -258,7 +258,7 @@ export function processFor(
if (!parseResult) {
context.onError(
createCompilerError(ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, dir.loc)
createCompilerError(ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, dir.loc),
)
return
}
@ -276,7 +276,7 @@ export function processFor(
keyAlias: key,
objectIndexAlias: index,
parseResult,
children: isTemplateNode(node) ? node.children : [node]
children: isTemplateNode(node) ? node.children : [node],
}
context.replaceNode(forNode)
@ -306,34 +306,34 @@ export function processFor(
export function finalizeForParseResult(
result: ForParseResult,
context: TransformContext
context: TransformContext,
) {
if (result.finalized) return
if (!__BROWSER__ && context.prefixIdentifiers) {
result.source = processExpression(
result.source as SimpleExpressionNode,
context
context,
)
if (result.key) {
result.key = processExpression(
result.key as SimpleExpressionNode,
context,
true
true,
)
}
if (result.index) {
result.index = processExpression(
result.index as SimpleExpressionNode,
context,
true
true,
)
}
if (result.value) {
result.value = processExpression(
result.value as SimpleExpressionNode,
context,
true
true,
)
}
}
@ -343,21 +343,21 @@ export function finalizeForParseResult(
validateBrowserExpression(
result.key as SimpleExpressionNode,
context,
true
true,
)
}
if (result.index) {
validateBrowserExpression(
result.index as SimpleExpressionNode,
context,
true
true,
)
}
if (result.value) {
validateBrowserExpression(
result.value as SimpleExpressionNode,
context,
true
true,
)
}
}
@ -366,13 +366,13 @@ export function finalizeForParseResult(
export function createForLoopParams(
{ value, key, index }: ForParseResult,
memoArgs: ExpressionNode[] = []
memoArgs: ExpressionNode[] = [],
): ExpressionNode[] {
return createParamsList([value, key, index, ...memoArgs])
}
function createParamsList(
args: (ExpressionNode | undefined)[]
args: (ExpressionNode | undefined)[],
): ExpressionNode[] {
let i = args.length
while (i--) {

View File

@ -1,37 +1,37 @@
import {
type TransformContext,
createStructuralDirectiveTransform,
TransformContext,
traverseNode
traverseNode,
} from '../transform'
import {
NodeTypes,
type AttributeNode,
type BlockCodegenNode,
type CacheExpression,
ConstantTypes,
type DirectiveNode,
type ElementNode,
ElementTypes,
ElementNode,
DirectiveNode,
IfBranchNode,
SimpleExpressionNode,
type IfBranchNode,
type IfConditionalExpression,
type IfNode,
type MemoExpression,
NodeTypes,
type SimpleExpressionNode,
convertToBlock,
createCallExpression,
createConditionalExpression,
createSimpleExpression,
createObjectProperty,
createObjectExpression,
IfConditionalExpression,
BlockCodegenNode,
IfNode,
createObjectProperty,
createSimpleExpression,
createVNodeCall,
AttributeNode,
locStub,
CacheExpression,
ConstantTypes,
MemoExpression,
convertToBlock
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { ErrorCodes, createCompilerError } from '../errors'
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import { FRAGMENT, CREATE_COMMENT } from '../runtimeHelpers'
import { injectProp, findDir, findProp, getMemoedVNodeCall } from '../utils'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { CREATE_COMMENT, FRAGMENT } from '../runtimeHelpers'
import { findDir, findProp, getMemoedVNodeCall, injectProp } from '../utils'
import { PatchFlagNames, PatchFlags } from '@vue/shared'
export const transformIf = createStructuralDirectiveTransform(
/^(if|else|else-if)$/,
@ -57,7 +57,7 @@ export const transformIf = createStructuralDirectiveTransform(
ifNode.codegenNode = createCodegenNodeForBranch(
branch,
key,
context
context,
) as IfConditionalExpression
} else {
// attach this branch's codegen node to the v-if root.
@ -65,12 +65,12 @@ export const transformIf = createStructuralDirectiveTransform(
parentCondition.alternate = createCodegenNodeForBranch(
branch,
key + ifNode.branches.length - 1,
context
context,
)
}
}
})
}
},
)
// target-agnostic transform used for both Client and SSR
@ -81,8 +81,8 @@ export function processIf(
processCodegen?: (
node: IfNode,
branch: IfBranchNode,
isRoot: boolean
) => (() => void) | undefined
isRoot: boolean,
) => (() => void) | undefined,
) {
if (
dir.name !== 'else' &&
@ -90,7 +90,7 @@ export function processIf(
) {
const loc = dir.exp ? dir.exp.loc : node.loc
context.onError(
createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc)
createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc),
)
dir.exp = createSimpleExpression(`true`, false, loc)
}
@ -110,7 +110,7 @@ export function processIf(
const ifNode: IfNode = {
type: NodeTypes.IF,
loc: node.loc,
branches: [branch]
branches: [branch],
}
context.replaceNode(ifNode)
if (processCodegen) {
@ -145,7 +145,7 @@ export function processIf(
sibling.branches[sibling.branches.length - 1].condition === undefined
) {
context.onError(
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc)
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc),
)
}
@ -175,8 +175,8 @@ export function processIf(
context.onError(
createCompilerError(
ErrorCodes.X_V_IF_SAME_KEY,
branch.userKey!.loc
)
branch.userKey!.loc,
),
)
}
})
@ -195,7 +195,7 @@ export function processIf(
context.currentNode = null
} else {
context.onError(
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc)
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc),
)
}
break
@ -211,14 +211,14 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
condition: dir.name === 'else' ? undefined : dir.exp,
children: isTemplateIf && !findDir(node, 'for') ? node.children : [node],
userKey: findProp(node, `key`),
isTemplateIf
isTemplateIf,
}
}
function createCodegenNodeForBranch(
branch: IfBranchNode,
keyIndex: number,
context: TransformContext
context: TransformContext,
): IfConditionalExpression | BlockCodegenNode | MemoExpression {
if (branch.condition) {
return createConditionalExpression(
@ -228,8 +228,8 @@ function createCodegenNodeForBranch(
// closes the current block.
createCallExpression(context.helper(CREATE_COMMENT), [
__DEV__ ? '"v-if"' : '""',
'true'
])
'true',
]),
) as IfConditionalExpression
} else {
return createChildrenCodegenNode(branch, keyIndex, context)
@ -239,7 +239,7 @@ function createCodegenNodeForBranch(
function createChildrenCodegenNode(
branch: IfBranchNode,
keyIndex: number,
context: TransformContext
context: TransformContext,
): BlockCodegenNode | MemoExpression {
const { helper } = context
const keyProperty = createObjectProperty(
@ -248,8 +248,8 @@ function createChildrenCodegenNode(
`${keyIndex}`,
false,
locStub,
ConstantTypes.CAN_HOIST
)
ConstantTypes.CAN_HOIST,
),
)
const { children } = branch
const firstChild = children[0]
@ -286,7 +286,7 @@ function createChildrenCodegenNode(
true,
false,
false /* isComponent */,
branch.loc
branch.loc,
)
}
} else {
@ -306,7 +306,7 @@ function createChildrenCodegenNode(
function isSameKey(
a: AttributeNode | DirectiveNode | undefined,
b: AttributeNode | DirectiveNode
b: AttributeNode | DirectiveNode,
): boolean {
if (!a || a.type !== b.type) {
return false
@ -334,7 +334,7 @@ function isSameKey(
}
function getParentCondition(
node: IfConditionalExpression | CacheExpression
node: IfConditionalExpression | CacheExpression,
): IfConditionalExpression {
while (true) {
if (node.type === NodeTypes.JS_CONDITIONAL_EXPRESSION) {

View File

@ -1,13 +1,13 @@
import { NodeTransform } from '../transform'
import type { NodeTransform } from '../transform'
import { findDir } from '../utils'
import {
ElementTypes,
type MemoExpression,
NodeTypes,
type PlainElementNode,
convertToBlock,
createCallExpression,
createFunctionExpression,
ElementTypes,
MemoExpression,
NodeTypes,
PlainElementNode
} from '../ast'
import { WITH_MEMO } from '../runtimeHelpers'
@ -33,7 +33,7 @@ export const transformMemo: NodeTransform = (node, context) => {
dir.exp!,
createFunctionExpression(undefined, codegenNode),
`_cache`,
String(context.cached++)
String(context.cached++),
]) as MemoExpression
}
}

View File

@ -1,20 +1,20 @@
import { DirectiveTransform } from '../transform'
import type { DirectiveTransform } from '../transform'
import {
createSimpleExpression,
createObjectProperty,
createCompoundExpression,
NodeTypes,
Property,
ConstantTypes,
ElementTypes,
ExpressionNode,
ConstantTypes
type ExpressionNode,
NodeTypes,
type Property,
createCompoundExpression,
createObjectProperty,
createSimpleExpression,
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { ErrorCodes, createCompilerError } from '../errors'
import {
hasScopeRef,
isMemberExpression,
isSimpleIdentifier,
hasScopeRef,
isStaticExp
isStaticExp,
} from '../utils'
import { IS_REF } from '../runtimeHelpers'
import { BindingTypes } from '../options'
@ -24,7 +24,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
const { exp, arg } = dir
if (!exp) {
context.onError(
createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION, dir.loc)
createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION, dir.loc),
)
return createTransformProps()
}
@ -60,7 +60,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
(!isMemberExpression(expString, context) && !maybeRef)
) {
context.onError(
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc),
)
return createTransformProps()
}
@ -72,7 +72,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
context.identifiers[expString]
) {
context.onError(
createCompilerError(ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE, exp.loc)
createCompilerError(ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE, exp.loc),
)
return createTransformProps()
}
@ -92,7 +92,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
assignmentExp = createCompoundExpression([
`${eventArg} => ((`,
createSimpleExpression(rawExp, false, exp.loc),
`).value = $event)`
`).value = $event)`,
])
} else {
// v-model used on a potentially ref binding in <script setup> inline mode.
@ -102,14 +102,14 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
assignmentExp = createCompoundExpression([
`${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? (`,
createSimpleExpression(rawExp, false, exp.loc),
`).value = $event : ${altAssignment})`
`).value = $event : ${altAssignment})`,
])
}
} else {
assignmentExp = createCompoundExpression([
`${eventArg} => ((`,
exp,
`) = $event)`
`) = $event)`,
])
}
@ -117,7 +117,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
// modelValue: foo
createObjectProperty(propName, dir.exp!),
// "onUpdate:modelValue": $event => (foo = $event)
createObjectProperty(eventName, assignmentExp)
createObjectProperty(eventName, assignmentExp),
]
// cache v-model handler if applicable (when it doesn't refer any scope vars)
@ -148,9 +148,9 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
`{ ${modifiers} }`,
false,
dir.loc,
ConstantTypes.CAN_HOIST
)
)
ConstantTypes.CAN_HOIST,
),
),
)
}

View File

@ -1,16 +1,16 @@
import { DirectiveTransform, DirectiveTransformResult } from '../transform'
import type { DirectiveTransform, DirectiveTransformResult } from '../transform'
import {
type DirectiveNode,
ElementTypes,
type ExpressionNode,
NodeTypes,
type SimpleExpressionNode,
createCompoundExpression,
createObjectProperty,
createSimpleExpression,
DirectiveNode,
ElementTypes,
ExpressionNode,
NodeTypes,
SimpleExpressionNode
} from '../ast'
import { camelize, toHandlerKey } from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import { ErrorCodes, createCompilerError } from '../errors'
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import { hasScopeRef, isMemberExpression } from '../utils'
@ -33,7 +33,7 @@ export const transformOn: DirectiveTransform = (
dir,
node,
context,
augmentor
augmentor,
) => {
const { loc, modifiers, arg } = dir as VOnDirectiveNode
if (!dir.exp && !modifiers.length) {
@ -65,7 +65,7 @@ export const transformOn: DirectiveTransform = (
eventName = createCompoundExpression([
`${context.helperString(TO_HANDLER_KEY)}(`,
arg,
`)`
`)`,
])
}
} else {
@ -95,7 +95,7 @@ export const transformOn: DirectiveTransform = (
exp,
context,
false,
hasMultipleStatements
hasMultipleStatements,
)
isInlineStatement && context.removeIdentifiers(`$event`)
// with scope analysis, the function is hoistable if it has no reference
@ -134,7 +134,7 @@ export const transformOn: DirectiveTransform = (
exp as SimpleExpressionNode,
context,
false,
hasMultipleStatements
hasMultipleStatements,
)
}
@ -151,7 +151,7 @@ export const transformOn: DirectiveTransform = (
}(...args)`
} => ${hasMultipleStatements ? `{` : `(`}`,
exp,
hasMultipleStatements ? `}` : `)`
hasMultipleStatements ? `}` : `)`,
])
}
}
@ -160,9 +160,9 @@ export const transformOn: DirectiveTransform = (
props: [
createObjectProperty(
eventName,
exp || createSimpleExpression(`() => {}`, false, loc)
)
]
exp || createSimpleExpression(`() => {}`, false, loc),
),
],
}
// apply extended compiler augmentor

View File

@ -1,6 +1,6 @@
import { NodeTransform } from '../transform'
import type { NodeTransform } from '../transform'
import { findDir } from '../utils'
import { ElementNode, ForNode, IfNode, NodeTypes } from '../ast'
import { type ElementNode, type ForNode, type IfNode, NodeTypes } from '../ast'
import { SET_BLOCK_TRACKING } from '../runtimeHelpers'
const seen = new WeakSet()

View File

@ -1,34 +1,34 @@
import {
ElementNode,
ObjectExpression,
createObjectExpression,
type CallExpression,
type ConditionalExpression,
type DirectiveNode,
type ElementNode,
ElementTypes,
type ExpressionNode,
type FunctionExpression,
NodeTypes,
type ObjectExpression,
type Property,
type SlotsExpression,
type SourceLocation,
type TemplateChildNode,
createArrayExpression,
createCallExpression,
createConditionalExpression,
createFunctionExpression,
createObjectExpression,
createObjectProperty,
createSimpleExpression,
createFunctionExpression,
DirectiveNode,
ElementTypes,
ExpressionNode,
Property,
TemplateChildNode,
SourceLocation,
createConditionalExpression,
ConditionalExpression,
FunctionExpression,
CallExpression,
createCallExpression,
createArrayExpression,
SlotsExpression
} from '../ast'
import { TransformContext, NodeTransform } from '../transform'
import { createCompilerError, ErrorCodes } from '../errors'
import type { NodeTransform, TransformContext } from '../transform'
import { ErrorCodes, createCompilerError } from '../errors'
import {
findDir,
isTemplateNode,
assert,
isVSlot,
findDir,
hasScopeRef,
isStaticExp
isStaticExp,
isTemplateNode,
isVSlot,
} from '../utils'
import { CREATE_SLOTS, RENDER_LIST, WITH_CTX } from '../runtimeHelpers'
import { createForLoopParams, finalizeForParseResult } from './vFor'
@ -99,7 +99,7 @@ export type SlotFnBuilder = (
slotProps: ExpressionNode | undefined,
vFor: DirectiveNode | undefined,
slotChildren: TemplateChildNode[],
loc: SourceLocation
loc: SourceLocation,
) => FunctionExpression
const buildClientSlotFn: SlotFnBuilder = (props, _vForExp, children, loc) =>
@ -108,7 +108,7 @@ const buildClientSlotFn: SlotFnBuilder = (props, _vForExp, children, loc) =>
children,
false /* newline */,
true /* isSlot */,
children.length ? children[0].loc : loc
children.length ? children[0].loc : loc,
)
// Instead of being a DirectiveTransform, v-slot processing is called during
@ -116,7 +116,7 @@ const buildClientSlotFn: SlotFnBuilder = (props, _vForExp, children, loc) =>
export function buildSlots(
node: ElementNode,
context: TransformContext,
buildSlotFn: SlotFnBuilder = buildClientSlotFn
buildSlotFn: SlotFnBuilder = buildClientSlotFn,
): {
slots: SlotsExpression
hasDynamicSlots: boolean
@ -147,8 +147,8 @@ export function buildSlots(
slotsProperties.push(
createObjectProperty(
arg || createSimpleExpression('default', true),
buildSlotFn(exp, undefined, children, loc)
)
buildSlotFn(exp, undefined, children, loc),
),
)
}
@ -178,7 +178,7 @@ export function buildSlots(
if (onComponentSlot) {
// already has on-component slot - this is incorrect usage.
context.onError(
createCompilerError(ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE, slotDir.loc)
createCompilerError(ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE, slotDir.loc),
)
break
}
@ -188,7 +188,7 @@ export function buildSlots(
const {
arg: slotName = createSimpleExpression(`default`, true),
exp: slotProps,
loc: dirLoc
loc: dirLoc,
} = slotDir
// check if name is dynamic.
@ -211,8 +211,8 @@ export function buildSlots(
createConditionalExpression(
vIf.exp!,
buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++),
defaultFallback
)
defaultFallback,
),
)
} else if (
(vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))
@ -246,14 +246,14 @@ export function buildSlots(
buildDynamicSlot(
slotName,
slotFunction,
conditionalBranchIndex++
conditionalBranchIndex++,
),
defaultFallback
defaultFallback,
)
: buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++)
} else {
context.onError(
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc)
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc),
)
}
} else if (vFor) {
@ -269,13 +269,16 @@ export function buildSlots(
createFunctionExpression(
createForLoopParams(parseResult),
buildDynamicSlot(slotName, slotFunction),
true /* force newline */
)
])
true /* force newline */,
),
]),
)
} else {
context.onError(
createCompilerError(ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, vFor.loc)
createCompilerError(
ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
vFor.loc,
),
)
}
} else {
@ -285,8 +288,8 @@ export function buildSlots(
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES,
dirLoc
)
dirLoc,
),
)
continue
}
@ -302,7 +305,7 @@ export function buildSlots(
if (!onComponentSlot) {
const buildDefaultSlotProperty = (
props: ExpressionNode | undefined,
children: TemplateChildNode[]
children: TemplateChildNode[],
) => {
const fn = buildSlotFn(props, undefined, children, loc)
if (__COMPAT__ && context.compatConfig) {
@ -326,12 +329,12 @@ export function buildSlots(
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN,
implicitDefaultChildren[0].loc
)
implicitDefaultChildren[0].loc,
),
)
} else {
slotsProperties.push(
buildDefaultSlotProperty(undefined, implicitDefaultChildren)
buildDefaultSlotProperty(undefined, implicitDefaultChildren),
)
}
}
@ -351,37 +354,37 @@ export function buildSlots(
// 1 = compiled and static = can skip normalization AND diff as optimized
createSimpleExpression(
slotFlag + (__DEV__ ? ` /* ${slotFlagsText[slotFlag]} */` : ``),
false
)
)
false,
),
),
),
loc
loc,
) as SlotsExpression
if (dynamicSlots.length) {
slots = createCallExpression(context.helper(CREATE_SLOTS), [
slots,
createArrayExpression(dynamicSlots)
createArrayExpression(dynamicSlots),
]) as SlotsExpression
}
return {
slots,
hasDynamicSlots
hasDynamicSlots,
}
}
function buildDynamicSlot(
name: ExpressionNode,
fn: FunctionExpression,
index?: number
index?: number,
): ObjectExpression {
const props = [
createObjectProperty(`name`, name),
createObjectProperty(`fn`, fn)
createObjectProperty(`fn`, fn),
]
if (index != null) {
props.push(
createObjectProperty(`key`, createSimpleExpression(String(index), true))
createObjectProperty(`key`, createSimpleExpression(String(index), true)),
)
}
return createObjectExpression(props)

View File

@ -1,45 +1,45 @@
import {
Position,
ElementNode,
NodeTypes,
CallExpression,
createCallExpression,
DirectiveNode,
type BlockCodegenNode,
type CallExpression,
type DirectiveNode,
type ElementNode,
ElementTypes,
TemplateChildNode,
RootNode,
ObjectExpression,
Property,
JSChildNode,
type ExpressionNode,
type IfBranchNode,
type InterpolationNode,
type JSChildNode,
type MemoExpression,
NodeTypes,
type ObjectExpression,
type Position,
type Property,
type RenderSlotCall,
type RootNode,
type SimpleExpressionNode,
type SlotOutletNode,
type TemplateChildNode,
type TemplateNode,
type TextNode,
type VNodeCall,
createCallExpression,
createObjectExpression,
SlotOutletNode,
TemplateNode,
RenderSlotCall,
ExpressionNode,
IfBranchNode,
TextNode,
InterpolationNode,
VNodeCall,
SimpleExpressionNode,
BlockCodegenNode,
MemoExpression
} from './ast'
import { TransformContext } from './transform'
import type { TransformContext } from './transform'
import {
MERGE_PROPS,
TELEPORT,
SUSPENSE,
KEEP_ALIVE,
BASE_TRANSITION,
TO_HANDLERS,
NORMALIZE_PROPS,
GUARD_REACTIVE_PROPS,
WITH_MEMO
KEEP_ALIVE,
MERGE_PROPS,
NORMALIZE_PROPS,
SUSPENSE,
TELEPORT,
TO_HANDLERS,
WITH_MEMO,
} from './runtimeHelpers'
import { isString, isObject, NOOP } from '@vue/shared'
import { PropsExpression } from './transforms/transformElement'
import { NOOP, isObject, isString } from '@vue/shared'
import type { PropsExpression } from './transforms/transformElement'
import { parseExpression } from '@babel/parser'
import { Expression } from '@babel/types'
import type { Expression } from '@babel/types'
import { unwrapTSNode } from './babelUtils'
export const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
@ -70,7 +70,7 @@ enum MemberExpLexState {
inMemberExp,
inBrackets,
inParens,
inString
inString,
}
const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/
@ -157,7 +157,7 @@ export const isMemberExpressionNode = __BROWSER__
: (path: string, context: TransformContext): boolean => {
try {
let ret: Expression = parseExpression(path, {
plugins: context.expressionPlugins
plugins: context.expressionPlugins,
})
ret = unwrapTSNode(ret) as Expression
return (
@ -177,16 +177,16 @@ export const isMemberExpression = __BROWSER__
export function advancePositionWithClone(
pos: Position,
source: string,
numberOfCharacters: number = source.length
numberOfCharacters: number = source.length,
): Position {
return advancePositionWithMutation(
{
offset: pos.offset,
line: pos.line,
column: pos.column
column: pos.column,
},
source,
numberOfCharacters
numberOfCharacters,
)
}
@ -195,7 +195,7 @@ export function advancePositionWithClone(
export function advancePositionWithMutation(
pos: Position,
source: string,
numberOfCharacters: number = source.length
numberOfCharacters: number = source.length,
): Position {
let linesCount = 0
let lastNewLinePos = -1
@ -226,7 +226,7 @@ export function assert(condition: boolean, msg?: string) {
export function findDir(
node: ElementNode,
name: string | RegExp,
allowEmpty: boolean = false
allowEmpty: boolean = false,
): DirectiveNode | undefined {
for (let i = 0; i < node.props.length; i++) {
const p = node.props[i]
@ -244,7 +244,7 @@ export function findProp(
node: ElementNode,
name: string,
dynamicOnly: boolean = false,
allowEmpty: boolean = false
allowEmpty: boolean = false,
): ElementNode['props'][0] | undefined {
for (let i = 0; i < node.props.length; i++) {
const p = node.props[i]
@ -265,7 +265,7 @@ export function findProp(
export function isStaticArgOf(
arg: DirectiveNode['arg'],
name: string
name: string,
): boolean {
return !!(arg && isStaticExp(arg) && arg.content === name)
}
@ -277,12 +277,12 @@ export function hasDynamicKeyVBind(node: ElementNode): boolean {
p.name === 'bind' &&
(!p.arg || // v-bind="obj"
p.arg.type !== NodeTypes.SIMPLE_EXPRESSION || // v-bind:[_ctx.foo]
!p.arg.isStatic) // v-bind:[foo]
!p.arg.isStatic), // v-bind:[foo]
)
}
export function isText(
node: TemplateChildNode
node: TemplateChildNode,
): node is TextNode | InterpolationNode {
return node.type === NodeTypes.INTERPOLATION || node.type === NodeTypes.TEXT
}
@ -292,7 +292,7 @@ export function isVSlot(p: ElementNode['props'][0]): p is DirectiveNode {
}
export function isTemplateNode(
node: RootNode | TemplateChildNode
node: RootNode | TemplateChildNode,
): node is TemplateNode {
return (
node.type === NodeTypes.ELEMENT && node.tagType === ElementTypes.TEMPLATE
@ -300,7 +300,7 @@ export function isTemplateNode(
}
export function isSlotOutlet(
node: RootNode | TemplateChildNode
node: RootNode | TemplateChildNode,
): node is SlotOutletNode {
return node.type === NodeTypes.ELEMENT && node.tagType === ElementTypes.SLOT
}
@ -309,7 +309,7 @@ const propsHelperSet = new Set([NORMALIZE_PROPS, GUARD_REACTIVE_PROPS])
function getUnnormalizedProps(
props: PropsExpression | '{}',
callPath: CallExpression[] = []
callPath: CallExpression[] = [],
): [PropsExpression | '{}', CallExpression[]] {
if (
props &&
@ -320,7 +320,7 @@ function getUnnormalizedProps(
if (!isString(callee) && propsHelperSet.has(callee)) {
return getUnnormalizedProps(
props.arguments[0] as PropsExpression,
callPath.concat(props)
callPath.concat(props),
)
}
}
@ -329,7 +329,7 @@ function getUnnormalizedProps(
export function injectProp(
node: VNodeCall | RenderSlotCall,
prop: Property,
context: TransformContext
context: TransformContext,
) {
let propsWithInjection: ObjectExpression | CallExpression | undefined
/**
@ -372,7 +372,7 @@ export function injectProp(
// #2366
propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [
createObjectExpression([prop]),
props
props,
])
} else {
props.arguments.unshift(createObjectExpression([prop]))
@ -388,7 +388,7 @@ export function injectProp(
// single v-bind with expression, return a merged replacement
propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [
createObjectExpression([prop]),
props
props,
])
// in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(props))`,
// it will be rewritten as `normalizeProps(mergeProps({ key: 0 }, props))`,
@ -420,7 +420,7 @@ function hasProp(prop: Property, props: ObjectExpression) {
result = props.properties.some(
p =>
p.key.type === NodeTypes.SIMPLE_EXPRESSION &&
p.key.content === propKeyName
p.key.content === propKeyName,
)
}
return result
@ -428,7 +428,7 @@ function hasProp(prop: Property, props: ObjectExpression) {
export function toValidAssetId(
name: string,
type: 'component' | 'directive' | 'filter'
type: 'component' | 'directive' | 'filter',
): string {
// see issue#4422, we need adding identifier on validAssetId if variable `name` has specific character
return `_${type}_${name.replace(/[^\w]/g, (searchValue, replaceValue) => {
@ -439,7 +439,7 @@ export function toValidAssetId(
// Check if a node contains expressions that reference current context scope ids
export function hasScopeRef(
node: TemplateChildNode | IfBranchNode | ExpressionNode | undefined,
ids: TransformContext['identifiers']
ids: TransformContext['identifiers'],
): boolean {
if (!node || Object.keys(ids).length === 0) {
return false

View File

@ -1,6 +1,6 @@
import { SimpleExpressionNode } from './ast'
import { TransformContext } from './transform'
import { createCompilerError, ErrorCodes } from './errors'
import type { SimpleExpressionNode } from './ast'
import type { TransformContext } from './transform'
import { ErrorCodes, createCompilerError } from './errors'
// these keywords should not appear inside expressions, but operators like
// 'typeof', 'instanceof', and 'in' are allowed
@ -13,7 +13,7 @@ const prohibitedKeywordRE = new RegExp(
)
.split(',')
.join('\\b|\\b') +
'\\b'
'\\b',
)
// strip strings in expressions
@ -29,7 +29,7 @@ export function validateBrowserExpression(
node: SimpleExpressionNode,
context: TransformContext,
asParams = false,
asRawStatements = false
asRawStatements = false,
) {
const exp = node.content
@ -43,7 +43,7 @@ export function validateBrowserExpression(
new Function(
asRawStatements
? ` ${exp} `
: `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`
: `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`,
)
} catch (e: any) {
let message = e.message
@ -58,8 +58,8 @@ export function validateBrowserExpression(
ErrorCodes.X_INVALID_EXPRESSION,
node.loc,
undefined,
message
)
message,
),
)
}
}

View File

@ -29,16 +29,16 @@ describe('decodeHtmlBrowser', () => {
// #3001 html tags inside attribute values
expect(decodeHtmlBrowser('<strong>Text</strong>', true)).toBe(
'<strong>Text</strong>'
'<strong>Text</strong>',
)
expect(decodeHtmlBrowser('<strong>&amp;</strong>', true)).toBe(
'<strong>&</strong>'
'<strong>&</strong>',
)
expect(
decodeHtmlBrowser(
'<strong>&lt;strong&gt;&amp;&lt;/strong&gt;</strong>',
true
)
true,
),
).toBe('<strong><strong>&</strong></strong>')
})
})

View File

@ -1,13 +1,13 @@
import {
baseParse as parse,
NodeTypes,
ElementNode,
TextNode,
ElementTypes,
InterpolationNode,
AttributeNode,
type AttributeNode,
ConstantTypes,
Namespaces
type ElementNode,
ElementTypes,
type InterpolationNode,
Namespaces,
NodeTypes,
type TextNode,
baseParse as parse,
} from '@vue/compiler-core'
import { parserOptions } from '../src/parserOptions'
@ -16,7 +16,7 @@ describe('DOM parser', () => {
test('textarea handles comments/elements as just text', () => {
const ast = parse(
'<textarea>some<div>text</div>and<!--comment--></textarea>',
parserOptions
parserOptions,
)
const element = ast.children[0] as ElementNode
const text = element.children[0] as TextNode
@ -27,8 +27,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 46, line: 1, column: 47 },
source: 'some<div>text</div>and<!--comment-->'
}
source: 'some<div>text</div>and<!--comment-->',
},
})
})
@ -43,8 +43,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 15, line: 1, column: 16 },
source: '&amp;'
}
source: '&amp;',
},
})
})
@ -58,16 +58,16 @@ describe('DOM parser', () => {
content: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `foo`,
isStatic: false
}
}
isStatic: false,
},
},
])
})
test('style handles comments/elements as just a text', () => {
const ast = parse(
'<style>some<div>text</div>and<!--comment--></style>',
parserOptions
parserOptions,
)
const element = ast.children[0] as ElementNode
const text = element.children[0] as TextNode
@ -78,8 +78,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 43, line: 1, column: 44 },
source: 'some<div>text</div>and<!--comment-->'
}
source: 'some<div>text</div>and<!--comment-->',
},
})
})
@ -94,8 +94,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 12, line: 1, column: 13 },
source: '&amp;'
}
source: '&amp;',
},
})
})
@ -109,8 +109,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 14, line: 1, column: 15 },
end: { offset: 23, line: 1, column: 24 },
source: 'some text'
}
source: 'some text',
},
})
})
@ -120,21 +120,21 @@ describe('DOM parser', () => {
expect((ast.children[0] as ElementNode).children).toMatchObject([
{
type: NodeTypes.TEXT,
content: ` \na `
content: ` \na `,
},
{
type: NodeTypes.ELEMENT,
children: [
{
type: NodeTypes.TEXT,
content: `foo \n bar`
}
]
content: `foo \n bar`,
},
],
},
{
type: NodeTypes.TEXT,
content: ` \n c`
}
content: ` \n c`,
},
])
})
@ -145,7 +145,7 @@ describe('DOM parser', () => {
expect((ast.children[0] as ElementNode).children).toMatchObject([
{
type: NodeTypes.TEXT,
content: `hello`
content: `hello`,
},
{
type: NodeTypes.ELEMENT,
@ -153,10 +153,10 @@ describe('DOM parser', () => {
{
type: NodeTypes.TEXT,
// should not remove the leading newline for nested elements
content: `\nbye`
}
]
}
content: `\nbye`,
},
],
},
])
})
@ -166,7 +166,7 @@ describe('DOM parser', () => {
const ast = parse(`foo&nbsp;&nbsp;bar`, parserOptions)
expect(ast.children[0]).toMatchObject({
type: NodeTypes.TEXT,
content: `foo${nbsp}${nbsp}bar`
content: `foo${nbsp}${nbsp}bar`,
})
})
@ -181,8 +181,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 11, line: 1, column: 12 },
source: '&ampersand;'
}
source: '&ampersand;',
},
})
})
@ -190,7 +190,7 @@ describe('DOM parser', () => {
test('HTML entities compatibility in attribute', () => {
const ast = parse(
'<div a="&ampersand;" b="&amp;ersand;" c="&amp!"></div>',
parserOptions
parserOptions,
)
const element = ast.children[0] as ElementNode
const text1 = (element.props[0] as AttributeNode).value
@ -203,8 +203,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 20, line: 1, column: 21 },
source: '"&ampersand;"'
}
source: '"&ampersand;"',
},
})
expect(text2).toStrictEqual({
type: NodeTypes.TEXT,
@ -212,8 +212,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 23, line: 1, column: 24 },
end: { offset: 37, line: 1, column: 38 },
source: '"&amp;ersand;"'
}
source: '"&amp;ersand;"',
},
})
expect(text3).toStrictEqual({
type: NodeTypes.TEXT,
@ -221,8 +221,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 40, line: 1, column: 41 },
end: { offset: 47, line: 1, column: 48 },
source: '"&amp!"'
}
source: '"&amp!"',
},
})
})
@ -236,8 +236,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 6, line: 1, column: 7 },
source: '&#x86;'
}
source: '&#x86;',
},
})
})
})
@ -258,14 +258,14 @@ describe('DOM parser', () => {
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 16, line: 1, column: 17 },
source: 'a &lt; b'
}
source: 'a &lt; b',
},
},
loc: {
start: { offset: 5, line: 1, column: 6 },
end: { offset: 19, line: 1, column: 20 },
source: '{{ a &lt; b }}'
}
source: '{{ a &lt; b }}',
},
})
})
})
@ -285,9 +285,9 @@ describe('DOM parser', () => {
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 5, line: 1, column: 6 },
source: '<img>'
source: '<img>',
},
codegenNode: undefined
codegenNode: undefined,
})
})
@ -297,26 +297,26 @@ describe('DOM parser', () => {
expect(ast.children[0]).toMatchObject({
type: NodeTypes.ELEMENT,
tag: 'div',
tagType: ElementTypes.ELEMENT
tagType: ElementTypes.ELEMENT,
})
expect(ast.children[1]).toMatchObject({
type: NodeTypes.ELEMENT,
tag: 'comp',
tagType: ElementTypes.COMPONENT
tagType: ElementTypes.COMPONENT,
})
expect(ast.children[2]).toMatchObject({
type: NodeTypes.ELEMENT,
tag: 'Comp',
tagType: ElementTypes.COMPONENT
tagType: ElementTypes.COMPONENT,
})
})
test('Strict end tag detection for textarea.', () => {
const ast = parse(
'<textarea>hello</textarea</textarea0></texTArea>',
parserOptions
parserOptions,
)
const element = ast.children[0] as ElementNode
const text = element.children[0] as TextNode
@ -328,8 +328,8 @@ describe('DOM parser', () => {
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 37, line: 1, column: 38 },
source: 'hello</textarea</textarea0>'
}
source: 'hello</textarea</textarea0>',
},
})
})
})
@ -359,7 +359,7 @@ describe('DOM parser', () => {
test('SVG in MATH_ML namespace', () => {
const ast = parse(
'<math><annotation-xml><svg></svg></annotation-xml></math>',
parserOptions
parserOptions,
)
const elementMath = ast.children[0] as ElementNode
const elementAnnotation = elementMath.children[0] as ElementNode
@ -372,7 +372,7 @@ describe('DOM parser', () => {
test('html text/html in MATH_ML namespace', () => {
const ast = parse(
'<math><annotation-xml encoding="text/html"><test/></annotation-xml></math>',
parserOptions
parserOptions,
)
const elementMath = ast.children[0] as ElementNode
@ -386,7 +386,7 @@ describe('DOM parser', () => {
test('html application/xhtml+xml in MATH_ML namespace', () => {
const ast = parse(
'<math><annotation-xml encoding="application/xhtml+xml"><test/></annotation-xml></math>',
parserOptions
parserOptions,
)
const elementMath = ast.children[0] as ElementNode
const elementAnnotation = elementMath.children[0] as ElementNode
@ -399,7 +399,7 @@ describe('DOM parser', () => {
test('mtext malignmark in MATH_ML namespace', () => {
const ast = parse(
'<math><mtext><malignmark/></mtext></math>',
parserOptions
parserOptions,
)
const elementMath = ast.children[0] as ElementNode
const elementText = elementMath.children[0] as ElementNode
@ -422,7 +422,7 @@ describe('DOM parser', () => {
test('foreignObject tag in SVG namespace', () => {
const ast = parse(
'<svg><foreignObject><test/></foreignObject></svg>',
parserOptions
parserOptions,
)
const elementSvg = ast.children[0] as ElementNode
const elementForeignObject = elementSvg.children[0] as ElementNode
@ -473,7 +473,7 @@ describe('DOM parser', () => {
test('root ns', () => {
const ast = parse('<foreignObject><test/></foreignObject>', {
...parserOptions,
ns: Namespaces.SVG
ns: Namespaces.SVG,
})
const elementForieng = ast.children[0] as ElementNode
const element = elementForieng.children[0] as ElementNode
@ -487,13 +487,13 @@ describe('DOM parser', () => {
// treatment for <script>, <style>, <textarea> etc.
const ast = parse('<script><g/><g/></script>', {
...parserOptions,
ns: Namespaces.SVG
ns: Namespaces.SVG,
})
const elementSvg = ast.children[0] as ElementNode
// should parse as nodes instead of text
expect(elementSvg.children).toMatchObject([
{ type: NodeTypes.ELEMENT, tag: 'g' },
{ type: NodeTypes.ELEMENT, tag: 'g' }
{ type: NodeTypes.ELEMENT, tag: 'g' },
])
})
})

View File

@ -4,7 +4,7 @@ describe('Transition multi children warnings', () => {
function checkWarning(
template: string,
shouldWarn: boolean,
message = `<Transition> expects exactly one child element or component.`
message = `<Transition> expects exactly one child element or component.`,
) {
const spy = vi.fn()
compile(template.trim(), {
@ -12,7 +12,7 @@ describe('Transition multi children warnings', () => {
transformHoist: null,
onError: err => {
spy(err.message)
}
},
})
if (shouldWarn) expect(spy).toHaveBeenCalledWith(message)
@ -27,7 +27,7 @@ describe('Transition multi children warnings', () => {
<div>hey</div>
</transition>
`,
true
true,
)
})
@ -38,7 +38,7 @@ describe('Transition multi children warnings', () => {
<div v-for="i in items">hey</div>
</transition>
`,
true
true,
)
})
@ -50,7 +50,7 @@ describe('Transition multi children warnings', () => {
<div v-else v-for="i in items">hey</div>
</transition>
`,
true
true,
)
})
@ -61,7 +61,7 @@ describe('Transition multi children warnings', () => {
<template v-if="ok"></template>
</transition>
`,
true
true,
)
})
@ -73,7 +73,7 @@ describe('Transition multi children warnings', () => {
<template v-else></template>
</transition>
`,
true
true,
)
})
@ -85,7 +85,7 @@ describe('Transition multi children warnings', () => {
<div v-if="other">hey</div>
</transition>
`,
true
true,
)
})
@ -96,7 +96,7 @@ describe('Transition multi children warnings', () => {
<div>hey</div>
</transition>
`,
false
false,
)
})
@ -107,7 +107,7 @@ describe('Transition multi children warnings', () => {
<div v-if="a">hey</div>
</transition>
`,
false
false,
)
})
@ -120,7 +120,7 @@ describe('Transition multi children warnings', () => {
<div v-else>hey</div>
</transition>
`,
false
false,
)
})
@ -132,7 +132,7 @@ describe('Transition multi children warnings', () => {
<div v-else>hey</div>
</transition>
`,
false
false,
)
})
})
@ -143,7 +143,7 @@ test('inject persisted when child has v-show', () => {
<transition>
<div v-show="ok" />
</transition>
`).code
`).code,
).toMatchSnapshot()
})
@ -161,6 +161,6 @@ test('the v-if/else-if/else branches in Transition should ignore comments', () =
<p v-else/>
</div>
</transition>
`).code
`).code,
).toMatchSnapshot()
})

View File

@ -1,4 +1,4 @@
import { compile, CompilerError } from '../../src'
import { type CompilerError, compile } from '../../src'
describe('compiler: ignore side effect tags', () => {
it('should ignore script', () => {
@ -6,7 +6,7 @@ describe('compiler: ignore side effect tags', () => {
const { code } = compile(`<script>console.log(1)</script>`, {
onError(e) {
err = e
}
},
})
expect(code).not.toMatch('script')
expect(err).toBeDefined()
@ -18,7 +18,7 @@ describe('compiler: ignore side effect tags', () => {
const { code } = compile(`<style>h1 { color: red }</style>`, {
onError(e) {
err = e
}
},
})
expect(code).not.toMatch('style')
expect(err).toBeDefined()

View File

@ -1,13 +1,13 @@
import {
compile,
NodeTypes,
CREATE_STATIC,
ConstantTypes,
NodeTypes,
compile,
createSimpleExpression,
ConstantTypes
} from '../../src'
import {
StringifyThresholds,
stringifyStatic,
StringifyThresholds
} from '../../src/transforms/stringifyStatic'
describe('stringify static html', () => {
@ -15,7 +15,7 @@ describe('stringify static html', () => {
return compile(template, {
hoistStatic: true,
prefixIdentifiers: true,
transformHoist: stringifyStatic
transformHoist: stringifyStatic,
})
}
@ -25,7 +25,7 @@ describe('stringify static html', () => {
test('should bail on non-eligible static trees', () => {
const { ast } = compileWithStringify(
`<div><div><div>hello</div><div>hello</div></div></div>`
`<div><div><div>hello</div><div>hello</div></div></div>`,
)
// should be a normal vnode call
expect(ast.hoists[0]!.type).toBe(NodeTypes.VNODE_CALL)
@ -35,8 +35,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div><div>${repeat(
`<span class="foo"/>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div></div>`,
)
// should be optimized now
expect(ast.hoists).toMatchObject([
@ -47,15 +47,15 @@ describe('stringify static html', () => {
JSON.stringify(
`<div>${repeat(
`<span class="foo"></span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
),
'1'
]
'1',
],
}, // the children array is hoisted as well
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -63,8 +63,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div><div>${repeat(
`<span/>`,
StringifyThresholds.NODE_COUNT
)}</div></div>`
StringifyThresholds.NODE_COUNT,
)}</div></div>`,
)
// should be optimized now
expect(ast.hoists).toMatchObject([
@ -75,16 +75,16 @@ describe('stringify static html', () => {
JSON.stringify(
`<div>${repeat(
`<span></span>`,
StringifyThresholds.NODE_COUNT
)}</div>`
StringifyThresholds.NODE_COUNT,
)}</div>`,
),
'1'
]
'1',
],
},
// the children array is hoisted as well
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -92,8 +92,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div>${repeat(
`<span class="foo"/>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
)
// should have 6 hoisted nodes (including the entire array),
// but 2~5 should be null because they are merged into 1
@ -105,19 +105,19 @@ describe('stringify static html', () => {
JSON.stringify(
repeat(
`<span class="foo"></span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
),
),
'5'
]
'5',
],
},
null,
null,
null,
null,
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -125,8 +125,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div><div :style="{ color: 'red' }">${repeat(
`<span :class="[{ foo: true }, { bar: true }]">{{ 1 }} + {{ false }}</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div></div>`,
)
// should be optimized now
expect(ast.hoists).toMatchObject([
@ -137,15 +137,15 @@ describe('stringify static html', () => {
JSON.stringify(
`<div style="color:red;">${repeat(
`<span class="foo bar">1 + false</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
),
'1'
]
'1',
],
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -154,8 +154,8 @@ describe('stringify static html', () => {
`<div><div>${repeat(
`<span :class="'foo' + '&gt;ar'">{{ 1 }} + {{ '<' }}</span>` +
`<span>&amp;</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div></div>`,
)
// should be optimized now
expect(ast.hoists).toMatchObject([
@ -166,15 +166,15 @@ describe('stringify static html', () => {
JSON.stringify(
`<div>${repeat(
`<span class="foo&gt;ar">1 + &lt;</span>` + `<span>&amp;</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
),
'1'
]
'1',
],
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -182,7 +182,7 @@ describe('stringify static html', () => {
const { ast, code } = compile(
`<div><div>${repeat(
`<span class="foo">foo</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}<img src="./foo" /></div></div>`,
{
hoistStatic: true,
@ -195,7 +195,7 @@ describe('stringify static html', () => {
'_imports_0_',
false,
node.loc,
ConstantTypes.CAN_HOIST
ConstantTypes.CAN_HOIST,
)
node.props[0] = {
type: NodeTypes.DIRECTIVE,
@ -203,23 +203,23 @@ describe('stringify static html', () => {
arg: createSimpleExpression('src', true),
exp,
modifiers: [],
loc: node.loc
loc: node.loc,
}
}
}
]
}
},
],
},
)
expect(ast.hoists).toMatchObject([
{
// the expression and the tree are still hoistable
// but should stay NodeTypes.VNODE_CALL
// if it's stringified it will be NodeTypes.JS_CALL_EXPRESSION
type: NodeTypes.VNODE_CALL
type: NodeTypes.VNODE_CALL,
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
expect(code).toMatchSnapshot()
})
@ -230,7 +230,7 @@ describe('stringify static html', () => {
const { ast, code } = compile(
`<div><div>${repeat(
`<span class="foo">foo</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}<img src="./foo" /></div></div>`,
{
hoistStatic: true,
@ -243,7 +243,7 @@ describe('stringify static html', () => {
'_imports_0_',
false,
node.loc,
ConstantTypes.CAN_STRINGIFY
ConstantTypes.CAN_STRINGIFY,
)
node.props[0] = {
type: NodeTypes.DIRECTIVE,
@ -251,22 +251,22 @@ describe('stringify static html', () => {
arg: createSimpleExpression('src', true),
exp,
modifiers: [],
loc: node.loc
loc: node.loc,
}
}
}
]
}
},
],
},
)
expect(ast.hoists).toMatchObject([
{
// the hoisted node should be NodeTypes.JS_CALL_EXPRESSION
// of `createStaticVNode()` instead of dynamic NodeTypes.VNODE_CALL
type: NodeTypes.JS_CALL_EXPRESSION
type: NodeTypes.JS_CALL_EXPRESSION,
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
expect(code).toMatchSnapshot()
})
@ -276,31 +276,31 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div><div><input indeterminate>${repeat(
`<span class="foo">foo</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div></div>`,
)
expect(ast.hoists).toMatchObject([
{
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
const { ast: ast2 } = compileWithStringify(
`<div><div><input :indeterminate="true">${repeat(
`<span class="foo">foo</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div></div>`,
)
expect(ast2.hoists).toMatchObject([
{
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -308,31 +308,31 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div><div>${repeat(
`<span class="foo">foo</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}<input indeterminate></div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}<input indeterminate></div></div>`,
)
expect(ast.hoists).toMatchObject([
{
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
const { ast: ast2 } = compileWithStringify(
`<div><div>${repeat(
`<span class="foo">foo</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}<input :indeterminate="true"></div></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}<input :indeterminate="true"></div></div>`,
)
expect(ast2.hoists).toMatchObject([
{
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -340,16 +340,16 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<table><tbody>${repeat(
`<tr class="foo"><td>foo</td></tr>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</tbody></table>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</tbody></table>`,
)
expect(ast.hoists).toMatchObject([
{
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION
}
type: NodeTypes.JS_ARRAY_EXPRESSION,
},
])
})
@ -357,30 +357,30 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<foo>${repeat(
`<div class="foo"></div>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</foo>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</foo>`,
)
expect(ast.hoists.length).toBe(
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)
ast.hoists.forEach(node => {
expect(node).toMatchObject({
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
})
})
const { ast: ast2 } = compileWithStringify(
`<foo><template #foo>${repeat(
`<div class="foo"></div>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</template></foo>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</template></foo>`,
)
expect(ast2.hoists.length).toBe(
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)
ast2.hoists.forEach(node => {
expect(node).toMatchObject({
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
})
})
})
@ -389,8 +389,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div>${repeat(
`<span :title="null"></span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
)
expect(ast.hoists[0]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
@ -399,11 +399,11 @@ describe('stringify static html', () => {
JSON.stringify(
`${repeat(
`<span></span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}`,
),
'5'
]
'5',
],
})
})
@ -412,8 +412,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<button :disabled="false">enable</button>${repeat(
`<div></div>`,
StringifyThresholds.NODE_COUNT
)}`
StringifyThresholds.NODE_COUNT,
)}`,
)
expect(ast.hoists[0]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
@ -422,11 +422,11 @@ describe('stringify static html', () => {
JSON.stringify(
`<button>enable</button>${repeat(
`<div></div>`,
StringifyThresholds.NODE_COUNT
)}`
StringifyThresholds.NODE_COUNT,
)}`,
),
'21'
]
'21',
],
})
})
@ -436,8 +436,8 @@ describe('stringify static html', () => {
const { ast } = compileWithStringify(
`<div>${svg}${repeat(
repeated,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</svg></div>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</svg></div>`,
)
expect(ast.hoists[0]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
@ -446,11 +446,11 @@ describe('stringify static html', () => {
JSON.stringify(
`${svg}${repeat(
repeated,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</svg>`
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</svg>`,
),
'1'
]
'1',
],
})
})

View File

@ -1,10 +1,10 @@
import {
type CompilerOptions,
type ElementNode,
NodeTypes,
type VNodeCall,
baseParse as parse,
transform,
CompilerOptions,
ElementNode,
NodeTypes,
VNodeCall
} from '@vue/compiler-core'
import { transformBind } from '../../../compiler-core/src/transforms/vBind'
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
@ -12,16 +12,16 @@ import { transformStyle } from '../../src/transforms/transformStyle'
function transformWithStyleTransform(
template: string,
options: CompilerOptions = {}
options: CompilerOptions = {},
) {
const ast = parse(template)
transform(ast, {
nodeTransforms: [transformStyle],
...options
...options,
})
return {
root: ast,
node: ast.children[0] as ElementNode
node: ast.children[0] as ElementNode,
}
}
@ -34,13 +34,13 @@ describe('compiler: style transform', () => {
arg: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `style`,
isStatic: true
isStatic: true,
},
exp: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `{"color":"red"}`,
isStatic: false
}
isStatic: false,
},
})
})
@ -48,8 +48,8 @@ describe('compiler: style transform', () => {
const { node } = transformWithStyleTransform(`<div style="color: red"/>`, {
nodeTransforms: [transformStyle, transformElement],
directiveTransforms: {
bind: transformBind
}
bind: transformBind,
},
})
expect((node.codegenNode as VNodeCall).props).toMatchObject({
type: NodeTypes.JS_OBJECT_EXPRESSION,
@ -58,15 +58,15 @@ describe('compiler: style transform', () => {
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `style`,
isStatic: true
isStatic: true,
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `{"color":"red"}`,
isStatic: false
}
}
]
isStatic: false,
},
},
],
})
// should not cause the STYLE patchFlag to be attached
expect((node.codegenNode as VNodeCall).patchFlag).toBeUndefined()

View File

@ -1,14 +1,14 @@
import {
type CompilerOptions,
type PlainElementNode,
baseParse as parse,
transform,
PlainElementNode,
CompilerOptions
} from '@vue/compiler-core'
import { transformVHtml } from '../../src/transforms/vHtml'
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
import {
createObjectMatcher,
genFlagText
genFlagText,
} from '../../../compiler-core/__tests__/testUtils'
import { PatchFlags } from '@vue/shared'
import { DOMErrorCodes } from '../../src/errors'
@ -18,9 +18,9 @@ function transformWithVHtml(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms: [transformElement],
directiveTransforms: {
html: transformVHtml
html: transformVHtml,
},
...options
...options,
})
return ast
}
@ -31,40 +31,40 @@ describe('compiler: v-html transform', () => {
expect((ast.children[0] as PlainElementNode).codegenNode).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({
innerHTML: `[test]`
innerHTML: `[test]`,
}),
children: undefined,
patchFlag: genFlagText(PatchFlags.PROPS),
dynamicProps: `["innerHTML"]`
dynamicProps: `["innerHTML"]`,
})
})
it('should raise error and ignore children when v-html is present', () => {
const onError = vi.fn()
const ast = transformWithVHtml(`<div v-html="test">hello</div>`, {
onError
onError,
})
expect(onError.mock.calls).toMatchObject([
[{ code: DOMErrorCodes.X_V_HTML_WITH_CHILDREN }]
[{ code: DOMErrorCodes.X_V_HTML_WITH_CHILDREN }],
])
expect((ast.children[0] as PlainElementNode).codegenNode).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({
innerHTML: `[test]`
innerHTML: `[test]`,
}),
children: undefined, // <-- children should have been removed
patchFlag: genFlagText(PatchFlags.PROPS),
dynamicProps: `["innerHTML"]`
dynamicProps: `["innerHTML"]`,
})
})
it('should raise error if has no expression', () => {
const onError = vi.fn()
transformWithVHtml(`<div v-html></div>`, {
onError
onError,
})
expect(onError.mock.calls).toMatchObject([
[{ code: DOMErrorCodes.X_V_HTML_NO_EXPRESSION }]
[{ code: DOMErrorCodes.X_V_HTML_NO_EXPRESSION }],
])
})
})

View File

@ -1,8 +1,8 @@
import {
type CompilerOptions,
generate,
baseParse as parse,
transform,
CompilerOptions,
generate
} from '@vue/compiler-core'
import { transformModel } from '../../src/transforms/vModel'
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
@ -12,7 +12,7 @@ import {
V_MODEL_DYNAMIC,
V_MODEL_RADIO,
V_MODEL_SELECT,
V_MODEL_TEXT
V_MODEL_TEXT,
} from '../../src/runtimeHelpers'
function transformWithModel(template: string, options: CompilerOptions = {}) {
@ -20,9 +20,9 @@ function transformWithModel(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms: [transformElement],
directiveTransforms: {
model: transformModel
model: transformModel,
},
...options
...options,
})
return ast
}
@ -70,7 +70,7 @@ describe('compiler: transform v-model', () => {
expect(generate(root).code).toMatchSnapshot()
const root2 = transformWithModel(
'<input v-bind:[key]="val" v-model="model" />'
'<input v-bind:[key]="val" v-model="model" />',
)
expect(root2.helpers).toContain(V_MODEL_DYNAMIC)
expect(generate(root2).code).toMatchSnapshot()
@ -98,8 +98,8 @@ describe('compiler: transform v-model', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT
})
code: DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
}),
)
})
@ -110,8 +110,8 @@ describe('compiler: transform v-model', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT
})
code: DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
}),
)
})
@ -119,7 +119,7 @@ describe('compiler: transform v-model', () => {
const onError = vi.fn()
const root = transformWithModel('<my-input v-model="model" />', {
onError,
isCustomElement: tag => tag.startsWith('my-')
isCustomElement: tag => tag.startsWith('my-'),
})
expect(root.helpers).toContain(V_MODEL_TEXT)
expect(onError).not.toHaveBeenCalled()
@ -129,24 +129,24 @@ describe('compiler: transform v-model', () => {
test('should raise error if used file input element', () => {
const onError = vi.fn()
transformWithModel(`<input type="file" v-model="test"/>`, {
onError
onError,
})
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT
})
code: DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
}),
)
})
test('should error on dynamic value binding alongside v-model', () => {
const onError = vi.fn()
transformWithModel(`<input v-model="test" :value="test" />`, {
onError
onError,
})
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE
})
code: DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
}),
)
})
@ -154,7 +154,7 @@ describe('compiler: transform v-model', () => {
test('should NOT error on static value binding alongside v-model', () => {
const onError = vi.fn()
transformWithModel(`<input v-model="test" value="test" />`, {
onError
onError,
})
expect(onError).not.toHaveBeenCalled()
})

View File

@ -1,14 +1,14 @@
import {
baseParse as parse,
CompilerOptions,
ElementNode,
TO_HANDLER_KEY,
helperNameMap,
BindingTypes,
type CompilerOptions,
type ElementNode,
NodeTypes,
ObjectExpression,
type ObjectExpression,
TO_HANDLER_KEY,
type VNodeCall,
helperNameMap,
baseParse as parse,
transform,
VNodeCall,
BindingTypes
} from '@vue/compiler-core'
import { transformOn } from '../../src/transforms/vOn'
import { V_ON_WITH_KEYS, V_ON_WITH_MODIFIERS } from '../../src/runtimeHelpers'
@ -22,31 +22,31 @@ function parseWithVOn(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms: [transformExpression, transformElement],
directiveTransforms: {
on: transformOn
on: transformOn,
},
...options
...options,
})
const node = (ast.children[0] as ElementNode).codegenNode as VNodeCall
return {
root: ast,
node,
props: (node.props as ObjectExpression).properties
props: (node.props as ObjectExpression).properties,
}
}
describe('compiler-dom: transform v-on', () => {
it('should support multiple modifiers w/ prefixIdentifiers: true', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @click.stop.prevent="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
value: {
callee: V_ON_WITH_MODIFIERS,
arguments: [{ content: '_ctx.test' }, '["stop","prevent"]']
}
arguments: [{ content: '_ctx.test' }, '["stop","prevent"]'],
},
})
})
@ -54,8 +54,8 @@ describe('compiler-dom: transform v-on', () => {
const { props } = parseWithVOn(
`<div @click.stop="test" @keyup.enter="test" />`,
{
prefixIdentifiers: true
}
prefixIdentifiers: true,
},
)
const [clickProp, keyUpProp] = props
@ -64,95 +64,95 @@ describe('compiler-dom: transform v-on', () => {
type: NodeTypes.JS_PROPERTY,
value: {
callee: V_ON_WITH_MODIFIERS,
arguments: [{ content: '_ctx.test' }, '["stop"]']
}
arguments: [{ content: '_ctx.test' }, '["stop"]'],
},
})
expect(keyUpProp).toMatchObject({
type: NodeTypes.JS_PROPERTY,
value: {
callee: V_ON_WITH_KEYS,
arguments: [{ content: '_ctx.test' }, '["enter"]']
}
arguments: [{ content: '_ctx.test' }, '["enter"]'],
},
})
})
it('should support multiple modifiers and event options w/ prefixIdentifiers: true', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @click.stop.capture.once="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
key: {
content: `onClickCaptureOnce`
content: `onClickCaptureOnce`,
},
value: {
callee: V_ON_WITH_MODIFIERS,
arguments: [{ content: '_ctx.test' }, '["stop"]']
}
arguments: [{ content: '_ctx.test' }, '["stop"]'],
},
})
})
it('should wrap keys guard for keyboard events or dynamic events', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @keydown.stop.capture.ctrl.a="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
key: {
content: `onKeydownCapture`
content: `onKeydownCapture`,
},
value: {
callee: V_ON_WITH_KEYS,
arguments: [
{
callee: V_ON_WITH_MODIFIERS,
arguments: [{ content: '_ctx.test' }, '["stop","ctrl"]']
arguments: [{ content: '_ctx.test' }, '["stop","ctrl"]'],
},
'["a"]'
]
}
'["a"]',
],
},
})
})
it('should not wrap keys guard if no key modifier is present', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @keyup.exact="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
value: {
callee: V_ON_WITH_MODIFIERS,
arguments: [{ content: '_ctx.test' }, '["exact"]']
}
arguments: [{ content: '_ctx.test' }, '["exact"]'],
},
})
})
it('should wrap keys guard for static key event w/ left/right modifiers', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @keyup.left="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
value: {
callee: V_ON_WITH_KEYS,
arguments: [{ content: '_ctx.test' }, '["left"]']
}
arguments: [{ content: '_ctx.test' }, '["left"]'],
},
})
})
it('should wrap both for dynamic key event w/ left/right modifiers', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @[e].left="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
@ -161,41 +161,41 @@ describe('compiler-dom: transform v-on', () => {
arguments: [
{
callee: V_ON_WITH_MODIFIERS,
arguments: [{ content: `_ctx.test` }, `["left"]`]
arguments: [{ content: `_ctx.test` }, `["left"]`],
},
'["left"]'
]
}
'["left"]',
],
},
})
})
it('should not wrap normal guard if there is only keys guard', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @keyup.enter="test"/>`, {
prefixIdentifiers: true
prefixIdentifiers: true,
})
expect(prop).toMatchObject({
type: NodeTypes.JS_PROPERTY,
value: {
callee: V_ON_WITH_KEYS,
arguments: [{ content: '_ctx.test' }, '["enter"]']
}
arguments: [{ content: '_ctx.test' }, '["enter"]'],
},
})
})
test('should transform click.right', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @click.right="test"/>`)
expect(prop.key).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `onContextmenu`
content: `onContextmenu`,
})
// dynamic
const {
props: [prop2]
props: [prop2],
} = parseWithVOn(`<div @[event].right="test"/>`)
// (_toHandlerKey(event)).toLowerCase() === "onclick" ? "onContextmenu" : (_toHandlerKey(event))
expect(prop2.key).toMatchObject({
@ -206,34 +206,34 @@ describe('compiler-dom: transform v-on', () => {
children: [
`_${helperNameMap[TO_HANDLER_KEY]}(`,
{ content: 'event' },
`)`
]
`)`,
],
},
`) === "onClick" ? "onContextmenu" : (`,
{
children: [
`_${helperNameMap[TO_HANDLER_KEY]}(`,
{ content: 'event' },
`)`
]
`)`,
],
},
`)`
]
`)`,
],
})
})
test('should transform click.middle', () => {
const {
props: [prop]
props: [prop],
} = parseWithVOn(`<div @click.middle="test"/>`)
expect(prop.key).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `onMouseup`
content: `onMouseup`,
})
// dynamic
const {
props: [prop2]
props: [prop2],
} = parseWithVOn(`<div @[event].middle="test"/>`)
// (_eventNaming(event)).toLowerCase() === "onclick" ? "onMouseup" : (_eventNaming(event))
expect(prop2.key).toMatchObject({
@ -244,48 +244,48 @@ describe('compiler-dom: transform v-on', () => {
children: [
`_${helperNameMap[TO_HANDLER_KEY]}(`,
{ content: 'event' },
`)`
]
`)`,
],
},
`) === "onClick" ? "onMouseup" : (`,
{
children: [
`_${helperNameMap[TO_HANDLER_KEY]}(`,
{ content: 'event' },
`)`
]
`)`,
],
},
`)`
]
`)`,
],
})
})
test('cache handler w/ modifiers', () => {
const {
root,
props: [prop]
props: [prop],
} = parseWithVOn(`<div @keyup.enter.capture="foo" />`, {
prefixIdentifiers: true,
cacheHandlers: true
cacheHandlers: true,
})
expect(root.cached).toBe(1)
// should not treat cached handler as dynamicProp, so it should have no
// dynamicProps flags and only the hydration flag
expect((root as any).children[0].codegenNode.patchFlag).toBe(
genFlagText(PatchFlags.NEED_HYDRATION)
genFlagText(PatchFlags.NEED_HYDRATION),
)
expect(prop).toMatchObject({
key: {
content: `onKeyupCapture`
content: `onKeyupCapture`,
},
value: {
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: V_ON_WITH_KEYS
}
}
callee: V_ON_WITH_KEYS,
},
},
})
})
@ -293,11 +293,11 @@ describe('compiler-dom: transform v-on', () => {
const { node } = parseWithVOn(`<div @keydown.up="foo" />`, {
prefixIdentifiers: true,
bindingMetadata: {
foo: BindingTypes.SETUP_CONST
foo: BindingTypes.SETUP_CONST,
},
directiveTransforms: {
on: transformOn
}
on: transformOn,
},
})
// should only have hydration flag
expect(node.patchFlag).toBe(genFlagText(PatchFlags.NEED_HYDRATION))

View File

@ -1,8 +1,8 @@
import {
type CompilerOptions,
generate,
baseParse as parse,
transform,
generate,
CompilerOptions
} from '@vue/compiler-core'
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
import { transformShow } from '../../src/transforms/vShow'
@ -13,9 +13,9 @@ function transformWithShow(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms: [transformElement],
directiveTransforms: {
show: transformShow
show: transformShow,
},
...options
...options,
})
return ast
}
@ -34,8 +34,8 @@ describe('compiler: v-show transform', () => {
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_SHOW_NO_EXPRESSION
})
code: DOMErrorCodes.X_V_SHOW_NO_EXPRESSION,
}),
)
})
})

View File

@ -1,14 +1,14 @@
import {
type CompilerOptions,
type PlainElementNode,
baseParse as parse,
transform,
PlainElementNode,
CompilerOptions
} from '@vue/compiler-core'
import { transformVText } from '../../src/transforms/vText'
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
import {
createObjectMatcher,
genFlagText
genFlagText,
} from '../../../compiler-core/__tests__/testUtils'
import { PatchFlags } from '@vue/shared'
import { DOMErrorCodes } from '../../src/errors'
@ -18,9 +18,9 @@ function transformWithVText(template: string, options: CompilerOptions = {}) {
transform(ast, {
nodeTransforms: [transformElement],
directiveTransforms: {
text: transformVText
text: transformVText,
},
...options
...options,
})
return ast
}
@ -32,43 +32,43 @@ describe('compiler: v-text transform', () => {
tag: `"div"`,
props: createObjectMatcher({
textContent: {
arguments: [{ content: 'test' }]
}
arguments: [{ content: 'test' }],
},
}),
children: undefined,
patchFlag: genFlagText(PatchFlags.PROPS),
dynamicProps: `["textContent"]`
dynamicProps: `["textContent"]`,
})
})
it('should raise error and ignore children when v-text is present', () => {
const onError = vi.fn()
const ast = transformWithVText(`<div v-text="test">hello</div>`, {
onError
onError,
})
expect(onError.mock.calls).toMatchObject([
[{ code: DOMErrorCodes.X_V_TEXT_WITH_CHILDREN }]
[{ code: DOMErrorCodes.X_V_TEXT_WITH_CHILDREN }],
])
expect((ast.children[0] as PlainElementNode).codegenNode).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({
textContent: {
arguments: [{ content: 'test' }]
}
arguments: [{ content: 'test' }],
},
}),
children: undefined, // <-- children should have been removed
patchFlag: genFlagText(PatchFlags.PROPS),
dynamicProps: `["textContent"]`
dynamicProps: `["textContent"]`,
})
})
it('should raise error if has no expression', () => {
const onError = vi.fn()
transformWithVText(`<div v-text></div>`, {
onError
onError,
})
expect(onError.mock.calls).toMatchObject([
[{ code: DOMErrorCodes.X_V_TEXT_NO_EXPRESSION }]
[{ code: DOMErrorCodes.X_V_TEXT_NO_EXPRESSION }],
])
})
})

View File

@ -1,8 +1,8 @@
import {
SourceLocation,
CompilerError,
type CompilerError,
ErrorCodes,
type SourceLocation,
createCompilerError,
ErrorCodes
} from '@vue/compiler-core'
export interface DOMCompilerError extends CompilerError {
@ -11,12 +11,12 @@ export interface DOMCompilerError extends CompilerError {
export function createDOMCompilerError(
code: DOMErrorCodes,
loc?: SourceLocation
loc?: SourceLocation,
) {
return createCompilerError(
code,
loc,
__DEV__ || !__BROWSER__ ? DOMErrorMessages : undefined
__DEV__ || !__BROWSER__ ? DOMErrorMessages : undefined,
) as DOMCompilerError
}
@ -32,7 +32,7 @@ export enum DOMErrorCodes {
X_V_SHOW_NO_EXPRESSION,
X_TRANSITION_INVALID_CHILDREN,
X_IGNORED_SIDE_EFFECT_TAG,
__EXTEND_POINT__
__EXTEND_POINT__,
}
if (__TEST__) {
@ -43,7 +43,7 @@ if (__TEST__) {
throw new Error(
`DOMErrorCodes need to be updated to ${
ErrorCodes.__EXTEND_POINT__ + 1
} to match extension point from core ErrorCodes.`
} to match extension point from core ErrorCodes.`,
)
}
}
@ -59,5 +59,5 @@ export const DOMErrorMessages: { [code: number]: string } = {
[DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE]: `Unnecessary value binding used alongside v-model. It will interfere with v-model's behavior.`,
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`,
[DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN]: `<Transition> expects exactly one child element or component.`,
[DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG]: `Tags with side effect (<script> and <style>) are ignored in client component templates.`
[DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG]: `Tags with side effect (<script> and <style>) are ignored in client component templates.`,
}

View File

@ -1,13 +1,13 @@
import {
type CodegenResult,
type CompilerOptions,
type DirectiveTransform,
type NodeTransform,
type ParserOptions,
type RootNode,
baseCompile,
baseParse,
CompilerOptions,
CodegenResult,
ParserOptions,
RootNode,
noopDirectiveTransform,
NodeTransform,
DirectiveTransform
} from '@vue/compiler-core'
import { parserOptions } from './parserOptions'
import { transformStyle } from './transforms/transformStyle'
@ -25,7 +25,7 @@ export { parserOptions }
export const DOMNodeTransforms: NodeTransform[] = [
transformStyle,
...(__DEV__ ? [transformTransition] : [])
...(__DEV__ ? [transformTransition] : []),
]
export const DOMDirectiveTransforms: Record<string, DirectiveTransform> = {
@ -34,12 +34,12 @@ export const DOMDirectiveTransforms: Record<string, DirectiveTransform> = {
text: transformVText,
model: transformModel, // override compiler-core
on: transformOn, // override compiler-core
show: transformShow
show: transformShow,
}
export function compile(
src: string | RootNode,
options: CompilerOptions = {}
options: CompilerOptions = {},
): CodegenResult {
return baseCompile(
src,
@ -50,15 +50,15 @@ export function compile(
// by compiler-ssr to generate vnode fallback branches
ignoreSideEffectTags,
...DOMNodeTransforms,
...(options.nodeTransforms || [])
...(options.nodeTransforms || []),
],
directiveTransforms: extend(
{},
DOMDirectiveTransforms,
options.directiveTransforms || {}
options.directiveTransforms || {},
),
transformHoist: __BROWSER__ ? null : stringifyStatic
})
transformHoist: __BROWSER__ ? null : stringifyStatic,
}),
)
}
@ -71,6 +71,6 @@ export { transformStyle } from './transforms/transformStyle'
export {
createDOMCompilerError,
DOMErrorCodes,
DOMErrorMessages
DOMErrorMessages,
} from './errors'
export * from '@vue/compiler-core'

View File

@ -1,5 +1,5 @@
import { ParserOptions, NodeTypes, Namespaces } from '@vue/compiler-core'
import { isVoidTag, isHTMLTag, isSVGTag, isMathMLTag } from '@vue/shared'
import { Namespaces, NodeTypes, type ParserOptions } from '@vue/compiler-core'
import { isHTMLTag, isMathMLTag, isSVGTag, isVoidTag } from '@vue/shared'
import { TRANSITION, TRANSITION_GROUP } from './runtimeHelpers'
import { decodeHtmlBrowser } from './decodeHtmlBrowser'
@ -33,7 +33,7 @@ export const parserOptions: ParserOptions = {
a.name === 'encoding' &&
a.value != null &&
(a.value.content === 'text/html' ||
a.value.content === 'application/xhtml+xml')
a.value.content === 'application/xhtml+xml'),
)
) {
ns = Namespaces.HTML
@ -64,5 +64,5 @@ export const parserOptions: ParserOptions = {
}
}
return ns
}
},
}

View File

@ -24,5 +24,5 @@ registerRuntimeHelpers({
[V_ON_WITH_KEYS]: `withKeys`,
[V_SHOW]: `vShow`,
[TRANSITION]: `Transition`,
[TRANSITION_GROUP]: `TransitionGroup`
[TRANSITION_GROUP]: `TransitionGroup`,
})

View File

@ -1,12 +1,12 @@
import {
NodeTransform,
NodeTypes,
type ComponentNode,
ElementTypes,
ComponentNode,
IfBranchNode
type IfBranchNode,
type NodeTransform,
NodeTypes,
} from '@vue/compiler-core'
import { TRANSITION } from '../runtimeHelpers'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
export const transformTransition: NodeTransform = (node, context) => {
if (
@ -28,9 +28,9 @@ export const transformTransition: NodeTransform = (node, context) => {
{
start: node.children[0].loc.start,
end: node.children[node.children.length - 1].loc.end,
source: ''
}
)
source: '',
},
),
)
}
@ -45,7 +45,7 @@ export const transformTransition: NodeTransform = (node, context) => {
name: 'persisted',
nameLoc: node.loc,
value: undefined,
loc: node.loc
loc: node.loc,
})
}
}
@ -60,7 +60,7 @@ function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
const children = (node.children = node.children.filter(
c =>
c.type !== NodeTypes.COMMENT &&
!(c.type === NodeTypes.TEXT && !c.content.trim())
!(c.type === NodeTypes.TEXT && !c.content.trim()),
))
const child = children[0]
return (

View File

@ -1,4 +1,4 @@
import { NodeTransform, NodeTypes, ElementTypes } from '@vue/compiler-core'
import { ElementTypes, type NodeTransform, NodeTypes } from '@vue/compiler-core'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
export const ignoreSideEffectTags: NodeTransform = (node, context) => {
@ -11,8 +11,8 @@ export const ignoreSideEffectTags: NodeTransform = (node, context) => {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG,
node.loc
)
node.loc,
),
)
context.removeNode()
}

View File

@ -2,40 +2,40 @@
* This module is Node-only.
*/
import {
NodeTypes,
ElementNode,
TransformContext,
TemplateChildNode,
SimpleExpressionNode,
createCallExpression,
HoistTransform,
CREATE_STATIC,
ExpressionNode,
ElementTypes,
PlainElementNode,
JSChildNode,
TextCallNode,
ConstantTypes,
Namespaces
type ElementNode,
ElementTypes,
type ExpressionNode,
type HoistTransform,
type JSChildNode,
Namespaces,
NodeTypes,
type PlainElementNode,
type SimpleExpressionNode,
type TemplateChildNode,
type TextCallNode,
type TransformContext,
createCallExpression,
} from '@vue/compiler-core'
import {
isVoidTag,
escapeHtml,
isBooleanAttr,
isKnownHtmlAttr,
isKnownSvgAttr,
isString,
isSymbol,
isKnownHtmlAttr,
escapeHtml,
toDisplayString,
isVoidTag,
makeMap,
normalizeClass,
normalizeStyle,
stringifyStyle,
makeMap,
isKnownSvgAttr,
isBooleanAttr
toDisplayString,
} from '@vue/shared'
export enum StringifyThresholds {
ELEMENT_WITH_BINDING_COUNT = 5,
NODE_COUNT = 20
NODE_COUNT = 20,
}
type StringifiableNode = PlainElementNode | TextCallNode
@ -87,11 +87,11 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
// combine all currently eligible nodes into a single static vnode call
const staticCall = createCallExpression(context.helper(CREATE_STATIC), [
JSON.stringify(
currentChunk.map(node => stringifyNode(node, context)).join('')
currentChunk.map(node => stringifyNode(node, context)).join(''),
).replace(expReplaceRE, `" + $1 + "`),
// the 2nd argument indicates the number of DOM nodes this static vnode
// will insert / hydrate
String(currentChunk.length)
String(currentChunk.length),
])
// replace the first node's hoisted expression with the static vnode call
replaceHoist(currentChunk[0], staticCall, context)
@ -161,14 +161,14 @@ const isStringifiableAttr = (name: string, ns: Namespaces) => {
const replaceHoist = (
node: StringifiableNode,
replacement: JSChildNode | null,
context: TransformContext
context: TransformContext,
) => {
const hoistToReplace = (node.codegenNode as SimpleExpressionNode).hoisted!
context.hoists[context.hoists.indexOf(hoistToReplace)] = replacement
}
const isNonStringifiable = /*#__PURE__*/ makeMap(
`caption,thead,tr,th,tbody,td,tfoot,colgroup,col`
`caption,thead,tr,th,tbody,td,tfoot,colgroup,col`,
)
/**
@ -248,7 +248,7 @@ function analyzeNode(node: StringifiableNode): [number, number] | false {
function stringifyNode(
node: string | TemplateChildNode,
context: TransformContext
context: TransformContext,
): string {
if (isString(node)) {
return node
@ -277,7 +277,7 @@ function stringifyNode(
function stringifyElement(
node: ElementNode,
context: TransformContext
context: TransformContext,
): string {
let res = `<${node.tag}`
let innerHTML = ''
@ -316,7 +316,7 @@ function stringifyElement(
evaluated = stringifyStyle(normalizeStyle(evaluated))
}
res += ` ${(p.arg as SimpleExpressionNode).content}="${escapeHtml(
evaluated
evaluated,
)}"`
}
} else if (p.name === 'html') {
@ -325,7 +325,7 @@ function stringifyElement(
innerHTML = evaluateConstant(p.exp as SimpleExpressionNode)
} else if (p.name === 'text') {
innerHTML = escapeHtml(
toDisplayString(evaluateConstant(p.exp as SimpleExpressionNode))
toDisplayString(evaluateConstant(p.exp as SimpleExpressionNode)),
)
}
}

View File

@ -1,10 +1,10 @@
import {
NodeTransform,
ConstantTypes,
type NodeTransform,
NodeTypes,
type SimpleExpressionNode,
type SourceLocation,
createSimpleExpression,
SimpleExpressionNode,
SourceLocation,
ConstantTypes
} from '@vue/compiler-core'
import { parseStringStyle } from '@vue/shared'
@ -25,7 +25,7 @@ export const transformStyle: NodeTransform = node => {
arg: createSimpleExpression(`style`, true, p.loc),
exp: parseInlineCSS(p.value.content, p.loc),
modifiers: [],
loc: p.loc
loc: p.loc,
}
}
})
@ -34,13 +34,13 @@ export const transformStyle: NodeTransform = node => {
const parseInlineCSS = (
cssText: string,
loc: SourceLocation
loc: SourceLocation,
): SimpleExpressionNode => {
const normalized = parseStringStyle(cssText)
return createSimpleExpression(
JSON.stringify(normalized),
false,
loc,
ConstantTypes.CAN_STRINGIFY
ConstantTypes.CAN_STRINGIFY,
)
}

View File

@ -1,20 +1,20 @@
import {
DirectiveTransform,
type DirectiveTransform,
createObjectProperty,
createSimpleExpression
createSimpleExpression,
} from '@vue/compiler-core'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
export const transformVHtml: DirectiveTransform = (dir, node, context) => {
const { exp, loc } = dir
if (!exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_HTML_NO_EXPRESSION, loc)
createDOMCompilerError(DOMErrorCodes.X_V_HTML_NO_EXPRESSION, loc),
)
}
if (node.children.length) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_HTML_WITH_CHILDREN, loc)
createDOMCompilerError(DOMErrorCodes.X_V_HTML_WITH_CHILDREN, loc),
)
node.children.length = 0
}
@ -22,8 +22,8 @@ export const transformVHtml: DirectiveTransform = (dir, node, context) => {
props: [
createObjectProperty(
createSimpleExpression(`innerHTML`, true, loc),
exp || createSimpleExpression('', true)
)
]
exp || createSimpleExpression('', true),
),
],
}
}

View File

@ -1,20 +1,20 @@
import {
transformModel as baseTransform,
DirectiveTransform,
type DirectiveTransform,
ElementTypes,
findProp,
NodeTypes,
hasDynamicKeyVBind,
transformModel as baseTransform,
findDir,
isStaticArgOf
findProp,
hasDynamicKeyVBind,
isStaticArgOf,
} from '@vue/compiler-core'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
import {
V_MODEL_CHECKBOX,
V_MODEL_DYNAMIC,
V_MODEL_RADIO,
V_MODEL_SELECT,
V_MODEL_TEXT,
V_MODEL_DYNAMIC
} from '../runtimeHelpers'
export const transformModel: DirectiveTransform = (dir, node, context) => {
@ -28,8 +28,8 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
dir.arg.loc
)
dir.arg.loc,
),
)
}
@ -39,8 +39,8 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
value.loc
)
value.loc,
),
)
}
}
@ -74,8 +74,8 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
dir.loc
)
dir.loc,
),
)
break
default:
@ -108,8 +108,8 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
dir.loc
)
dir.loc,
),
)
}
@ -120,7 +120,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
!(
p.key.type === NodeTypes.SIMPLE_EXPRESSION &&
p.key.content === 'modelValue'
)
),
)
return baseResult

View File

@ -1,21 +1,21 @@
import {
transformOn as baseTransform,
DirectiveTransform,
createObjectProperty,
createCallExpression,
createSimpleExpression,
NodeTypes,
createCompoundExpression,
ExpressionNode,
SimpleExpressionNode,
isStaticExp,
CompilerDeprecationTypes,
TransformContext,
SourceLocation,
checkCompatEnabled
type DirectiveTransform,
type ExpressionNode,
NodeTypes,
type SimpleExpressionNode,
type SourceLocation,
type TransformContext,
transformOn as baseTransform,
checkCompatEnabled,
createCallExpression,
createCompoundExpression,
createObjectProperty,
createSimpleExpression,
isStaticExp,
} from '@vue/compiler-core'
import { V_ON_WITH_MODIFIERS, V_ON_WITH_KEYS } from '../runtimeHelpers'
import { makeMap, capitalize } from '@vue/shared'
import { V_ON_WITH_KEYS, V_ON_WITH_MODIFIERS } from '../runtimeHelpers'
import { capitalize, makeMap } from '@vue/shared'
const isEventOptionModifier = /*#__PURE__*/ makeMap(`passive,once,capture`)
const isNonKeyModifier = /*#__PURE__*/ makeMap(
@ -24,20 +24,20 @@ const isNonKeyModifier = /*#__PURE__*/ makeMap(
// system modifiers + exact
`ctrl,shift,alt,meta,exact,` +
// mouse
`middle`
`middle`,
)
// left & right could be mouse or key modifiers based on event type
const maybeKeyModifier = /*#__PURE__*/ makeMap('left,right')
const isKeyboardEvent = /*#__PURE__*/ makeMap(
`onkeyup,onkeydown,onkeypress`,
true
true,
)
const resolveModifiers = (
key: ExpressionNode,
modifiers: string[],
context: TransformContext,
loc: SourceLocation
loc: SourceLocation,
) => {
const keyModifiers = []
const nonKeyModifiers = []
@ -52,7 +52,7 @@ const resolveModifiers = (
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_V_ON_NATIVE,
context,
loc
loc,
)
) {
eventOptionModifiers.push(modifier)
@ -86,7 +86,7 @@ const resolveModifiers = (
return {
keyModifiers,
nonKeyModifiers,
eventOptionModifiers
eventOptionModifiers,
}
}
@ -101,7 +101,7 @@ const transformClick = (key: ExpressionNode, event: string) => {
key,
`) === "onClick" ? "${event}" : (`,
key,
`)`
`)`,
])
: key
}
@ -126,7 +126,7 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
if (nonKeyModifiers.length) {
handlerExp = createCallExpression(context.helper(V_ON_WITH_MODIFIERS), [
handlerExp,
JSON.stringify(nonKeyModifiers)
JSON.stringify(nonKeyModifiers),
])
}
@ -137,7 +137,7 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
) {
handlerExp = createCallExpression(context.helper(V_ON_WITH_KEYS), [
handlerExp,
JSON.stringify(keyModifiers)
JSON.stringify(keyModifiers),
])
}
@ -149,7 +149,7 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
}
return {
props: [createObjectProperty(key, handlerExp)]
props: [createObjectProperty(key, handlerExp)],
}
})
}

View File

@ -1,17 +1,17 @@
import { DirectiveTransform } from '@vue/compiler-core'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
import type { DirectiveTransform } from '@vue/compiler-core'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
import { V_SHOW } from '../runtimeHelpers'
export const transformShow: DirectiveTransform = (dir, node, context) => {
const { exp, loc } = dir
if (!exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, loc)
createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, loc),
)
}
return {
props: [],
needRuntime: context.helper(V_SHOW)
needRuntime: context.helper(V_SHOW),
}
}

View File

@ -1,23 +1,23 @@
import {
DirectiveTransform,
createObjectProperty,
createSimpleExpression,
type DirectiveTransform,
TO_DISPLAY_STRING,
createCallExpression,
getConstantType
createObjectProperty,
createSimpleExpression,
getConstantType,
} from '@vue/compiler-core'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
export const transformVText: DirectiveTransform = (dir, node, context) => {
const { exp, loc } = dir
if (!exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc)
createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc),
)
}
if (node.children.length) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc)
createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc),
)
node.children.length = 0
}
@ -31,10 +31,10 @@ export const transformVText: DirectiveTransform = (dir, node, context) => {
: createCallExpression(
context.helperString(TO_DISPLAY_STRING),
[exp],
loc
loc,
)
: createSimpleExpression('', true)
)
]
: createSimpleExpression('', true),
),
],
}
}

View File

@ -1,5 +1,5 @@
import { BindingTypes } from '@vue/compiler-core'
import { compileSFCScript as compile, assertCode, mockId } from './utils'
import { assertCode, compileSFCScript as compile, mockId } from './utils'
describe('SFC compile <script setup>', () => {
test('should compile JS syntax', () => {
@ -34,7 +34,7 @@ describe('SFC compile <script setup>', () => {
expect(content).toMatch(
`return { get aa() { return aa }, set aa(v) { aa = v }, ` +
`bb, cc, dd, get a() { return a }, set a(v) { a = v }, b, c, d, ` +
`get xx() { return xx }, get x() { return x } }`
`get xx() { return xx }, get x() { return x } }`,
)
expect(bindings).toStrictEqual({
x: BindingTypes.SETUP_MAYBE_REF,
@ -46,7 +46,7 @@ describe('SFC compile <script setup>', () => {
aa: BindingTypes.SETUP_LET,
bb: BindingTypes.LITERAL_CONST,
cc: BindingTypes.SETUP_CONST,
dd: BindingTypes.SETUP_CONST
dd: BindingTypes.SETUP_CONST,
})
assertCode(content)
})
@ -63,7 +63,7 @@ describe('SFC compile <script setup>', () => {
bar: BindingTypes.SETUP_MAYBE_REF,
baz: BindingTypes.SETUP_MAYBE_REF,
y: BindingTypes.SETUP_MAYBE_REF,
z: BindingTypes.SETUP_MAYBE_REF
z: BindingTypes.SETUP_MAYBE_REF,
})
assertCode(content)
})
@ -209,7 +209,7 @@ describe('SFC compile <script setup>', () => {
compile(`<script setup>
import { ref } from 'vue'
import 'foo/css'
</script>`).content
</script>`).content,
)
})
@ -220,7 +220,7 @@ describe('SFC compile <script setup>', () => {
import a from 'a' // comment
import b from 'b'
</script>
`).content
`).content,
)
})
@ -232,7 +232,7 @@ describe('SFC compile <script setup>', () => {
defineProps(['foo'])
defineEmits(['bar'])
const r = ref(0)
</script>`).content
</script>`).content,
)
})
@ -249,11 +249,11 @@ describe('SFC compile <script setup>', () => {
color: v-bind(msg)
}
</style>
`
`,
)
assertCode(content)
expect(content).toMatch(
`import { useCssVars as _useCssVars, unref as _unref } from 'vue'`
`import { useCssVars as _useCssVars, unref as _unref } from 'vue'`,
)
expect(content).toMatch(`import { useCssVars, ref } from 'vue'`)
})
@ -270,7 +270,7 @@ describe('SFC compile <script setup>', () => {
`)
assertCode(content)
expect(content.indexOf(`import { x }`)).toEqual(
content.lastIndexOf(`import { x }`)
content.lastIndexOf(`import { x }`),
)
})
@ -288,7 +288,7 @@ describe('SFC compile <script setup>', () => {
ref: BindingTypes.SETUP_MAYBE_REF,
reactive: BindingTypes.SETUP_MAYBE_REF,
foo: BindingTypes.SETUP_MAYBE_REF,
bar: BindingTypes.SETUP_MAYBE_REF
bar: BindingTypes.SETUP_MAYBE_REF,
})
})
@ -305,7 +305,7 @@ describe('SFC compile <script setup>', () => {
_reactive: BindingTypes.SETUP_MAYBE_REF,
_ref: BindingTypes.SETUP_MAYBE_REF,
foo: BindingTypes.SETUP_MAYBE_REF,
bar: BindingTypes.SETUP_MAYBE_REF
bar: BindingTypes.SETUP_MAYBE_REF,
})
})
@ -318,7 +318,7 @@ describe('SFC compile <script setup>', () => {
`)
expect(bindings).toStrictEqual({
bar: BindingTypes.SETUP_REACTIVE_CONST,
x: BindingTypes.SETUP_CONST
x: BindingTypes.SETUP_CONST,
})
})
})
@ -334,7 +334,7 @@ describe('SFC compile <script setup>', () => {
`)
assertCode(content)
expect(bindings).toStrictEqual({
foo: BindingTypes.SETUP_MAYBE_REF
foo: BindingTypes.SETUP_MAYBE_REF,
})
})
})
@ -363,7 +363,7 @@ describe('SFC compile <script setup>', () => {
// foo: lowercase component
expect(content).toMatch(
`return { fooBar, get FooBaz() { return FooBaz }, ` +
`get FooQux() { return FooQux }, get foo() { return foo } }`
`get FooQux() { return FooQux }, get foo() { return foo } }`,
)
assertCode(content)
})
@ -396,7 +396,7 @@ describe('SFC compile <script setup>', () => {
`)
expect(content).toMatch(
`return { get FooBar() { return FooBar }, get foo() { return foo }, ` +
`get bar() { return bar }, get baz() { return baz } }`
`get bar() { return bar }, get baz() { return baz } }`,
)
assertCode(content)
})
@ -413,7 +413,7 @@ describe('SFC compile <script setup>', () => {
</template>
`)
expect(content).toMatch(
`return { cond, get bar() { return bar }, get baz() { return baz } }`
`return { cond, get bar() { return bar }, get baz() { return baz } }`,
)
assertCode(content)
})
@ -431,7 +431,7 @@ describe('SFC compile <script setup>', () => {
// y: should not be matched by {{ yy }} or 'y' in binding exps
// x$y: #4274 should escape special chars when creating Regex
expect(content).toMatch(
`return { get x() { return x }, get z() { return z }, get x$y() { return x$y } }`
`return { get x() { return x }, get z() { return z }, get x$y() { return x$y } }`,
)
assertCode(content)
})
@ -448,7 +448,7 @@ describe('SFC compile <script setup>', () => {
`)
// VAR2 should not be matched
expect(content).toMatch(
`return { get VAR() { return VAR }, get VAR3() { return VAR3 } }`
`return { get VAR() { return VAR }, get VAR3() { return VAR3 } }`,
)
assertCode(content)
})
@ -465,7 +465,7 @@ describe('SFC compile <script setup>', () => {
</template>
`)
expect(content).toMatch(
`return { get FooBaz() { return FooBaz }, get Last() { return Last } }`
`return { get FooBaz() { return FooBaz }, get Last() { return Last } }`,
)
assertCode(content)
})
@ -514,7 +514,7 @@ describe('SFC compile <script setup>', () => {
</template>
`)
expect(content).toMatch(
'return { get foo() { return foo }, get bar() { return bar }, get Baz() { return Baz } }'
'return { get foo() { return foo }, get bar() { return bar }, get Baz() { return Baz } }',
)
assertCode(content)
})
@ -573,7 +573,7 @@ describe('SFC compile <script setup>', () => {
<div>static</div>
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
// check snapshot and make sure helper imports and
// hoists are placed correctly.
@ -591,7 +591,7 @@ describe('SFC compile <script setup>', () => {
defineExpose({ count })
</script>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
assertCode(content)
expect(content).toMatch(`setup(__props, { expose: __expose })`)
@ -612,7 +612,7 @@ describe('SFC compile <script setup>', () => {
<some-other-comp/>
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
expect(content).toMatch('[_unref(vMyDir)]')
expect(content).toMatch('_createVNode(ChildComp)')
@ -641,7 +641,7 @@ describe('SFC compile <script setup>', () => {
{{ tree.foo() }}
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
// no need to unref vue component import
expect(content).toMatch(`createVNode(Foo,`)
@ -680,7 +680,7 @@ describe('SFC compile <script setup>', () => {
<input v-model="lett">
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
// known const ref: set value
expect(content).toMatch(`(count).value = $event`)
@ -688,7 +688,7 @@ describe('SFC compile <script setup>', () => {
expect(content).toMatch(`_isRef(maybe) ? (maybe).value = $event : null`)
// let: handle both cases
expect(content).toMatch(
`_isRef(lett) ? (lett).value = $event : lett = $event`
`_isRef(lett) ? (lett).value = $event : lett = $event`,
)
assertCode(content)
})
@ -708,7 +708,7 @@ describe('SFC compile <script setup>', () => {
<input v-model="foo">
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
expect(content).not.toMatch(`_isRef(foo)`)
})
@ -746,7 +746,7 @@ describe('SFC compile <script setup>', () => {
}"/>
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
// known const ref: set value
expect(content).toMatch(`count.value = 1`)
@ -754,7 +754,7 @@ describe('SFC compile <script setup>', () => {
expect(content).toMatch(`maybe.value = count.value`)
// let: handle both cases
expect(content).toMatch(
`_isRef(lett) ? lett.value = count.value : lett = count.value`
`_isRef(lett) ? lett.value = count.value : lett = count.value`,
)
expect(content).toMatch(`_isRef(v) ? v.value += 1 : v += 1`)
expect(content).toMatch(`_isRef(v) ? v.value -= 1 : v -= 1`)
@ -780,7 +780,7 @@ describe('SFC compile <script setup>', () => {
<div @click="--lett"/>
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
// known const ref: set value
expect(content).toMatch(`count.value++`)
@ -809,7 +809,7 @@ describe('SFC compile <script setup>', () => {
<div @click="({ lett } = val)"/>
</template>
`,
{ inlineTemplate: true }
{ inlineTemplate: true },
)
// known const ref: set value
expect(content).toMatch(`({ count: count.value } = val)`)
@ -840,9 +840,9 @@ describe('SFC compile <script setup>', () => {
{
inlineTemplate: true,
templateOptions: {
ssr: true
}
}
ssr: true,
},
},
)
expect(content).toMatch(`\n __ssrInlineRender: true,\n`)
expect(content).toMatch(`return (_ctx, _push`)
@ -866,9 +866,9 @@ describe('SFC compile <script setup>', () => {
</template>
`,
{
inlineTemplate: false
}
)
inlineTemplate: false,
},
),
).not.toThrowError()
})
})
@ -887,11 +887,11 @@ describe('SFC compile <script setup>', () => {
const { content, bindings } = compile(
`<script setup lang="ts">
enum Foo { A = 123 }
</script>`
</script>`,
)
assertCode(content)
expect(bindings).toStrictEqual({
Foo: BindingTypes.LITERAL_CONST
Foo: BindingTypes.LITERAL_CONST,
})
})
@ -904,14 +904,14 @@ describe('SFC compile <script setup>', () => {
</script>
<script setup lang="ts">
enum Foo { A = 123 }
</script>`
</script>`,
)
assertCode(content)
expect(bindings).toStrictEqual({
D: BindingTypes.LITERAL_CONST,
C: BindingTypes.LITERAL_CONST,
B: BindingTypes.LITERAL_CONST,
Foo: BindingTypes.LITERAL_CONST
Foo: BindingTypes.LITERAL_CONST,
})
})
@ -920,11 +920,11 @@ describe('SFC compile <script setup>', () => {
`<script setup lang="ts">
const enum Foo { A = 123 }
</script>`,
{ hoistStatic: true }
{ hoistStatic: true },
)
assertCode(content)
expect(bindings).toStrictEqual({
Foo: BindingTypes.LITERAL_CONST
Foo: BindingTypes.LITERAL_CONST,
})
})
@ -933,7 +933,7 @@ describe('SFC compile <script setup>', () => {
`<script setup lang="ts">
import type { Foo } from './main.ts'
import { type Bar, Baz } from './main.ts'
</script>`
</script>`,
)
expect(content).toMatch(`return { get Baz() { return Baz } }`)
assertCode(content)
@ -1057,7 +1057,7 @@ describe('SFC compile <script setup>', () => {
// class method
assertAwaitDetection(
`const cls = class Foo { async method() { await bar }}`,
false
false,
)
})
})
@ -1065,7 +1065,7 @@ describe('SFC compile <script setup>', () => {
describe('errors', () => {
test('<script> and <script setup> must have same lang', () => {
expect(() =>
compile(`<script>foo()</script><script setup lang="ts">bar()</script>`)
compile(`<script>foo()</script><script setup lang="ts">bar()</script>`),
).toThrow(`<script> and <script setup> must have the same language type`)
})
@ -1075,20 +1075,20 @@ describe('SFC compile <script setup>', () => {
expect(() =>
compile(`<script setup>
export const a = 1
</script>`)
</script>`),
).toThrow(moduleErrorMsg)
expect(() =>
compile(`<script setup>
export * from './foo'
</script>`)
</script>`),
).toThrow(moduleErrorMsg)
expect(() =>
compile(`<script setup>
const bar = 1
export { bar as default }
</script>`)
</script>`),
).toThrow(moduleErrorMsg)
})
@ -1101,14 +1101,14 @@ describe('SFC compile <script setup>', () => {
default: () => bar
}
})
</script>`)
</script>`),
).toThrow(`cannot reference locally declared variables`)
expect(() =>
compile(`<script setup>
let bar = 'hello'
defineEmits([bar])
</script>`)
</script>`),
).toThrow(`cannot reference locally declared variables`)
// #4644
@ -1121,7 +1121,7 @@ describe('SFC compile <script setup>', () => {
default: () => bar
}
})
</script>`)
</script>`),
).not.toThrow(`cannot reference locally declared variables`)
})
@ -1137,7 +1137,7 @@ describe('SFC compile <script setup>', () => {
defineEmits({
foo: bar => bar > 1
})
</script>`).content
</script>`).content,
)
})
@ -1153,7 +1153,7 @@ describe('SFC compile <script setup>', () => {
defineEmits({
foo: () => bar > 1
})
</script>`).content
</script>`).content,
)
})
})
@ -1187,7 +1187,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS
bar: BindingTypes.PROPS,
})
expect(bindings!.__isScriptSetup).toBe(false)
})
@ -1211,7 +1211,7 @@ describe('SFC analyze <script> bindings', () => {
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS,
baz: BindingTypes.PROPS,
qux: BindingTypes.PROPS
qux: BindingTypes.PROPS,
})
expect(bindings!.__isScriptSetup).toBe(false)
})
@ -1232,7 +1232,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.SETUP_MAYBE_REF,
bar: BindingTypes.SETUP_MAYBE_REF
bar: BindingTypes.SETUP_MAYBE_REF,
})
expect(bindings!.__isScriptSetup).toBe(false)
})
@ -1247,7 +1247,7 @@ describe('SFC analyze <script> bindings', () => {
</script>
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.LITERAL_CONST
foo: BindingTypes.LITERAL_CONST,
})
})
@ -1267,7 +1267,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.SETUP_MAYBE_REF,
bar: BindingTypes.SETUP_MAYBE_REF
bar: BindingTypes.SETUP_MAYBE_REF,
})
expect(bindings!.__isScriptSetup).toBe(false)
})
@ -1288,7 +1288,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.DATA,
bar: BindingTypes.DATA
bar: BindingTypes.DATA,
})
})
@ -1321,7 +1321,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.OPTIONS,
bar: BindingTypes.OPTIONS
bar: BindingTypes.OPTIONS,
})
})
@ -1335,7 +1335,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.OPTIONS,
bar: BindingTypes.OPTIONS
bar: BindingTypes.OPTIONS,
})
})
@ -1352,7 +1352,7 @@ describe('SFC analyze <script> bindings', () => {
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.OPTIONS,
bar: BindingTypes.OPTIONS
bar: BindingTypes.OPTIONS,
})
})
@ -1389,7 +1389,7 @@ describe('SFC analyze <script> bindings', () => {
baz: BindingTypes.SETUP_MAYBE_REF,
qux: BindingTypes.DATA,
quux: BindingTypes.OPTIONS,
quuz: BindingTypes.OPTIONS
quuz: BindingTypes.OPTIONS,
})
})
@ -1416,7 +1416,7 @@ describe('SFC analyze <script> bindings', () => {
c: BindingTypes.LITERAL_CONST,
d: BindingTypes.SETUP_MAYBE_REF,
e: BindingTypes.SETUP_LET,
foo: BindingTypes.PROPS
foo: BindingTypes.PROPS,
})
})
@ -1427,8 +1427,8 @@ describe('SFC analyze <script> bindings', () => {
<template>{{ a }}</template>`,
undefined,
{
filename: 'FooBar.vue'
}
filename: 'FooBar.vue',
},
)
expect(content).toMatch(`export default {
__name: 'FooBar'`)
@ -1446,8 +1446,8 @@ describe('SFC analyze <script> bindings', () => {
<template>{{ a }}</template>`,
undefined,
{
filename: 'FooBar.vue'
}
filename: 'FooBar.vue',
},
)
expect(content).not.toMatch(`name: 'FooBar'`)
expect(content).toMatch(`name: 'Baz'`)
@ -1466,8 +1466,8 @@ describe('SFC analyze <script> bindings', () => {
<template>{{ a }}</template>`,
undefined,
{
filename: 'FooBar.vue'
}
filename: 'FooBar.vue',
},
)
expect(content).not.toMatch(`name: 'FooBar'`)
expect(content).toMatch(`name: 'Baz'`)
@ -1483,8 +1483,8 @@ describe('SFC genDefaultAs', () => {
export default {}
</script>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(`const _sfc_ = {}`)
@ -1500,8 +1500,8 @@ describe('SFC genDefaultAs', () => {
.foo { color: v-bind(x) }
</style>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).not.toMatch('__default__')
@ -1518,12 +1518,12 @@ describe('SFC genDefaultAs', () => {
const a = 1
</script>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`,
)
assertCode(content)
})
@ -1537,12 +1537,12 @@ describe('SFC genDefaultAs', () => {
const a = 1
</script>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`
`const _sfc_ = /*#__PURE__*/Object.assign(__default__`,
)
assertCode(content)
})
@ -1553,8 +1553,8 @@ describe('SFC genDefaultAs', () => {
const a = 1
</script>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(`const _sfc_ = {\n setup`)
@ -1567,8 +1567,8 @@ describe('SFC genDefaultAs', () => {
const a = 1
</script>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(`const _sfc_ = /*#__PURE__*/_defineComponent(`)
@ -1584,12 +1584,12 @@ describe('SFC genDefaultAs', () => {
const a = 1
</script>`,
{
genDefaultAs: '_sfc_'
}
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(
`const _sfc_ = /*#__PURE__*/_defineComponent({\n ...__default__`
`const _sfc_ = /*#__PURE__*/_defineComponent({\n ...__default__`,
)
assertCode(content)
})
@ -1600,12 +1600,12 @@ describe('SFC genDefaultAs', () => {
import { toRef } from 'vue'
const props = defineProps<{foo: string}>()
const foo = toRef(() => props.foo)
</script>`
</script>`,
)
expect(bindings).toStrictEqual({
toRef: BindingTypes.SETUP_CONST,
props: BindingTypes.SETUP_REACTIVE_CONST,
foo: BindingTypes.SETUP_REF
foo: BindingTypes.SETUP_REF,
})
})
@ -1622,7 +1622,7 @@ describe('SFC genDefaultAs', () => {
compile(`
<script setup>
import { foo } from './foo.js' assert { type: 'foobar' }
</script>`)
</script>`),
).toThrow()
})
@ -1635,9 +1635,9 @@ describe('SFC genDefaultAs', () => {
`,
{
babelParserPlugins: [
['importAttributes', { deprecatedAssertSyntax: true }]
]
}
['importAttributes', { deprecatedAssertSyntax: true }],
],
},
)
assertCode(content)
})

View File

@ -1,5 +1,5 @@
import { BindingTypes } from '@vue/compiler-core'
import { compileSFCScript as compile, assertCode } from '../utils'
import { assertCode, compileSFCScript as compile } from '../utils'
describe('defineEmits', () => {
test('basic usage', () => {
@ -10,13 +10,13 @@ const myEmit = defineEmits(['foo', 'bar'])
`)
assertCode(content)
expect(bindings).toStrictEqual({
myEmit: BindingTypes.SETUP_CONST
myEmit: BindingTypes.SETUP_CONST,
})
// should remove defineEmits import and call
expect(content).not.toMatch('defineEmits')
// should generate correct setup signature
expect(content).toMatch(
`setup(__props, { expose: __expose, emit: __emit }) {`
`setup(__props, { expose: __expose, emit: __emit }) {`,
)
expect(content).toMatch('const myEmit = __emit')
// should include context options in default export
@ -226,9 +226,9 @@ const emit = defineEmits(['a', 'b'])
foo: []
(e: 'hi'): void
}>()
</script>`)
</script>`),
).toThrow(
`defineEmits() type cannot mixed call signature and property syntax.`
`defineEmits() type cannot mixed call signature and property syntax.`,
)
})
})

View File

@ -1,4 +1,4 @@
import { compileSFCScript as compile, assertCode } from '../utils'
import { assertCode, compileSFCScript as compile } from '../utils'
test('defineExpose()', () => {
const { content } = compile(`

View File

@ -1,5 +1,5 @@
import { BindingTypes } from '@vue/compiler-core'
import { compileSFCScript as compile, assertCode } from '../utils'
import { assertCode, compileSFCScript as compile } from '../utils'
describe('defineModel()', () => {
test('basic usage', () => {
@ -10,7 +10,7 @@ describe('defineModel()', () => {
const c = defineModel('count')
const toString = defineModel('toString', { type: Function })
</script>
`
`,
)
assertCode(content)
expect(content).toMatch('props: {')
@ -18,10 +18,10 @@ describe('defineModel()', () => {
expect(content).toMatch('"count": {},')
expect(content).toMatch('"toString": { type: Function },')
expect(content).toMatch(
'emits: ["update:modelValue", "update:count", "update:toString"],'
'emits: ["update:modelValue", "update:count", "update:toString"],',
)
expect(content).toMatch(
`const modelValue = _useModel(__props, "modelValue")`
`const modelValue = _useModel(__props, "modelValue")`,
)
expect(content).toMatch(`const c = _useModel(__props, "count")`)
expect(content).toMatch(`return { modelValue, c, toString }`)
@ -31,7 +31,7 @@ describe('defineModel()', () => {
modelValue: BindingTypes.SETUP_REF,
count: BindingTypes.PROPS,
c: BindingTypes.SETUP_REF,
toString: BindingTypes.SETUP_REF
toString: BindingTypes.SETUP_REF,
})
})
@ -43,7 +43,7 @@ describe('defineModel()', () => {
defineEmits(['change'])
const count = defineModel({ default: 0 })
</script>
`
`,
)
assertCode(content)
expect(content).toMatch(`props: /*#__PURE__*/_mergeModels({ foo: String }`)
@ -53,7 +53,7 @@ describe('defineModel()', () => {
expect(bindings).toStrictEqual({
count: BindingTypes.SETUP_REF,
foo: BindingTypes.PROPS,
modelValue: BindingTypes.PROPS
modelValue: BindingTypes.PROPS,
})
})
@ -64,7 +64,7 @@ describe('defineModel()', () => {
defineProps(['foo', 'bar'])
const count = defineModel('count')
</script>
`
`,
)
assertCode(content)
expect(content).toMatch(`props: /*#__PURE__*/_mergeModels(['foo', 'bar'], {
@ -75,7 +75,7 @@ describe('defineModel()', () => {
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS,
count: BindingTypes.SETUP_REF
count: BindingTypes.SETUP_REF,
})
})
@ -91,7 +91,7 @@ describe('defineModel()', () => {
const local = true
const hoist = defineModel('hoist', { local })
</script>`
</script>`,
)
assertCode(content)
expect(content).toMatch(`_useModel(__props, "modelValue", { local: true })`)
@ -111,21 +111,21 @@ describe('defineModel()', () => {
const disabled = defineModel<number>('disabled', { required: false })
const any = defineModel<any | boolean>('any')
</script>
`
`,
)
assertCode(content)
expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
expect(content).toMatch('"count": { type: Number }')
expect(content).toMatch(
'"disabled": { type: Number, ...{ required: false } }'
'"disabled": { type: Number, ...{ required: false } }',
)
expect(content).toMatch('"any": { type: Boolean, skipCheck: true }')
expect(content).toMatch(
'emits: ["update:modelValue", "update:count", "update:disabled", "update:any"]'
'emits: ["update:modelValue", "update:count", "update:disabled", "update:any"]',
)
expect(content).toMatch(
`const modelValue = _useModel(__props, "modelValue")`
`const modelValue = _useModel(__props, "modelValue")`,
)
expect(content).toMatch(`const count = _useModel(__props, "count")`)
expect(content).toMatch(`const disabled = _useModel(__props, "disabled")`)
@ -135,7 +135,7 @@ describe('defineModel()', () => {
modelValue: BindingTypes.SETUP_REF,
count: BindingTypes.SETUP_REF,
disabled: BindingTypes.SETUP_REF,
any: BindingTypes.SETUP_REF
any: BindingTypes.SETUP_REF,
})
})
@ -150,21 +150,21 @@ describe('defineModel()', () => {
const optional = defineModel<string>('optional', { required: false })
</script>
`,
{ isProd: true }
{ isProd: true },
)
assertCode(content)
expect(content).toMatch('"modelValue": { type: Boolean }')
expect(content).toMatch('"fn": {}')
expect(content).toMatch(
'"fnWithDefault": { type: Function, ...{ default: () => null } },'
'"fnWithDefault": { type: Function, ...{ default: () => null } },',
)
expect(content).toMatch('"str": {}')
expect(content).toMatch('"optional": { required: false }')
expect(content).toMatch(
'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]'
'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]',
)
expect(content).toMatch(
`const modelValue = _useModel(__props, "modelValue")`
`const modelValue = _useModel(__props, "modelValue")`,
)
expect(content).toMatch(`const fn = _useModel(__props, "fn")`)
expect(content).toMatch(`const str = _useModel(__props, "str")`)
@ -173,7 +173,7 @@ describe('defineModel()', () => {
fn: BindingTypes.SETUP_REF,
fnWithDefault: BindingTypes.SETUP_REF,
str: BindingTypes.SETUP_REF,
optional: BindingTypes.SETUP_REF
optional: BindingTypes.SETUP_REF,
})
})
})

View File

@ -1,4 +1,4 @@
import { compileSFCScript as compile, assertCode } from '../utils'
import { assertCode, compileSFCScript as compile } from '../utils'
describe('defineOptions()', () => {
test('basic usage', () => {
@ -12,7 +12,7 @@ describe('defineOptions()', () => {
expect(content).not.toMatch('defineOptions')
// should include context options in default export
expect(content).toMatch(
`export default /*#__PURE__*/Object.assign({ name: 'FooApp' }, `
`export default /*#__PURE__*/Object.assign({ name: 'FooApp' }, `,
)
})
@ -35,7 +35,7 @@ describe('defineOptions()', () => {
defineOptions({ name: 'FooApp' })
defineOptions({ name: 'BarApp' })
</script>
`)
`),
).toThrowError('[@vue/compiler-sfc] duplicate defineOptions() call')
})
@ -45,9 +45,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ props: { foo: String } })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.',
)
expect(() =>
@ -55,9 +55,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ emits: ['update'] })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead.'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead.',
)
expect(() =>
@ -65,9 +65,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ expose: ['foo'] })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead.'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead.',
)
expect(() =>
@ -75,9 +75,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ slots: ['foo'] })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead.'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead.',
)
})
@ -87,9 +87,9 @@ describe('defineOptions()', () => {
<script setup lang="ts">
defineOptions<{ name: 'FooApp' }>()
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot accept type arguments'
'[@vue/compiler-sfc] defineOptions() cannot accept type arguments',
)
})
@ -99,9 +99,9 @@ describe('defineOptions()', () => {
<script setup lang="ts">
defineOptions({ props: [] } as any)
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.',
)
})
@ -111,9 +111,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ props: ['foo'] })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead',
)
expect(() =>
@ -121,9 +121,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ emits: ['update'] })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead',
)
expect(() =>
@ -131,9 +131,9 @@ describe('defineOptions()', () => {
<script setup>
defineOptions({ expose: ['foo'] })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead',
)
expect(() =>
@ -141,9 +141,9 @@ describe('defineOptions()', () => {
<script setup lang="ts">
defineOptions({ slots: Object })
</script>
`)
`),
).toThrowError(
'[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead'
'[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead',
)
})
})

View File

@ -1,5 +1,5 @@
import { BindingTypes } from '@vue/compiler-core'
import { compileSFCScript as compile, assertCode } from '../utils'
import { assertCode, compileSFCScript as compile } from '../utils'
describe('defineProps', () => {
test('basic usage', () => {
@ -17,7 +17,7 @@ const bar = 1
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
bar: BindingTypes.LITERAL_CONST,
props: BindingTypes.SETUP_REACTIVE_CONST
props: BindingTypes.SETUP_REACTIVE_CONST,
})
// should remove defineOptions import and call
@ -146,11 +146,11 @@ const props = defineProps({ foo: String })
expect(content).toMatch(`symbol: { type: Symbol, required: true }`)
expect(content).toMatch(`error: { type: Error, required: true }`)
expect(content).toMatch(
`objectOrFn: { type: [Function, Object], required: true },`
`objectOrFn: { type: [Function, Object], required: true },`,
)
expect(content).toMatch(`extract: { type: Number, required: true }`)
expect(content).toMatch(
`exclude: { type: [Number, Boolean], required: true }`
`exclude: { type: [Number, Boolean], required: true }`,
)
expect(content).toMatch(`uppercase: { type: String, required: true }`)
expect(content).toMatch(`params: { type: Array, required: true }`)
@ -158,10 +158,10 @@ const props = defineProps({ foo: String })
expect(content).toMatch(`union: { type: [String, Number], required: true }`)
expect(content).toMatch(`literalUnion: { type: String, required: true }`)
expect(content).toMatch(
`literalUnionNumber: { type: Number, required: true }`
`literalUnionNumber: { type: Number, required: true }`,
)
expect(content).toMatch(
`literalUnionMixed: { type: [String, Number, Boolean], required: true }`
`literalUnionMixed: { type: [String, Number, Boolean], required: true }`,
)
expect(content).toMatch(`intersection: { type: Object, required: true }`)
expect(content).toMatch(`intersection2: { type: String, required: true }`)
@ -171,13 +171,13 @@ const props = defineProps({ foo: String })
expect(content).toMatch(`unknownUnion: { type: null, required: true }`)
// intersection containing unknown type: narrow to the known types
expect(content).toMatch(
`unknownIntersection: { type: Object, required: true },`
`unknownIntersection: { type: Object, required: true },`,
)
expect(content).toMatch(
`unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`
`unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`,
)
expect(content).toMatch(
`unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`
`unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`,
)
expect(bindings).toStrictEqual({
string: BindingTypes.PROPS,
@ -218,7 +218,7 @@ const props = defineProps({ foo: String })
unknownUnion: BindingTypes.PROPS,
unknownIntersection: BindingTypes.PROPS,
unknownUnionWithBoolean: BindingTypes.PROPS,
unknownUnionWithFunction: BindingTypes.PROPS
unknownUnionWithFunction: BindingTypes.PROPS,
})
})
@ -232,7 +232,7 @@ const props = defineProps({ foo: String })
assertCode(content)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS
x: BindingTypes.PROPS,
})
})
@ -257,7 +257,7 @@ const props = defineProps({ foo: String })
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS,
y: BindingTypes.PROPS,
z: BindingTypes.PROPS
z: BindingTypes.PROPS,
})
})
@ -271,7 +271,7 @@ const props = defineProps({ foo: String })
assertCode(content)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS
x: BindingTypes.PROPS,
})
})
@ -287,7 +287,7 @@ const props = defineProps({ foo: String })
assertCode(content)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS
x: BindingTypes.PROPS,
})
})
@ -301,7 +301,7 @@ const props = defineProps({ foo: String })
assertCode(content)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS
x: BindingTypes.PROPS,
})
})
@ -315,7 +315,7 @@ const props = defineProps({ foo: String })
assertCode(content)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS
x: BindingTypes.PROPS,
})
})
@ -328,7 +328,7 @@ const props = defineProps({ foo: String })
expect(content).toMatch(`props: ['foo']`)
assertCode(content)
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS
foo: BindingTypes.PROPS,
})
})
@ -354,21 +354,21 @@ const props = defineProps({ foo: String })
`)
assertCode(content)
expect(content).toMatch(
`foo: { type: String, required: false, default: 'hi' }`
`foo: { type: String, required: false, default: 'hi' }`,
)
expect(content).toMatch(`bar: { type: Number, required: false }`)
expect(content).toMatch(`baz: { type: Boolean, required: true }`)
expect(content).toMatch(
`qux: { type: Function, required: false, default() { return 1 } }`
`qux: { type: Function, required: false, default() { return 1 } }`,
)
expect(content).toMatch(
`quux: { type: Function, required: false, default() { } }`
`quux: { type: Function, required: false, default() { } }`,
)
expect(content).toMatch(
`quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } }`
`quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } }`,
)
expect(content).toMatch(
`fred: { type: String, required: false, get default() { return 'fred' } }`
`fred: { type: String, required: false, get default() { return 'fred' } }`,
)
expect(content).toMatch(`const props = __props`)
expect(bindings).toStrictEqual({
@ -379,7 +379,7 @@ const props = defineProps({ foo: String })
quux: BindingTypes.PROPS,
quuxx: BindingTypes.PROPS,
fred: BindingTypes.PROPS,
props: BindingTypes.SETUP_CONST
props: BindingTypes.SETUP_CONST,
})
})
@ -415,7 +415,7 @@ const props = defineProps({ foo: String })
})
</script>
`,
{ isProd: true }
{ isProd: true },
)
assertCode(content)
expect(content).toMatch(`const props = __props`)
@ -446,7 +446,7 @@ const props = defineProps({ foo: String })
foo: { type: String, required: false },
bar: { type: Number, required: false },
baz: { type: Boolean, required: true }
}, { ...defaults })`.trim()
}, { ...defaults })`.trim(),
)
})
@ -469,7 +469,7 @@ const props = defineProps({ foo: String })
foo: { type: String, required: false },
bar: { type: Number, required: false },
baz: { type: Boolean, required: true }
}, defaults)`.trim()
}, defaults)`.trim(),
)
})
@ -487,7 +487,7 @@ const props = defineProps({ foo: String })
}>(), { ...defaults })
</script>
`,
{ isProd: true }
{ isProd: true },
)
assertCode(content)
expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
@ -498,7 +498,7 @@ const props = defineProps({ foo: String })
bar: { type: Boolean },
baz: { type: [Boolean, Function] },
qux: {}
}, { ...defaults })`.trim()
}, { ...defaults })`.trim(),
)
})
@ -520,7 +520,7 @@ const props = defineProps({ foo: String })
foo: { type: Function, required: false }
}, {
['fo' + 'o']() { return 'foo' }
})`.trim()
})`.trim(),
)
})
@ -533,8 +533,8 @@ const props = defineProps({ foo: String })
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
{ hoistStatic: true },
).content,
).toMatch(`foo: { type: Number`)
expect(
@ -545,8 +545,8 @@ const props = defineProps({ foo: String })
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
{ hoistStatic: true },
).content,
).toMatch(`foo: { type: String`)
expect(
@ -557,8 +557,8 @@ const props = defineProps({ foo: String })
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
{ hoistStatic: true },
).content,
).toMatch(`foo: { type: [String, Number]`)
expect(
@ -569,8 +569,8 @@ const props = defineProps({ foo: String })
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
{ hoistStatic: true },
).content,
).toMatch(`foo: { type: Number`)
})
@ -585,7 +585,7 @@ const props = defineProps({ foo: String })
`)
expect(bindings).toStrictEqual({
bar: BindingTypes.SETUP_REF,
computed: BindingTypes.SETUP_CONST
computed: BindingTypes.SETUP_CONST,
})
})
@ -596,7 +596,7 @@ const props = defineProps({ foo: String })
const { foo } = defineProps<{
foo: Foo
}>()
</script>`
</script>`,
)
expect(content).toMatch(`const { foo } = __props`)
assertCode(content)
@ -649,7 +649,7 @@ const props = defineProps({ foo: String })
assertCode(content)
expect(content).toMatch(`"spa ce": { type: null, required: true }`)
expect(content).toMatch(
`"exclamation!mark": { type: null, required: true }`
`"exclamation!mark": { type: null, required: true }`,
)
expect(content).toMatch(`"double\\"quote": { type: null, required: true }`)
expect(content).toMatch(`"hash#tag": { type: null, required: true }`)
@ -670,7 +670,7 @@ const props = defineProps({ foo: String })
expect(content).toMatch(`"question?mark": { type: null, required: true }`)
expect(content).toMatch(`"at@sign": { type: null, required: true }`)
expect(content).toMatch(
`"square[brack]ets": { type: null, required: true }`
`"square[brack]ets": { type: null, required: true }`,
)
expect(content).toMatch(`"back\\\\slash": { type: null, required: true }`)
expect(content).toMatch(`"ca^ret": { type: null, required: true }`)
@ -707,7 +707,7 @@ const props = defineProps({ foo: String })
'curly{bra}ces': BindingTypes.PROPS,
'pi|pe': BindingTypes.PROPS,
'til~de': BindingTypes.PROPS,
'da-sh': BindingTypes.PROPS
'da-sh': BindingTypes.PROPS,
})
})
@ -718,7 +718,7 @@ const props = defineProps({ foo: String })
const props = defineProps<{ foo: number}>()
</script>`,
{ isProd: true, customElement: filename => /\.ce\.vue$/.test(filename) },
{ filename: 'app.ce.vue' }
{ filename: 'app.ce.vue' },
)
expect(content).toMatch(`foo: {type: Number}`)
@ -736,7 +736,7 @@ const props = defineProps({ foo: String })
});
</script>`,
{ isProd: true, customElement: filename => /\.ce\.vue$/.test(filename) },
{ filename: 'app.ce.vue' }
{ filename: 'app.ce.vue' },
)
expect(content).toMatch(`foo: { default: 5.5, type: Number }`)
assertCode(content)

View File

@ -1,13 +1,13 @@
import { BindingTypes } from '@vue/compiler-core'
import { SFCScriptCompileOptions } from '../../src'
import { compileSFCScript, assertCode } from '../utils'
import type { SFCScriptCompileOptions } from '../../src'
import { assertCode, compileSFCScript } from '../utils'
describe('sfc reactive props destructure', () => {
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) {
return compileSFCScript(src, {
inlineTemplate: true,
propsDestructure: true,
...options
...options,
})
}
@ -24,7 +24,7 @@ describe('sfc reactive props destructure', () => {
expect(content).toMatch(`_toDisplayString(__props.foo)`)
assertCode(content)
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS
foo: BindingTypes.PROPS,
})
})
@ -44,7 +44,7 @@ describe('sfc reactive props destructure', () => {
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
bar: BindingTypes.LITERAL_CONST,
hello: BindingTypes.LITERAL_CONST
hello: BindingTypes.LITERAL_CONST,
})
})
@ -65,7 +65,7 @@ describe('sfc reactive props destructure', () => {
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS,
test: BindingTypes.SETUP_CONST
test: BindingTypes.SETUP_CONST,
})
})
@ -115,11 +115,11 @@ describe('sfc reactive props destructure', () => {
`)
expect(bindings).toStrictEqual({
__propsAliases: {
fooBar: 'foo:bar'
fooBar: 'foo:bar',
},
foo: BindingTypes.PROPS,
'foo:bar': BindingTypes.PROPS,
fooBar: BindingTypes.PROPS_ALIASED
fooBar: BindingTypes.PROPS_ALIASED,
})
expect(content).toMatch(`
@ -159,13 +159,13 @@ describe('sfc reactive props destructure', () => {
`)
expect(bindings).toStrictEqual({
__propsAliases: {
fooBar: 'foo:bar'
fooBar: 'foo:bar',
},
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS,
'foo:bar': BindingTypes.PROPS,
fooBar: BindingTypes.PROPS_ALIASED,
'onUpdate:modelValue': BindingTypes.PROPS
'onUpdate:modelValue': BindingTypes.PROPS,
})
expect(content).toMatch(`
props: {
@ -184,7 +184,7 @@ describe('sfc reactive props destructure', () => {
const { foo = 1, bar = {}, func = () => {} } = defineProps<{ foo?: number, bar?: object, baz?: any, boola?: boolean, boolb?: boolean | number, func?: Function }>()
</script>
`,
{ isProd: true }
{ isProd: true },
)
assertCode(content)
// literals can be used as-is, non-literals are always returned from a
@ -220,8 +220,8 @@ describe('sfc reactive props destructure', () => {
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS_ALIASED,
__propsAliases: {
bar: 'foo'
}
bar: 'foo',
},
})
})
@ -242,8 +242,8 @@ describe('sfc reactive props destructure', () => {
'foo.bar': BindingTypes.PROPS,
fooBar: BindingTypes.PROPS_ALIASED,
__propsAliases: {
fooBar: 'foo.bar'
}
fooBar: 'foo.bar',
},
})
})
@ -254,14 +254,14 @@ describe('sfc reactive props destructure', () => {
</script>
`)
expect(content).toMatch(
`const rest = _createPropsRestProxy(__props, ["foo","bar"])`
`const rest = _createPropsRestProxy(__props, ["foo","bar"])`,
)
assertCode(content)
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
bar: BindingTypes.PROPS,
baz: BindingTypes.PROPS,
rest: BindingTypes.SETUP_REACTIVE_CONST
rest: BindingTypes.SETUP_REACTIVE_CONST,
})
})
@ -279,7 +279,7 @@ describe('sfc reactive props destructure', () => {
expect(content).toMatch(`_toDisplayString(__props.foo)`)
assertCode(content)
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS
foo: BindingTypes.PROPS,
})
})
@ -339,22 +339,22 @@ describe('sfc reactive props destructure', () => {
test('should error on deep destructure', () => {
expect(() =>
compile(
`<script setup>const { foo: [bar] } = defineProps(['foo'])</script>`
)
`<script setup>const { foo: [bar] } = defineProps(['foo'])</script>`,
),
).toThrow(`destructure does not support nested patterns`)
expect(() =>
compile(
`<script setup>const { foo: { bar } } = defineProps(['foo'])</script>`
)
`<script setup>const { foo: { bar } } = defineProps(['foo'])</script>`,
),
).toThrow(`destructure does not support nested patterns`)
})
test('should error on computed key', () => {
expect(() =>
compile(
`<script setup>const { [foo]: bar } = defineProps(['foo'])</script>`
)
`<script setup>const { [foo]: bar } = defineProps(['foo'])</script>`,
),
).toThrow(`destructure cannot use computed key`)
})
@ -363,8 +363,8 @@ describe('sfc reactive props destructure', () => {
compile(
`<script setup lang="ts">
const { foo } = withDefaults(defineProps<{ foo: string }>(), { foo: 'foo' })
</script>`
)
</script>`,
),
).toThrow(`withDefaults() is unnecessary when using destructure`)
})
@ -376,8 +376,8 @@ describe('sfc reactive props destructure', () => {
const {
foo = () => x
} = defineProps(['foo'])
</script>`
)
</script>`,
),
).toThrow(`cannot reference locally declared variables`)
})
@ -387,8 +387,8 @@ describe('sfc reactive props destructure', () => {
`<script setup>
const { foo } = defineProps(['foo'])
foo = 'bar'
</script>`
)
</script>`,
),
).toThrow(`Cannot assign to destructured props`)
expect(() =>
@ -396,8 +396,8 @@ describe('sfc reactive props destructure', () => {
`<script setup>
let { foo } = defineProps(['foo'])
foo = 'bar'
</script>`
)
</script>`,
),
).toThrow(`Cannot assign to destructured props`)
})
@ -408,10 +408,10 @@ describe('sfc reactive props destructure', () => {
import { watch } from 'vue'
const { foo } = defineProps(['foo'])
watch(foo, () => {})
</script>`
)
</script>`,
),
).toThrow(
`"foo" is a destructured prop and should not be passed directly to watch().`
`"foo" is a destructured prop and should not be passed directly to watch().`,
)
expect(() =>
@ -420,10 +420,10 @@ describe('sfc reactive props destructure', () => {
import { watch as w } from 'vue'
const { foo } = defineProps(['foo'])
w(foo, () => {})
</script>`
)
</script>`,
),
).toThrow(
`"foo" is a destructured prop and should not be passed directly to watch().`
`"foo" is a destructured prop and should not be passed directly to watch().`,
)
expect(() =>
@ -432,10 +432,10 @@ describe('sfc reactive props destructure', () => {
import { toRef } from 'vue'
const { foo } = defineProps(['foo'])
toRef(foo)
</script>`
)
</script>`,
),
).toThrow(
`"foo" is a destructured prop and should not be passed directly to toRef().`
`"foo" is a destructured prop and should not be passed directly to toRef().`,
)
expect(() =>
@ -444,10 +444,10 @@ describe('sfc reactive props destructure', () => {
import { toRef as r } from 'vue'
const { foo } = defineProps(['foo'])
r(foo)
</script>`
)
</script>`,
),
).toThrow(
`"foo" is a destructured prop and should not be passed directly to toRef().`
`"foo" is a destructured prop and should not be passed directly to toRef().`,
)
})
@ -457,8 +457,8 @@ describe('sfc reactive props destructure', () => {
compile(
`<script setup lang="ts">
const { foo = 'hello' } = defineProps<{ foo?: number }>()
</script>`
)
</script>`,
),
).toThrow(`Default value of prop "foo" does not match declared type.`)
})
@ -472,8 +472,8 @@ describe('sfc reactive props destructure', () => {
const { error: e, info } = useRequest();
watch(e, () => {});
watch(info, () => {});
</script>`
)
</script>`,
),
).not.toThrowError()
})
})

View File

@ -1,4 +1,4 @@
import { compileSFCScript as compile, assertCode } from '../utils'
import { assertCode, compileSFCScript as compile } from '../utils'
describe('defineSlots()', () => {
test('basic usage', () => {

View File

@ -1,13 +1,13 @@
import { BindingTypes } from '@vue/compiler-core'
import { SFCScriptCompileOptions } from '../../src'
import { compileSFCScript, assertCode } from '../utils'
import type { SFCScriptCompileOptions } from '../../src'
import { assertCode, compileSFCScript } from '../utils'
describe('sfc hoist static', () => {
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) {
return compileSFCScript(src, {
inlineTemplate: true,
hoistStatic: true,
...options
...options,
})
}
@ -34,7 +34,7 @@ describe('sfc hoist static', () => {
boolean: BindingTypes.LITERAL_CONST,
nil: BindingTypes.LITERAL_CONST,
bigint: BindingTypes.LITERAL_CONST,
template: BindingTypes.LITERAL_CONST
template: BindingTypes.LITERAL_CONST,
})
assertCode(content)
})
@ -57,7 +57,7 @@ describe('sfc hoist static', () => {
binary: BindingTypes.LITERAL_CONST,
conditional: BindingTypes.LITERAL_CONST,
unary: BindingTypes.LITERAL_CONST,
sequence: BindingTypes.LITERAL_CONST
sequence: BindingTypes.LITERAL_CONST,
})
assertCode(content)
})
@ -79,7 +79,7 @@ describe('sfc hoist static', () => {
expect(content.startsWith(hoistCode)).toBe(true)
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
defaultValue: BindingTypes.LITERAL_CONST
defaultValue: BindingTypes.LITERAL_CONST,
})
assertCode(content)
})
@ -100,7 +100,7 @@ describe('sfc hoist static', () => {
KEY1: BindingTypes.SETUP_LET,
KEY2: BindingTypes.SETUP_LET,
regex: BindingTypes.SETUP_CONST,
undef: BindingTypes.SETUP_MAYBE_REF
undef: BindingTypes.SETUP_MAYBE_REF,
})
expect(content).toMatch(`setup(__props) {\n\n ${code}`)
assertCode(content)
@ -131,7 +131,7 @@ describe('sfc hoist static', () => {
KEY4: BindingTypes.SETUP_CONST,
KEY5: BindingTypes.SETUP_CONST,
KEY6: BindingTypes.SETUP_CONST,
i: BindingTypes.SETUP_LET
i: BindingTypes.SETUP_LET,
})
expect(content).toMatch(`setup(__props) {\n\n ${code}`)
assertCode(content)
@ -149,7 +149,7 @@ describe('sfc hoist static', () => {
`)
expect(bindings).toStrictEqual({
arr: BindingTypes.SETUP_CONST,
obj: BindingTypes.SETUP_CONST
obj: BindingTypes.SETUP_CONST,
})
expect(content).toMatch(`setup(__props) {\n\n ${code}`)
assertCode(content)
@ -169,7 +169,7 @@ describe('sfc hoist static', () => {
expect(bindings).toStrictEqual({
Foo: BindingTypes.SETUP_CONST,
fn: BindingTypes.SETUP_CONST,
fn2: BindingTypes.SETUP_CONST
fn2: BindingTypes.SETUP_CONST,
})
expect(content).toMatch(`setup(__props) {\n\n ${code}`)
assertCode(content)
@ -185,7 +185,7 @@ describe('sfc hoist static', () => {
</script>
`)
expect(bindings).toStrictEqual({
foo: BindingTypes.SETUP_CONST
foo: BindingTypes.SETUP_CONST,
})
assertCode(content)
})
@ -197,10 +197,10 @@ describe('sfc hoist static', () => {
const foo = 'bar'
</script>
`,
{ hoistStatic: false }
{ hoistStatic: false },
)
expect(bindings).toStrictEqual({
foo: BindingTypes.SETUP_CONST
foo: BindingTypes.SETUP_CONST,
})
assertCode(content)
})
@ -212,7 +212,7 @@ describe('sfc hoist static', () => {
const foo = 'bar'
</script>
<template>{{ foo }}</template>
`
`,
)
expect(content).toMatch('_toDisplayString(foo)')
})

View File

@ -1,13 +1,13 @@
import { normalize } from 'node:path'
import { Identifier } from '@babel/types'
import { SFCScriptCompileOptions, parse } from '../../src'
import type { Identifier } from '@babel/types'
import { type SFCScriptCompileOptions, parse } from '../../src'
import { ScriptCompileContext } from '../../src/script/context'
import {
inferRuntimeType,
invalidateTypeCache,
recordImports,
registerTS,
resolveTypeElements,
registerTS
} from '../../src/script/resolveType'
import ts from 'typescript'
@ -25,7 +25,7 @@ describe('resolveType', () => {
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['Function'],
baz: ['String']
baz: ['String'],
})
expect(calls?.length).toBe(2)
})
@ -35,9 +35,9 @@ describe('resolveType', () => {
resolve(`
type Aliased = { foo: number }
defineProps<Aliased>()
`).props
`).props,
).toStrictEqual({
foo: ['Number']
foo: ['Number'],
})
})
@ -46,9 +46,9 @@ describe('resolveType', () => {
resolve(`
export type Aliased = { foo: number }
defineProps<Aliased>()
`).props
`).props,
).toStrictEqual({
foo: ['Number']
foo: ['Number'],
})
})
@ -57,9 +57,9 @@ describe('resolveType', () => {
resolve(`
interface Aliased { foo: number }
defineProps<Aliased>()
`).props
`).props,
).toStrictEqual({
foo: ['Number']
foo: ['Number'],
})
})
@ -68,9 +68,9 @@ describe('resolveType', () => {
resolve(`
export interface Aliased { foo: number }
defineProps<Aliased>()
`).props
`).props,
).toStrictEqual({
foo: ['Number']
foo: ['Number'],
})
})
@ -82,12 +82,12 @@ describe('resolveType', () => {
interface C { c: string }
interface Aliased extends B, C { foo: number }
defineProps<Aliased>()
`).props
`).props,
).toStrictEqual({
a: ['Function'],
b: ['Boolean'],
c: ['String'],
foo: ['Number']
foo: ['Number'],
})
})
@ -96,9 +96,9 @@ describe('resolveType', () => {
resolve(`
class Foo {}
defineProps<{ foo: Foo }>()
`).props
`).props,
).toStrictEqual({
foo: ['Object']
foo: ['Object'],
})
})
@ -106,7 +106,7 @@ describe('resolveType', () => {
expect(
resolve(`
defineProps<(e: 'foo') => void>()
`).calls?.length
`).calls?.length,
).toBe(1)
})
@ -115,7 +115,7 @@ describe('resolveType', () => {
resolve(`
type Fn = (e: 'foo') => void
defineProps<Fn>()
`).calls?.length
`).calls?.length,
).toBe(1)
})
@ -126,13 +126,13 @@ describe('resolveType', () => {
type Bar = { bar: string }
type Baz = { bar: string | boolean }
defineProps<{ self: any } & Foo & Bar & Baz>()
`).props
`).props,
).toStrictEqual({
self: ['Unknown'],
foo: ['Number'],
// both Bar & Baz has 'bar', but Baz['bar] is wider so it should be
// preferred
bar: ['String', 'Boolean']
bar: ['String', 'Boolean'],
})
})
@ -156,12 +156,12 @@ describe('resolveType', () => {
}
defineProps<CommonProps & ConditionalProps>()
`).props
`).props,
).toStrictEqual({
size: ['String'],
color: ['String', 'Number'],
appearance: ['String'],
note: ['String']
note: ['String'],
})
})
@ -173,12 +173,12 @@ describe('resolveType', () => {
defineProps<{
[\`_\${T}_\${S}_\`]: string
}>()
`).props
`).props,
).toStrictEqual({
_foo_x_: ['String'],
_foo_y_: ['String'],
_bar_x_: ['String'],
_bar_y_: ['String']
_bar_y_: ['String'],
})
})
@ -195,7 +195,7 @@ describe('resolveType', () => {
} & {
[K in \`x\${T}\`]: string
}>()
`).props
`).props,
).toStrictEqual({
foo: ['String', 'Number'],
bar: ['String', 'Number'],
@ -204,7 +204,7 @@ describe('resolveType', () => {
FOO: ['String'],
xfoo: ['String'],
xbar: ['String'],
optional: ['Boolean']
optional: ['Boolean'],
})
})
@ -213,14 +213,14 @@ describe('resolveType', () => {
resolve(`
type T = { foo: number, bar: string }
defineProps<Partial<T>>()
`).raw.props
`).raw.props,
).toMatchObject({
foo: {
optional: true
optional: true,
},
bar: {
optional: true
}
optional: true,
},
})
})
@ -229,14 +229,14 @@ describe('resolveType', () => {
resolve(`
type T = { foo?: number, bar?: string }
defineProps<Required<T>>()
`).raw.props
`).raw.props,
).toMatchObject({
foo: {
optional: false
optional: false,
},
bar: {
optional: false
}
optional: false,
},
})
})
@ -246,10 +246,10 @@ describe('resolveType', () => {
type T = { foo: number, bar: string, baz: boolean }
type K = 'foo' | 'bar'
defineProps<Pick<T, K>>()
`).props
`).props,
).toStrictEqual({
foo: ['Number'],
bar: ['String']
bar: ['String'],
})
})
@ -259,9 +259,9 @@ describe('resolveType', () => {
type T = { foo: number, bar: string, baz: boolean }
type K = 'foo' | 'bar'
defineProps<Omit<T, K>>()
`).props
`).props,
).toStrictEqual({
baz: ['Boolean']
baz: ['Boolean'],
})
})
@ -271,9 +271,9 @@ describe('resolveType', () => {
type T = { bar: number }
type S = { nested: { foo: T['bar'] }}
defineProps<S['nested']>()
`).props
`).props,
).toStrictEqual({
foo: ['Number']
foo: ['Number'],
})
})
@ -284,10 +284,10 @@ describe('resolveType', () => {
type T = { foo: string, bar: number }
type S = { foo: { foo: T[string] }, bar: { bar: string } }
defineProps<S[K]>()
`).props
`).props,
).toStrictEqual({
foo: ['String', 'Number'],
bar: ['String']
bar: ['String'],
})
})
@ -299,12 +299,12 @@ describe('resolveType', () => {
type T = [1, 'foo']
type TT = [foo: 1, bar: 'foo']
defineProps<{ foo: A[number], bar: AA[number], tuple: T[number], namedTuple: TT[number] }>()
`).props
`).props,
).toStrictEqual({
foo: ['String', 'Number'],
bar: ['String'],
tuple: ['Number', 'String'],
namedTuple: ['Number', 'String']
namedTuple: ['Number', 'String'],
})
})
@ -321,9 +321,9 @@ describe('resolveType', () => {
}
}
defineProps<Foo.Bar.A>()
`).props
`).props,
).toStrictEqual({
foo: ['Number']
foo: ['Number'],
})
})
@ -340,10 +340,10 @@ describe('resolveType', () => {
foo: Foo['a'],
bar: Foo['b']
}>()
`).props
`).props,
).toStrictEqual({
foo: ['String'],
bar: ['Number']
bar: ['Number'],
})
})
@ -360,10 +360,10 @@ describe('resolveType', () => {
foo: Foo.A,
bar: Foo.B
}>()
`).props
`).props,
).toStrictEqual({
foo: ['String'],
bar: ['Number']
bar: ['Number'],
})
})
@ -380,10 +380,10 @@ describe('resolveType', () => {
foo: Foo.A,
bar: Foo['b']
}>()
`).props
`).props,
).toStrictEqual({
foo: ['String'],
bar: ['Number']
bar: ['Number'],
})
})
@ -399,9 +399,9 @@ describe('resolveType', () => {
defineProps<{
foo: Foo
}>()
`).props
`).props,
).toStrictEqual({
foo: ['Number', 'String']
foo: ['Number', 'String'],
})
})
@ -410,9 +410,9 @@ describe('resolveType', () => {
resolve(`
declare const a: string
defineProps<{ foo: typeof a }>()
`).props
`).props,
).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
@ -429,11 +429,11 @@ describe('resolveType', () => {
}
type Props = ExtractPropTypes<typeof props>
defineProps<Props>()
`
`,
)
expect(props).toStrictEqual({
foo: ['String'],
bar: ['Boolean']
bar: ['Boolean'],
})
expect(raw.props.bar.optional).toBe(false)
})
@ -447,11 +447,11 @@ describe('resolveType', () => {
}
type Props = Partial<import('vue').ExtractPropTypes<ReturnType<typeof props>>>
defineProps<Props>()
`
`,
)
expect(props).toStrictEqual({
foo: ['String'],
bar: ['Boolean']
bar: ['Boolean'],
})
})
@ -461,9 +461,9 @@ describe('resolveType', () => {
resolve(`
type Props<T> = T
defineProps<Props<{ foo: string }>>()
`).props
`).props,
).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
@ -474,11 +474,11 @@ describe('resolveType', () => {
type Bar = { bar: number; }
type Props<T,U> = T & U & { baz: boolean }
defineProps<Props<Foo, Bar>>()
`).props
`).props,
).toStrictEqual({
foo: ['String'],
bar: ['Number'],
baz: ['Boolean']
baz: ['Boolean'],
})
})
@ -489,9 +489,9 @@ describe('resolveType', () => {
type Props<T> = Aliased<T>
type Foo = { foo: string; }
defineProps<Props<Foo>>()
`).props
`).props,
).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
@ -500,9 +500,9 @@ describe('resolveType', () => {
resolve(`
type Aliased<T> = { foo: T }
defineProps<Aliased<string>>()
`).props
`).props,
).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
@ -514,25 +514,25 @@ describe('resolveType', () => {
}
type Foo = string
defineProps<Props<Foo>>()
`).props
`).props,
).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
test('generic from external-file', () => {
const files = {
'/foo.ts': 'export type P<T> = { foo: T }'
'/foo.ts': 'export type P<T> = { foo: T }',
}
const { props } = resolve(
`
import { P } from './foo'
defineProps<P<string>>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
})
@ -544,7 +544,7 @@ describe('resolveType', () => {
'/bar.d.ts':
'type X = { bar: string }; export { X as Y };' +
// verify that we can parse syntax that is only valid in d.ts
'export const baz: boolean'
'export const baz: boolean',
}
const { props, deps } = resolve(
`
@ -552,11 +552,11 @@ describe('resolveType', () => {
import { Y as PP } from './bar'
defineProps<P & PP>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -568,7 +568,7 @@ describe('resolveType', () => {
'type X = { bar: string }; export { X as Y };' +
// verify that we can parse syntax that is only valid in d.ts
'export const baz: boolean',
'C:\\Test\\FolderB\\buz.ts': 'export type Z = { buz: string }'
'C:\\Test\\FolderB\\buz.ts': 'export type Z = { buz: string }',
}
const { props, deps } = resolve(
`
@ -579,32 +579,32 @@ describe('resolveType', () => {
`,
files,
{},
'C:\\Test\\FolderA\\Test.vue'
'C:\\Test\\FolderA\\Test.vue',
)
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['String'],
buz: ['String']
buz: ['String'],
})
expect(deps && [...deps].map(normalize)).toStrictEqual(
Object.keys(files).map(normalize)
Object.keys(files).map(normalize),
)
})
// #8244
test('utility type in external file', () => {
const files = {
'/foo.ts': 'type A = { n?: number }; export type B = Required<A>'
'/foo.ts': 'type A = { n?: number }; export type B = Required<A>',
}
const { props } = resolve(
`
import { B } from './foo'
defineProps<B>()
`,
files
files,
)
expect(props).toStrictEqual({
n: ['Number']
n: ['Number'],
})
})
@ -613,7 +613,7 @@ describe('resolveType', () => {
'/foo.vue':
'<script lang="ts">export type P = { foo: number }</script>',
'/bar.vue':
'<script setup lang="tsx">export type P = { bar: string }</script>'
'<script setup lang="tsx">export type P = { bar: string }</script>',
}
const { props, deps } = resolve(
`
@ -621,11 +621,11 @@ describe('resolveType', () => {
import { P as PP } from './bar.vue'
defineProps<P & PP>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -635,18 +635,18 @@ describe('resolveType', () => {
'/foo.ts': `import type { P as PP } from './nested/bar.vue'
export type P = { foo: number } & PP`,
'/nested/bar.vue':
'<script setup lang="ts">export type P = { bar: string }</script>'
'<script setup lang="ts">export type P = { bar: string }</script>',
}
const { props, deps } = resolve(
`
import { P } from './foo'
defineProps<P>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -654,17 +654,17 @@ describe('resolveType', () => {
test('relative (chained, re-export)', () => {
const files = {
'/foo.ts': `export { P as PP } from './bar'`,
'/bar.ts': 'export type P = { bar: string }'
'/bar.ts': 'export type P = { bar: string }',
}
const { props, deps } = resolve(
`
import { PP as P } from './foo'
defineProps<P>()
`,
files
files,
)
expect(props).toStrictEqual({
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -672,17 +672,17 @@ describe('resolveType', () => {
test('relative (chained, export *)', () => {
const files = {
'/foo.ts': `export * from './bar'`,
'/bar.ts': 'export type P = { bar: string }'
'/bar.ts': 'export type P = { bar: string }',
}
const { props, deps } = resolve(
`
import { P } from './foo'
defineProps<P>()
`,
files
files,
)
expect(props).toStrictEqual({
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -690,7 +690,7 @@ describe('resolveType', () => {
test('relative (default export)', () => {
const files = {
'/foo.ts': `export default interface P { foo: string }`,
'/bar.ts': `type X = { bar: string }; export default X`
'/bar.ts': `type X = { bar: string }; export default X`,
}
const { props, deps } = resolve(
`
@ -698,11 +698,11 @@ describe('resolveType', () => {
import X from './bar'
defineProps<P & X>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['String'],
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -711,7 +711,7 @@ describe('resolveType', () => {
const files = {
'/bar.ts': `export { default } from './foo'`,
'/foo.ts': `export default interface P { foo: string }; export interface PP { bar: number }`,
'/baz.ts': `export { PP as default } from './foo'`
'/baz.ts': `export { PP as default } from './foo'`,
}
const { props, deps } = resolve(
`
@ -719,11 +719,11 @@ describe('resolveType', () => {
import PP from './baz'
defineProps<P & PP>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['String'],
bar: ['Number']
bar: ['Number'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -732,17 +732,17 @@ describe('resolveType', () => {
const files = {
'/foo.ts': `export default interface P { foo: string }`,
'/bar.ts': `export default interface PP { bar: number }`,
'/baz.ts': `export { default as X } from './foo'; export { default as XX } from './bar'; `
'/baz.ts': `export { default as X } from './foo'; export { default as XX } from './bar'; `,
}
const { props, deps } = resolve(
`import { X, XX } from './baz'
defineProps<X & XX>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['String'],
bar: ['Number']
bar: ['Number'],
})
expect(deps && [...deps]).toStrictEqual(['/baz.ts', '/foo.ts', '/bar.ts'])
})
@ -750,17 +750,17 @@ describe('resolveType', () => {
test('relative (dynamic import)', () => {
const files = {
'/foo.ts': `export type P = { foo: string, bar: import('./bar').N }`,
'/bar.ts': 'export type N = number'
'/bar.ts': 'export type N = number',
}
const { props, deps } = resolve(
`
defineProps<import('./foo').P>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['String'],
bar: ['Number']
bar: ['Number'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -770,17 +770,17 @@ describe('resolveType', () => {
const files = {
'/foo.d.ts':
'import { PP } from "./bar.js"; export type P = { foo: PP }',
'/bar.d.ts': 'export type PP = "foo" | "bar"'
'/bar.d.ts': 'export type PP = "foo" | "bar"',
}
const { props, deps } = resolve(
`
import { P } from './foo'
defineProps<P>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['String']
foo: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -788,17 +788,17 @@ describe('resolveType', () => {
test('ts module resolve', () => {
const files = {
'/node_modules/foo/package.json': JSON.stringify({
types: 'index.d.ts'
types: 'index.d.ts',
}),
'/node_modules/foo/index.d.ts': 'export type P = { foo: number }',
'/tsconfig.json': JSON.stringify({
compilerOptions: {
paths: {
bar: ['./pp.ts']
}
}
bar: ['./pp.ts'],
},
},
}),
'/pp.ts': 'export type PP = { bar: string }'
'/pp.ts': 'export type PP = { bar: string }',
}
const { props, deps } = resolve(
@ -807,16 +807,16 @@ describe('resolveType', () => {
import { PP } from 'bar'
defineProps<P & PP>()
`,
files
files,
)
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual([
'/node_modules/foo/index.d.ts',
'/pp.ts'
'/pp.ts',
])
})
@ -825,23 +825,23 @@ describe('resolveType', () => {
'/tsconfig.json': JSON.stringify({
references: [
{
path: './tsconfig.app.json'
}
]
path: './tsconfig.app.json',
},
],
}),
'/tsconfig.app.json': JSON.stringify({
include: ['**/*.ts', '**/*.vue'],
extends: './tsconfig.web.json'
extends: './tsconfig.web.json',
}),
'/tsconfig.web.json': JSON.stringify({
compilerOptions: {
composite: true,
paths: {
bar: ['./user.ts']
}
}
bar: ['./user.ts'],
},
},
}),
'/user.ts': 'export type User = { bar: string }'
'/user.ts': 'export type User = { bar: string }',
}
const { props, deps } = resolve(
@ -849,11 +849,11 @@ describe('resolveType', () => {
import { User } from 'bar'
defineProps<User>()
`,
files
files,
)
expect(props).toStrictEqual({
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(['/user.ts'])
})
@ -864,12 +864,12 @@ describe('resolveType', () => {
compilerOptions: {
include: ['**/*.ts', '**/*.vue'],
paths: {
'@/*': ['./src/*']
}
}
'@/*': ['./src/*'],
},
},
}),
'/src/Foo.vue':
'<script lang="ts">export type P = { bar: string }</script>'
'<script lang="ts">export type P = { bar: string }</script>',
}
const { props, deps } = resolve(
@ -877,11 +877,11 @@ describe('resolveType', () => {
import { P } from '@/Foo.vue'
defineProps<P>()
`,
files
files,
)
expect(props).toStrictEqual({
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(['/src/Foo.vue'])
})
@ -898,16 +898,16 @@ describe('resolveType', () => {
type PP = { bar: string }
}
export {}
`
`,
}
const { props, deps } = resolve(`defineProps<App.User & PP>()`, files, {
globalTypeFiles: Object.keys(files)
globalTypeFiles: Object.keys(files),
})
expect(props).toStrictEqual({
name: ['String'],
bar: ['String']
bar: ['String'],
})
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
@ -927,33 +927,33 @@ describe('resolveType', () => {
id: string
}
}
`
`,
}
const { props } = resolve(`defineProps<App.Data.AircraftData>()`, files, {
globalTypeFiles: Object.keys(files)
globalTypeFiles: Object.keys(files),
})
expect(props).toStrictEqual({
id: ['String'],
manufacturer: ['Object']
manufacturer: ['Object'],
})
})
// #9871
test('shared generics with different args', () => {
const files = {
'/foo.ts': `export interface Foo<T> { value: T }`
'/foo.ts': `export interface Foo<T> { value: T }`,
}
const { props } = resolve(
`import type { Foo } from './foo'
defineProps<Foo<string>>()`,
files,
undefined,
`/One.vue`
`/One.vue`,
)
expect(props).toStrictEqual({
value: ['String']
value: ['String'],
})
const { props: props2 } = resolve(
`import type { Foo } from './foo'
@ -961,10 +961,10 @@ describe('resolveType', () => {
files,
undefined,
`/Two.vue`,
false /* do not invalidate cache */
false /* do not invalidate cache */,
)
expect(props2).toStrictEqual({
value: ['Number']
value: ['Number'],
})
})
})
@ -972,25 +972,25 @@ describe('resolveType', () => {
describe('errors', () => {
test('failed type reference', () => {
expect(() => resolve(`defineProps<X>()`)).toThrow(
`Unresolvable type reference`
`Unresolvable type reference`,
)
})
test('unsupported computed keys', () => {
expect(() => resolve(`defineProps<{ [Foo]: string }>()`)).toThrow(
`Unsupported computed key in type referenced by a macro`
`Unsupported computed key in type referenced by a macro`,
)
})
test('unsupported index type', () => {
expect(() => resolve(`defineProps<X[K]>()`)).toThrow(
`Unsupported type when resolving index type`
`Unsupported type when resolving index type`,
)
})
test('failed import source resolve', () => {
expect(() =>
resolve(`import { X } from './foo'; defineProps<X>()`)
resolve(`import { X } from './foo'; defineProps<X>()`),
).toThrow(`Failed to resolve import source "./foo"`)
})
@ -1001,7 +1001,7 @@ describe('resolveType', () => {
resolve(`
import type P from 'unknown'
defineProps<{ foo: P }>()
`)
`),
).not.toThrow()
})
@ -1011,7 +1011,7 @@ describe('resolveType', () => {
import type Base from 'unknown'
interface Props extends Base {}
defineProps<Props>()
`)
`),
).toThrow(`@vue-ignore`)
})
@ -1026,11 +1026,11 @@ describe('resolveType', () => {
foo: string
}
defineProps<Props>()
`))
`)),
).not.toThrow(`@vue-ignore`)
expect(res.props).toStrictEqual({
foo: ['String']
foo: ['String'],
})
})
})
@ -1041,10 +1041,10 @@ function resolve(
files: Record<string, string> = {},
options?: Partial<SFCScriptCompileOptions>,
sourceFileName: string = '/Test.vue',
invalidateCache = true
invalidateCache = true,
) {
const { descriptor } = parse(`<script setup lang="ts">\n${code}\n</script>`, {
filename: sourceFileName
filename: sourceFileName,
})
const ctx = new ScriptCompileContext(descriptor, {
id: 'test',
@ -1054,9 +1054,9 @@ function resolve(
},
readFile(file) {
return files[file] ?? files[normalize(file)]
}
},
},
...options
...options,
})
if (invalidateCache) {
@ -1088,6 +1088,6 @@ function resolve(
props,
calls: raw.calls,
deps: ctx.deps,
raw
raw,
}
}

View File

@ -1,20 +1,20 @@
import {
type SFCStyleCompileOptions,
compileStyle,
compileStyleAsync,
SFCStyleCompileOptions
} from '../src/compileStyle'
import path from 'path'
import path from 'node:path'
export function compileScoped(
source: string,
options?: Partial<SFCStyleCompileOptions>
options?: Partial<SFCStyleCompileOptions>,
): string {
const res = compileStyle({
source,
filename: 'test.css',
id: 'data-v-test',
scoped: true,
...options
...options,
})
if (res.errors.length) {
res.errors.forEach(err => {
@ -28,34 +28,34 @@ export function compileScoped(
describe('SFC scoped CSS', () => {
test('simple selectors', () => {
expect(compileScoped(`h1 { color: red; }`)).toMatch(
`h1[data-v-test] { color: red;`
`h1[data-v-test] { color: red;`,
)
expect(compileScoped(`.foo { color: red; }`)).toMatch(
`.foo[data-v-test] { color: red;`
`.foo[data-v-test] { color: red;`,
)
})
test('descendent selector', () => {
expect(compileScoped(`h1 .foo { color: red; }`)).toMatch(
`h1 .foo[data-v-test] { color: red;`
`h1 .foo[data-v-test] { color: red;`,
)
})
test('multiple selectors', () => {
expect(compileScoped(`h1 .foo, .bar, .baz { color: red; }`)).toMatch(
`h1 .foo[data-v-test], .bar[data-v-test], .baz[data-v-test] { color: red;`
`h1 .foo[data-v-test], .bar[data-v-test], .baz[data-v-test] { color: red;`,
)
})
test('pseudo class', () => {
expect(compileScoped(`.foo:after { color: red; }`)).toMatch(
`.foo[data-v-test]:after { color: red;`
`.foo[data-v-test]:after { color: red;`,
)
})
test('pseudo element', () => {
expect(compileScoped(`::selection { display: none; }`)).toMatch(
'[data-v-test]::selection {'
'[data-v-test]::selection {',
)
})
@ -217,30 +217,30 @@ describe('SFC scoped CSS', () => {
to { opacity: 1; }
}
`,
{ id: 'data-v-test' }
{ id: 'data-v-test' },
)
expect(style).toContain(
`.anim[data-v-test] {\n animation: color-test 5s infinite, other 5s;`
`.anim[data-v-test] {\n animation: color-test 5s infinite, other 5s;`,
)
expect(style).toContain(
`.anim-2[data-v-test] {\n animation-name: color-test`
`.anim-2[data-v-test] {\n animation-name: color-test`,
)
expect(style).toContain(
`.anim-3[data-v-test] {\n animation: 5s color-test infinite, 5s other;`
`.anim-3[data-v-test] {\n animation: 5s color-test infinite, 5s other;`,
)
expect(style).toContain(`@keyframes color-test {`)
expect(style).toContain(`@-webkit-keyframes color-test {`)
expect(style).toContain(
`.anim-multiple[data-v-test] {\n animation: color-test 5s infinite,opacity-test 2s;`
`.anim-multiple[data-v-test] {\n animation: color-test 5s infinite,opacity-test 2s;`,
)
expect(style).toContain(
`.anim-multiple-2[data-v-test] {\n animation-name: color-test,opacity-test;`
`.anim-multiple-2[data-v-test] {\n animation-name: color-test,opacity-test;`,
)
expect(style).toContain(`@keyframes opacity-test {\nfrom { opacity: 0;`)
expect(style).toContain(
`@-webkit-keyframes opacity-test {\nfrom { opacity: 0;`
`@-webkit-keyframes opacity-test {\nfrom { opacity: 0;`,
)
})
@ -265,7 +265,7 @@ describe('SFC scoped CSS', () => {
}"
`)
expect(
`::v-deep usage as a combinator has been deprecated.`
`::v-deep usage as a combinator has been deprecated.`,
).toHaveBeenWarned()
})
@ -276,7 +276,7 @@ describe('SFC scoped CSS', () => {
}"
`)
expect(
`the >>> and /deep/ combinators have been deprecated.`
`the >>> and /deep/ combinators have been deprecated.`,
).toHaveBeenWarned()
})
@ -287,7 +287,7 @@ describe('SFC scoped CSS', () => {
}"
`)
expect(
`the >>> and /deep/ combinators have been deprecated.`
`the >>> and /deep/ combinators have been deprecated.`,
).toHaveBeenWarned()
})
})
@ -299,7 +299,7 @@ describe('SFC CSS modules', () => {
source: `.red { color: red }\n.green { color: green }\n:global(.blue) { color: blue }`,
filename: `test.css`,
id: 'test',
modules: true
modules: true,
})
expect(result.modules).toBeDefined()
expect(result.modules!.red).toMatch('_red_')
@ -316,8 +316,8 @@ describe('SFC CSS modules', () => {
modulesOptions: {
scopeBehaviour: 'global',
generateScopedName: `[name]__[local]__[hash:base64:5]`,
localsConvention: 'camelCaseOnly'
}
localsConvention: 'camelCaseOnly',
},
})
expect(result.modules).toBeDefined()
expect(result.modules!.fooBar).toMatch('__foo-bar__')
@ -333,11 +333,11 @@ describe('SFC style preprocessors', () => {
`,
filename: path.resolve(__dirname, './fixture/test.scss'),
id: '',
preprocessLang: 'scss'
preprocessLang: 'scss',
})
expect([...res.dependencies]).toStrictEqual([
path.join(__dirname, './fixture/import.scss')
path.join(__dirname, './fixture/import.scss'),
])
})
@ -348,7 +348,7 @@ describe('SFC style preprocessors', () => {
@mixin square($size) {
width: $size;
height: $size;
}`
}`,
},
source: `
.square {
@ -357,7 +357,7 @@ describe('SFC style preprocessors', () => {
`,
filename: path.resolve(__dirname, './fixture/test.scss'),
id: '',
preprocessLang: 'scss'
preprocessLang: 'scss',
})
expect(res.errors.length).toBe(0)
@ -380,12 +380,12 @@ describe('SFC style preprocessors', () => {
width: $size;
height: $size;
}`
}
},
},
source,
filename,
id: '',
preprocessLang: 'scss'
preprocessLang: 'scss',
})
expect(res.errors.length).toBe(0)

View File

@ -1,15 +1,15 @@
import { RawSourceMap, SourceMapConsumer } from 'source-map-js'
import { type RawSourceMap, SourceMapConsumer } from 'source-map-js'
import {
type SFCTemplateCompileOptions,
compileTemplate,
SFCTemplateCompileOptions
} from '../src/compileTemplate'
import { parse, SFCTemplateBlock } from '../src/parse'
import { type SFCTemplateBlock, parse } from '../src/parse'
import { compileScript } from '../src'
function compile(opts: Omit<SFCTemplateCompileOptions, 'id'>) {
return compileTemplate({
...opts,
id: ''
id: '',
})
}
@ -50,13 +50,13 @@ body
p Cool Pug example!
</template>
`,
{ filename: 'example.vue', sourceMap: true }
{ filename: 'example.vue', sourceMap: true },
).descriptor.template as SFCTemplateBlock
const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
preprocessLang: template.lang,
})
expect(result.errors.length).toBe(0)
@ -74,31 +74,31 @@ test('preprocess pug with indents and blank lines', () => {
p This is the last line.
</template>
`,
{ filename: 'example.vue', sourceMap: true }
{ filename: 'example.vue', sourceMap: true },
).descriptor.template as SFCTemplateBlock
const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
preprocessLang: template.lang,
})
expect(result.errors.length).toBe(0)
expect(result.source).toBe(
'<body><h1>The next line contains four spaces.</h1><div class="container"><p>The next line is empty.</p></div><p>This is the last line.</p></body>'
'<body><h1>The next line contains four spaces.</h1><div class="container"><p>The next line is empty.</p></div><p>This is the last line.</p></body>',
)
})
test('warn missing preprocessor', () => {
const template = parse(`<template lang="unknownLang">hi</template>\n`, {
filename: 'example.vue',
sourceMap: true
sourceMap: true,
}).descriptor.template as SFCTemplateBlock
const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
preprocessLang: template.lang,
})
expect(result.errors.length).toBe(1)
@ -110,8 +110,8 @@ test('transform asset url options', () => {
const { code: code1 } = compile({
...input,
transformAssetUrls: {
tags: { foo: ['bar'] }
}
tags: { foo: ['bar'] },
},
})
expect(code1).toMatch(`import _imports_0 from 'baz'\n`)
@ -119,15 +119,15 @@ test('transform asset url options', () => {
const { code: code2 } = compile({
...input,
transformAssetUrls: {
foo: ['bar']
}
foo: ['bar'],
},
})
expect(code2).toMatch(`import _imports_0 from 'baz'\n`)
// false option
const { code: code3 } = compile({
...input,
transformAssetUrls: false
transformAssetUrls: false,
})
expect(code3).not.toMatch(`import _imports_0 from 'baz'\n`)
})
@ -139,12 +139,12 @@ test('source map', () => {
<div><p>{{ foobar }}</p></div>
</template>
`,
{ filename: 'example.vue', sourceMap: true }
{ filename: 'example.vue', sourceMap: true },
).descriptor.template!
const { code, map } = compile({
filename: 'example.vue',
source: template.content
source: template.content,
})
expect(map!.sources).toEqual([`example.vue`])
@ -152,7 +152,7 @@ test('source map', () => {
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(code, 'foobar'))
consumer.originalPositionFor(getPositionInCode(code, 'foobar')),
).toMatchObject(getPositionInCode(template.content, `foobar`))
})
@ -164,7 +164,7 @@ test('should work w/ AST from descriptor', () => {
`
const template = parse(source, {
filename: 'example.vue',
sourceMap: true
sourceMap: true,
}).descriptor.template!
expect(template.ast!.source).toBe(source)
@ -172,7 +172,7 @@ test('should work w/ AST from descriptor', () => {
const { code, map } = compile({
filename: 'example.vue',
source: template.content,
ast: template.ast
ast: template.ast,
})
expect(map!.sources).toEqual([`example.vue`])
@ -182,14 +182,14 @@ test('should work w/ AST from descriptor', () => {
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(code, 'foobar'))
consumer.originalPositionFor(getPositionInCode(code, 'foobar')),
).toMatchObject(getPositionInCode(source, `foobar`))
expect(code).toBe(
compile({
filename: 'example.vue',
source: template.content
}).code
source: template.content,
}).code,
)
})
@ -201,7 +201,7 @@ test('should work w/ AST from descriptor in SSR mode', () => {
`
const template = parse(source, {
filename: 'example.vue',
sourceMap: true
sourceMap: true,
}).descriptor.template!
expect(template.ast!.source).toBe(source)
@ -210,7 +210,7 @@ test('should work w/ AST from descriptor in SSR mode', () => {
filename: 'example.vue',
source: '', // make sure it's actually using the AST instead of source
ast: template.ast,
ssr: true
ssr: true,
})
expect(map!.sources).toEqual([`example.vue`])
@ -220,15 +220,15 @@ test('should work w/ AST from descriptor in SSR mode', () => {
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(code, 'foobar'))
consumer.originalPositionFor(getPositionInCode(code, 'foobar')),
).toMatchObject(getPositionInCode(source, `foobar`))
expect(code).toBe(
compile({
filename: 'example.vue',
source: template.content,
ssr: true
}).code
ssr: true,
}).code,
)
})
@ -240,7 +240,7 @@ test('should not reuse AST if using custom compiler', () => {
`
const template = parse(source, {
filename: 'example.vue',
sourceMap: true
sourceMap: true,
}).descriptor.template!
const { code } = compile({
@ -249,9 +249,9 @@ test('should not reuse AST if using custom compiler', () => {
ast: template.ast,
compiler: {
parse: () => null as any,
// @ts-ignore
compile: input => ({ code: input })
}
// @ts-expect-error
compile: input => ({ code: input }),
},
})
// what we really want to assert is that the `input` received by the custom
@ -267,7 +267,7 @@ test('should force re-parse on already transformed AST', () => {
`
const template = parse(source, {
filename: 'example.vue',
sourceMap: true
sourceMap: true,
}).descriptor.template!
// force set to empty, if this is reused then it won't generate proper code
@ -277,14 +277,14 @@ test('should force re-parse on already transformed AST', () => {
const { code } = compile({
filename: 'example.vue',
source: '',
ast: template.ast
ast: template.ast,
})
expect(code).toBe(
compile({
filename: 'example.vue',
source: template.content
}).code
source: template.content,
}).code,
)
})
@ -296,7 +296,7 @@ test('should force re-parse with correct compiler in SSR mode', () => {
`
const template = parse(source, {
filename: 'example.vue',
sourceMap: true
sourceMap: true,
}).descriptor.template!
// force set to empty, if this is reused then it won't generate proper code
@ -307,15 +307,15 @@ test('should force re-parse with correct compiler in SSR mode', () => {
filename: 'example.vue',
source: '',
ast: template.ast,
ssr: true
ssr: true,
})
expect(code).toBe(
compile({
filename: 'example.vue',
source: template.content,
ssr: true
}).code
ssr: true,
}).code,
)
})
@ -323,7 +323,7 @@ test('template errors', () => {
const result = compile({
filename: 'example.vue',
source: `<div
:bar="a[" v-model="baz"/>`
:bar="a[" v-model="baz"/>`,
})
expect(result.errors).toMatchSnapshot()
})
@ -335,20 +335,20 @@ test('preprocessor errors', () => {
div(class='class)
</template>
`,
{ filename: 'example.vue', sourceMap: true }
{ filename: 'example.vue', sourceMap: true },
).descriptor.template as SFCTemplateBlock
const result = compile({
filename: 'example.vue',
source: template.content,
preprocessLang: template.lang
preprocessLang: template.lang,
})
expect(result.errors.length).toBe(1)
const message = result.errors[0].toString()
expect(message).toMatch(`Error: example.vue:3:1`)
expect(message).toMatch(
`The end of the string reached with no closing bracket ) found.`
`The end of the string reached with no closing bracket ) found.`,
)
})
@ -362,7 +362,7 @@ test('should generate the correct imports expression', () => {
<img src="./bar.svg"/>
</Comp>
`,
ssr: true
ssr: true,
})
expect(code).toMatch(`_ssrRenderAttr(\"src\", _imports_1)`)
expect(code).toMatch(`_createVNode(\"img\", { src: _imports_1 })`)
@ -384,7 +384,7 @@ test('should not hoist srcset URLs in SSR mode', () => {
</picture>
</router-link>
`,
ssr: true
ssr: true,
})
expect(code).toMatchSnapshot()
})
@ -422,7 +422,7 @@ test('prefixing edge case for reused AST', () => {
id: 'xxx',
filename: 'test.vue',
ast: descriptor.template!.ast,
source: descriptor.template!.content
source: descriptor.template!.content,
})
expect(code).not.toMatch(`_ctx.t`)
})
@ -436,7 +436,7 @@ interface Pos {
function getPositionInCode(
code: string,
token: string,
expectName: string | boolean = false
expectName: string | boolean = false,
): Pos {
const generatedOffset = code.indexOf(token)
let line = 1
@ -452,7 +452,7 @@ function getPositionInCode(
column:
lastNewLinePos === -1
? generatedOffset
: generatedOffset - lastNewLinePos - 1
: generatedOffset - lastNewLinePos - 1,
}
if (expectName) {
res.name = typeof expectName === 'string' ? expectName : token

View File

@ -1,5 +1,5 @@
import { compileStyle, parse } from '../src'
import { mockId, compileSFCScript, assertCode } from './utils'
import { assertCode, compileSFCScript, mockId } from './utils'
describe('CSS vars injection', () => {
test('generating correct code for nested paths', () => {
@ -8,7 +8,7 @@ describe('CSS vars injection', () => {
`<style>div{
color: v-bind(color);
font-size: v-bind('font.size');
}</style>`
}</style>`,
)
expect(content).toMatch(`_useCssVars(_ctx => ({
"${mockId}-color": (_ctx.color),
@ -32,7 +32,7 @@ describe('CSS vars injection', () => {
div {
font-size: v-bind(size);
}
</style>`
</style>`,
)
expect(content).toMatch(`_useCssVars(_ctx => ({
"${mockId}-size": (_ctx.size)
@ -57,7 +57,7 @@ describe('CSS vars injection', () => {
font-size: v-bind(size);
border: v-bind(foo);
}
</style>`
</style>`,
)
// should handle:
// 1. local const bindings
@ -69,7 +69,7 @@ describe('CSS vars injection', () => {
"${mockId}-foo": (__props.foo)
})`)
expect(content).toMatch(
`import { useCssVars as _useCssVars, unref as _unref } from 'vue'`
`import { useCssVars as _useCssVars, unref as _unref } from 'vue'`,
)
assertCode(content)
})
@ -85,7 +85,7 @@ describe('CSS vars injection', () => {
font-family: v-bind();
}`,
filename: 'test.css',
id: 'data-v-test'
id: 'data-v-test',
})
expect(code).toMatchInlineSnapshot(`
".foo {
@ -106,7 +106,7 @@ describe('CSS vars injection', () => {
color: v-bind(color);
font-size: v-bind('font.size');
}</style>`,
{ isProd: true }
{ isProd: true },
)
expect(content).toMatch(`_useCssVars(_ctx => ({
"4003f1a6": (_ctx.color),
@ -120,7 +120,7 @@ describe('CSS vars injection', () => {
}`,
filename: 'test.css',
id: mockId,
isProd: true
isProd: true,
})
expect(code).toMatchInlineSnapshot(`
".foo {
@ -135,8 +135,8 @@ describe('CSS vars injection', () => {
assertCode(
compileSFCScript(
`<script>const a = 1</script>\n` +
`<style>div{ color: v-bind(color); }</style>`
).content
`<style>div{ color: v-bind(color); }</style>`,
).content,
)
})
@ -144,8 +144,8 @@ describe('CSS vars injection', () => {
assertCode(
compileSFCScript(
`<script>export default { setup() {} }</script>\n` +
`<style>div{ color: v-bind(color); }</style>`
).content
`<style>div{ color: v-bind(color); }</style>`,
).content,
)
})
@ -155,8 +155,8 @@ describe('CSS vars injection', () => {
`<script>
// export default {}
export default {}
</script>\n` + `<style>div{ color: v-bind(color); }</style>`
).content
</script>\n` + `<style>div{ color: v-bind(color); }</style>`,
).content,
)
})
@ -164,8 +164,8 @@ describe('CSS vars injection', () => {
assertCode(
compileSFCScript(
`<script setup>const color = 'red'</script>\n` +
`<style>div{ color: v-bind(color); }</style>`
).content
`<style>div{ color: v-bind(color); }</style>`,
).content,
)
})
@ -178,7 +178,7 @@ describe('CSS vars injection', () => {
div{ /* color: v-bind(color); */ width:20; }
div{ width: v-bind(width); }
/* comment */
</style>`
</style>`,
)
expect(content).not.toMatch(`"${mockId}-color": (color)`)
@ -198,7 +198,7 @@ describe('CSS vars injection', () => {
p {
color: v-bind(color);
}
</style>`
</style>`,
)
// color should only be injected once, even if it is twice in style
expect(content).toMatch(`_useCssVars(_ctx => ({
@ -229,7 +229,7 @@ describe('CSS vars injection', () => {
p {
color: v-bind(((a + b)) / (2 * a));
}
</style>`
</style>`,
)
expect(content).toMatch(`_useCssVars(_ctx => ({
"${mockId}-foo": (_unref(foo)),
@ -243,7 +243,7 @@ describe('CSS vars injection', () => {
// #6022
test('should be able to parse incomplete expressions', () => {
const {
descriptor: { cssVars }
descriptor: { cssVars },
} = parse(
`<script setup>let xxx = 1</script>
<style scoped>
@ -251,7 +251,7 @@ describe('CSS vars injection', () => {
font-weight: v-bind("count.toString(");
font-weight: v-bind(xxx);
}
</style>`
</style>`,
)
expect(cssVars).toMatchObject([`count.toString(`, `xxx`])
})
@ -266,10 +266,10 @@ describe('CSS vars injection', () => {
label {
background: v-bind(background);
}
</style>`
</style>`,
)
expect(content).toMatch(
`export default {\n setup(__props, { expose: __expose }) {\n __expose();\n\n_useCssVars(_ctx => ({\n "xxxxxxxx-background": (_unref(background))\n}))`
`export default {\n setup(__props, { expose: __expose }) {\n __expose();\n\n_useCssVars(_ctx => ({\n "xxxxxxxx-background": (_unref(background))\n}))`,
)
})
@ -287,9 +287,9 @@ describe('CSS vars injection', () => {
{
inlineTemplate: true,
templateOptions: {
ssr: true
}
}
ssr: true,
},
},
)
expect(content).not.toMatch(`_useCssVars`)
})
@ -308,9 +308,9 @@ describe('CSS vars injection', () => {
{
inlineTemplate: false,
templateOptions: {
ssr: true
}
}
ssr: true,
},
},
)
expect(content).not.toMatch(`_useCssVars`)
})
@ -333,9 +333,9 @@ describe('CSS vars injection', () => {
</style>`,
{
templateOptions: {
ssr: true
}
}
ssr: true,
},
},
)
expect(content).not.toMatch(`_useCssVars`)
})

View File

@ -37,7 +37,7 @@ font-weight: bold;
}
</style>`
const {
descriptor: { styles }
descriptor: { styles },
} = parse(src)
expect(styles[0].map).not.toBeUndefined()
@ -69,7 +69,7 @@ font-weight: bold;
// Padding determines how many blank lines will there be before the style block
const padding = Math.round(Math.random() * 10)
const script = parse(
`${'\n'.repeat(padding)}<script>\nconsole.log(1)\n }\n</script>\n`
`${'\n'.repeat(padding)}<script>\nconsole.log(1)\n }\n</script>\n`,
).descriptor.script
expect(script!.map).not.toBeUndefined()
@ -88,7 +88,7 @@ font-weight: bold;
h1 foo
div bar
span baz
</template>\n`
</template>\n`,
).descriptor.template!
expect(template.map).not.toBeUndefined()
@ -103,7 +103,7 @@ font-weight: bold;
test('custom block', () => {
const padding = Math.round(Math.random() * 10)
const custom = parse(
`${'\n'.repeat(padding)}<i18n>\n{\n "greeting": "hello"\n}\n</i18n>\n`
`${'\n'.repeat(padding)}<i18n>\n{\n "greeting": "hello"\n}\n</i18n>\n`,
).descriptor.customBlocks[0]
expect(custom!.map).not.toBeUndefined()
@ -138,42 +138,42 @@ h1 { color: red }
const padTrue = parse(content.trim(), { pad: true }).descriptor
expect(padTrue.script!.content).toBe(
Array(3 + 1).join('//\n') + '\nexport default {}\n'
Array(3 + 1).join('//\n') + '\nexport default {}\n',
)
expect(padTrue.styles[0].content).toBe(
Array(6 + 1).join('\n') + '\nh1 { color: red }\n'
Array(6 + 1).join('\n') + '\nh1 { color: red }\n',
)
expect(padTrue.customBlocks[0].content).toBe(
Array(9 + 1).join('\n') + '\n{ "greeting": "hello" }\n'
Array(9 + 1).join('\n') + '\n{ "greeting": "hello" }\n',
)
const padLine = parse(content.trim(), { pad: 'line' }).descriptor
expect(padLine.script!.content).toBe(
Array(3 + 1).join('//\n') + '\nexport default {}\n'
Array(3 + 1).join('//\n') + '\nexport default {}\n',
)
expect(padLine.styles[0].content).toBe(
Array(6 + 1).join('\n') + '\nh1 { color: red }\n'
Array(6 + 1).join('\n') + '\nh1 { color: red }\n',
)
expect(padLine.customBlocks[0].content).toBe(
Array(9 + 1).join('\n') + '\n{ "greeting": "hello" }\n'
Array(9 + 1).join('\n') + '\n{ "greeting": "hello" }\n',
)
const padSpace = parse(content.trim(), { pad: 'space' }).descriptor
expect(padSpace.script!.content).toBe(
`<template>\n<div></div>\n</template>\n<script>`.replace(/./g, ' ') +
'\nexport default {}\n'
'\nexport default {}\n',
)
expect(padSpace.styles[0].content).toBe(
`<template>\n<div></div>\n</template>\n<script>\nexport default {}\n</script>\n<style>`.replace(
/./g,
' '
) + '\nh1 { color: red }\n'
' ',
) + '\nh1 { color: red }\n',
)
expect(padSpace.customBlocks[0].content).toBe(
`<template>\n<div></div>\n</template>\n<script>\nexport default {}\n</script>\n<style>\nh1 { color: red }\n</style>\n<i18n>`.replace(
/./g,
' '
) + '\n{ "greeting": "hello" }\n'
' ',
) + '\n{ "greeting": "hello" }\n',
)
})
@ -187,8 +187,8 @@ h1 { color: red }
end: {
line: 3,
column: 1,
offset: 10 + content.length
}
offset: 10 + content.length,
},
})
})
@ -198,7 +198,7 @@ h1 { color: red }
expect(descriptor.template!.content).toBeFalsy()
expect(descriptor.template!.loc).toMatchObject({
start: { line: 1, column: 12, offset: 11 },
end: { line: 1, column: 12, offset: 11 }
end: { line: 1, column: 12, offset: 11 },
})
})
@ -208,7 +208,7 @@ h1 { color: red }
expect(descriptor.template!.content).toBeFalsy()
expect(descriptor.template!.loc).toMatchObject({
start: { line: 1, column: 11, offset: 10 },
end: { line: 1, column: 11, offset: 10 }
end: { line: 1, column: 11, offset: 10 },
})
})
@ -219,7 +219,7 @@ h1 { color: red }
expect(parse(`<style> \n\t </style>`).descriptor.styles.length).toBe(0)
expect(parse(`<custom/>`).descriptor.customBlocks.length).toBe(0)
expect(
parse(`<custom> \n\t </custom>`).descriptor.customBlocks.length
parse(`<custom> \n\t </custom>`).descriptor.customBlocks.length,
).toBe(0)
})
@ -239,19 +239,19 @@ h1 { color: red }
const { descriptor } = parse(
`<script></script>\n<script setup>\n</script>`,
{
ignoreEmpty: false
}
ignoreEmpty: false,
},
)
expect(descriptor.script).toBeTruthy()
expect(descriptor.script!.loc).toMatchObject({
start: { line: 1, column: 9, offset: 8 },
end: { line: 1, column: 9, offset: 8 }
end: { line: 1, column: 9, offset: 8 },
})
expect(descriptor.scriptSetup).toBeTruthy()
expect(descriptor.scriptSetup!.loc).toMatchObject({
start: { line: 2, column: 15, offset: 32 },
end: { line: 3, column: 1, offset: 33 }
end: { line: 3, column: 1, offset: 33 },
})
})
@ -267,7 +267,7 @@ h1 { color: red }
test('treat empty lang attribute as the html', () => {
const content = `<div><template v-if="ok">ok</template></div>`
const { descriptor, errors } = parse(
`<template lang="">${content}</template>`
`<template lang="">${content}</template>`,
)
expect(descriptor.template!.content).toBe(content)
expect(errors.length).toBe(0)
@ -277,7 +277,7 @@ h1 { color: red }
test('template with preprocessor lang should be treated as plain text', () => {
const content = `p(v-if="1 < 2") test <div/>`
const { descriptor, errors } = parse(
`<template lang="pug">` + content + `</template>`
`<template lang="pug">` + content + `</template>`,
)
expect(errors.length).toBe(0)
expect(descriptor.template!.content).toBe(content)
@ -301,17 +301,17 @@ h1 { color: red }
expect(parse(`<template>hi</template>`).descriptor.slotted).toBe(false)
expect(
parse(`<template>hi</template><style>h1{color:red;}</style>`).descriptor
.slotted
.slotted,
).toBe(false)
expect(
parse(
`<template>hi</template><style scoped>:slotted(h1){color:red;}</style>`
).descriptor.slotted
`<template>hi</template><style scoped>:slotted(h1){color:red;}</style>`,
).descriptor.slotted,
).toBe(true)
expect(
parse(
`<template>hi</template><style scoped>::v-slotted(h1){color:red;}</style>`
).descriptor.slotted
`<template>hi</template><style scoped>::v-slotted(h1){color:red;}</style>`,
).descriptor.slotted,
).toBe(true)
})
@ -332,8 +332,8 @@ h1 { color: red }
options.onError!(new Error('foo') as any)
return createRoot([])
},
compile: baseCompile
}
compile: baseCompile,
},
})
expect(errors.length).toBe(2)
// error thrown by the custom parse
@ -344,7 +344,7 @@ h1 { color: red }
test('treat custom blocks as raw text', () => {
const { errors, descriptor } = parse(
`<template><input></template><foo> <-& </foo>`
`<template><input></template><foo> <-& </foo>`,
)
expect(errors.length).toBe(0)
expect(descriptor.customBlocks[0].content).toBe(` <-& `)
@ -358,7 +358,7 @@ h1 { color: red }
test('should only allow single template element', () => {
assertWarning(
parse(`<template><div/></template><template><div/></template>`).errors,
`Single file component can contain only one <template> element`
`Single file component can contain only one <template> element`,
)
})
@ -366,24 +366,24 @@ h1 { color: red }
assertWarning(
parse(`<script>console.log(1)</script><script>console.log(1)</script>`)
.errors,
`Single file component can contain only one <script> element`
`Single file component can contain only one <script> element`,
)
})
test('should only allow single script setup element', () => {
assertWarning(
parse(
`<script setup>console.log(1)</script><script setup>console.log(1)</script>`
`<script setup>console.log(1)</script><script setup>console.log(1)</script>`,
).errors,
`Single file component can contain only one <script setup> element`
`Single file component can contain only one <script setup> element`,
)
})
test('should not warn script & script setup', () => {
expect(
parse(
`<script setup>console.log(1)</script><script>console.log(1)</script>`
).errors.length
`<script setup>console.log(1)</script><script>console.log(1)</script>`,
).errors.length,
).toBe(0)
})
@ -391,7 +391,7 @@ h1 { color: red }
test('should throw error if no <template> or <script> is present', () => {
assertWarning(
parse(`import { ref } from 'vue'`).errors,
`At least one <template> or <script> is required in a single file component`
`At least one <template> or <script> is required in a single file component`,
)
})
})

View File

@ -11,7 +11,7 @@ describe('compiler sfc: rewriteDefault', () => {
test('rewrite export default', () => {
expect(
rewriteDefault(`export default {}`, 'script')
rewriteDefault(`export default {}`, 'script'),
).toMatchInlineSnapshot(`"const script = {}"`)
})
@ -27,8 +27,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`const a = 1 \n export { a as b, a as default, a as c}`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const a = 1
export { a as b, a as c}
@ -38,8 +38,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`const a = 1 \n export { a as b, a as default , a as c}`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const a = 1
export { a as b, a as c}
@ -49,8 +49,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`const a = 1 \n export { a as b } \n export { a as default, a as c }`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const a = 1
export { a as b }
@ -69,7 +69,7 @@ describe('compiler sfc: rewriteDefault', () => {
test('export named default multiline', () => {
expect(
rewriteDefault(`let App = {}\n export {\nApp as default\n}`, '_sfc_main')
rewriteDefault(`let App = {}\n export {\nApp as default\n}`, '_sfc_main'),
).toMatchInlineSnapshot(`
"let App = {}
export {
@ -84,8 +84,8 @@ describe('compiler sfc: rewriteDefault', () => {
rewriteDefault(
`const a = 1 \n export {\n a as b,\n a as default,\n a as c}\n` +
`// export { myFunction as default }`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const a = 1
export {
@ -100,8 +100,8 @@ describe('compiler sfc: rewriteDefault', () => {
rewriteDefault(
`const a = 1 \n export {\n a as b,\n a as default ,\n a as c}\n` +
`// export { myFunction as default }`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const a = 1
export {
@ -115,7 +115,7 @@ describe('compiler sfc: rewriteDefault', () => {
test(`export { default } from '...'`, async () => {
expect(
rewriteDefault(`export { default, foo } from './index.js'`, 'script')
rewriteDefault(`export { default, foo } from './index.js'`, 'script'),
).toMatchInlineSnapshot(`
"import { default as __VUE_DEFAULT__ } from './index.js'
export { foo } from './index.js'
@ -123,7 +123,7 @@ describe('compiler sfc: rewriteDefault', () => {
`)
expect(
rewriteDefault(`export { default , foo } from './index.js'`, 'script')
rewriteDefault(`export { default , foo } from './index.js'`, 'script'),
).toMatchInlineSnapshot(`
"import { default as __VUE_DEFAULT__ } from './index.js'
export { foo } from './index.js'
@ -131,7 +131,7 @@ describe('compiler sfc: rewriteDefault', () => {
`)
expect(
rewriteDefault(`export { foo, default } from './index.js'`, 'script')
rewriteDefault(`export { foo, default } from './index.js'`, 'script'),
).toMatchInlineSnapshot(`
"import { default as __VUE_DEFAULT__ } from './index.js'
export { foo, } from './index.js'
@ -141,8 +141,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`export { foo as default, bar } from './index.js'`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"import { foo as __VUE_DEFAULT__ } from './index.js'
export { bar } from './index.js'
@ -152,8 +152,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`export { foo as default , bar } from './index.js'`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"import { foo as __VUE_DEFAULT__ } from './index.js'
export { bar } from './index.js'
@ -163,8 +163,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`export { bar, foo as default } from './index.js'`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"import { foo as __VUE_DEFAULT__ } from './index.js'
export { bar, } from './index.js'
@ -174,8 +174,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`export { foo as default } from './index.js' \n const foo = 1`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"import { foo as __VUE_DEFAULT__ } from './index.js'
export { } from './index.js'
@ -186,8 +186,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`const a = 1 \nexport { a as default } from 'xxx'`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"import { a as __VUE_DEFAULT__ } from 'xxx'
const a = 1
@ -206,7 +206,10 @@ describe('compiler sfc: rewriteDefault', () => {
test('export default class w/ comments', async () => {
expect(
rewriteDefault(`// export default\nexport default class Foo {}`, 'script')
rewriteDefault(
`// export default\nexport default class Foo {}`,
'script',
),
).toMatchInlineSnapshot(`
"// export default
class Foo {}
@ -218,8 +221,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`export default {}\n` + `// export default class Foo {}`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const script = {}
// export default class Foo {}"
@ -230,8 +233,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`/*\nexport default class Foo {}*/\n` + `export default class Bar {}`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"/*
export default class Foo {}*/
@ -243,8 +246,8 @@ describe('compiler sfc: rewriteDefault', () => {
test('@Component\nexport default class', async () => {
expect(
rewriteDefault(`@Component\nexport default class Foo {}`, 'script', [
'decorators-legacy'
])
'decorators-legacy',
]),
).toMatchInlineSnapshot(`
"@Component class Foo {}
const script = Foo"
@ -256,8 +259,8 @@ describe('compiler sfc: rewriteDefault', () => {
rewriteDefault(
`// export default\n@Component\nexport default class Foo {}`,
'script',
['decorators-legacy']
)
['decorators-legacy'],
),
).toMatchInlineSnapshot(`
"// export default
@Component class Foo {}
@ -269,8 +272,8 @@ describe('compiler sfc: rewriteDefault', () => {
expect(
rewriteDefault(
`export default {}\n` + `// @Component\n// export default class Foo {}`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"const script = {}
// @Component
@ -283,8 +286,8 @@ describe('compiler sfc: rewriteDefault', () => {
rewriteDefault(
`/*\n@Component\nexport default class Foo {}*/\n` +
`export default class Bar {}`,
'script'
)
'script',
),
).toMatchInlineSnapshot(`
"/*
@Component

View File

@ -1,14 +1,14 @@
import {
generate,
type TransformOptions,
baseParse,
generate,
transform,
TransformOptions
} from '@vue/compiler-core'
import {
transformAssetUrl,
type AssetURLOptions,
createAssetUrlTransformWithOptions,
AssetURLOptions,
normalizeOptions
normalizeOptions,
transformAssetUrl,
} from '../src/template/transformAssetUrl'
import { transformElement } from '../../compiler-core/src/transforms/transformElement'
import { transformBind } from '../../compiler-core/src/transforms/vBind'
@ -17,7 +17,7 @@ import { stringifyStatic } from '../../compiler-dom/src/transforms/stringifyStat
function compileWithAssetUrls(
template: string,
options?: AssetURLOptions,
transformOptions?: TransformOptions
transformOptions?: TransformOptions,
) {
const ast = baseParse(template)
const t = options
@ -26,9 +26,9 @@ function compileWithAssetUrls(
transform(ast, {
nodeTransforms: [t, transformElement],
directiveTransforms: {
bind: transformBind
bind: transformBind,
},
...transformOptions
...transformOptions,
})
return generate(ast, { mode: 'module' })
}
@ -57,8 +57,8 @@ describe('compiler sfc: transform asset url', () => {
'<use href="~@svg/file.svg#fragment"></use>',
{},
{
hoistStatic: true
}
hoistStatic: true,
},
)
expect(result.code).toMatchSnapshot()
})
@ -79,8 +79,8 @@ describe('compiler sfc: transform asset url', () => {
`<img src="~bar.png"></img>` + // -> still converts to import
`<img src="@theme/bar.png"></img>`, // -> still converts to import
{
base: '/foo'
}
base: '/foo',
},
)
expect(code).toMatch(`import _imports_0 from 'bar.png'`)
expect(code).toMatch(`import _imports_1 from '@theme/bar.png'`)
@ -94,8 +94,8 @@ describe('compiler sfc: transform asset url', () => {
`<img src="https://foo.bar/baz.png"/>` +
`<img src="//foo.bar/baz.png"/>`,
{
includeAbsolute: true
}
includeAbsolute: true,
},
)
expect(code).toMatchSnapshot()
})
@ -108,7 +108,7 @@ describe('compiler sfc: transform asset url', () => {
<circle id="myCircle" cx="0" cy="0" r="5" />
</defs>
<use x="5" y="5" xlink:href="#myCircle" />
</svg>`
</svg>`,
)
// should not remove it
expect(code).toMatch(`"xlink:href": "#myCircle"`)
@ -116,7 +116,7 @@ describe('compiler sfc: transform asset url', () => {
test('should allow for full base URLs, with paths', () => {
const { code } = compileWithAssetUrls(`<img src="./logo.png" />`, {
base: 'http://localhost:3000/src/'
base: 'http://localhost:3000/src/',
})
expect(code).toMatchSnapshot()
@ -124,7 +124,7 @@ describe('compiler sfc: transform asset url', () => {
test('should allow for full base URLs, without paths', () => {
const { code } = compileWithAssetUrls(`<img src="./logo.png" />`, {
base: 'http://localhost:3000'
base: 'http://localhost:3000',
})
expect(code).toMatchSnapshot()
@ -132,7 +132,7 @@ describe('compiler sfc: transform asset url', () => {
test('should allow for full base URLs, without port', () => {
const { code } = compileWithAssetUrls(`<img src="./logo.png" />`, {
base: 'http://localhost'
base: 'http://localhost',
})
expect(code).toMatchSnapshot()
@ -140,7 +140,7 @@ describe('compiler sfc: transform asset url', () => {
test('should allow for full base URLs, without protocol', () => {
const { code } = compileWithAssetUrls(`<img src="./logo.png" />`, {
base: '//localhost'
base: '//localhost',
})
expect(code).toMatchSnapshot()
@ -156,12 +156,12 @@ describe('compiler sfc: transform asset url', () => {
`<img src="./bar.png"/>` +
`</div>`,
{
includeAbsolute: true
includeAbsolute: true,
},
{
hoistStatic: true,
transformHoist: stringifyStatic
}
transformHoist: stringifyStatic,
},
)
expect(code).toMatch(`_createStaticVNode`)
expect(code).toMatchSnapshot()
@ -171,12 +171,12 @@ describe('compiler sfc: transform asset url', () => {
const { code } = compileWithAssetUrls(
`<div><img src="/foo bar.png"/></div>`,
{
includeAbsolute: true
includeAbsolute: true,
},
{
hoistStatic: true,
transformHoist: stringifyStatic
}
transformHoist: stringifyStatic,
},
)
expect(code).toMatch(`_createElementVNode`)
expect(code).toContain(`import _imports_0 from '/foo bar.png'`)
@ -186,12 +186,12 @@ describe('compiler sfc: transform asset url', () => {
const { code } = compileWithAssetUrls(
`<div><img src="./foo bar.png"/></div>`,
{
includeAbsolute: true
includeAbsolute: true,
},
{
hoistStatic: true,
transformHoist: stringifyStatic
}
transformHoist: stringifyStatic,
},
)
expect(code).toMatch(`_createElementVNode`)
expect(code).toContain(`import _imports_0 from './foo bar.png'`)

View File

@ -1,25 +1,25 @@
import {
generate,
type TransformOptions,
baseParse,
generate,
transform,
TransformOptions
} from '@vue/compiler-core'
import {
createSrcsetTransformWithOptions,
transformSrcset,
createSrcsetTransformWithOptions
} from '../src/template/transformSrcset'
import { transformElement } from '../../compiler-core/src/transforms/transformElement'
import { transformBind } from '../../compiler-core/src/transforms/vBind'
import {
AssetURLOptions,
normalizeOptions
type AssetURLOptions,
normalizeOptions,
} from '../src/template/transformAssetUrl'
import { stringifyStatic } from '../../compiler-dom/src/transforms/stringifyStatic'
function compileWithSrcset(
template: string,
options?: AssetURLOptions,
transformOptions?: TransformOptions
transformOptions?: TransformOptions,
) {
const ast = baseParse(template)
const srcsetTransform = options
@ -29,9 +29,9 @@ function compileWithSrcset(
hoistStatic: true,
nodeTransforms: [srcsetTransform, transformElement],
directiveTransforms: {
bind: transformBind
bind: transformBind,
},
...transformOptions
...transformOptions,
})
return generate(ast, { mode: 'module' })
}
@ -59,16 +59,16 @@ describe('compiler sfc: transform srcset', () => {
test('transform srcset w/ base', () => {
expect(
compileWithSrcset(src, {
base: '/foo'
}).code
base: '/foo',
}).code,
).toMatchSnapshot()
})
test('transform srcset w/ includeAbsolute: true', () => {
expect(
compileWithSrcset(src, {
includeAbsolute: true
}).code
includeAbsolute: true,
}).code,
).toMatchSnapshot()
})
@ -76,12 +76,12 @@ describe('compiler sfc: transform srcset', () => {
const code = compileWithSrcset(
`<div>${src}</div>`,
{
includeAbsolute: true
includeAbsolute: true,
},
{
hoistStatic: true,
transformHoist: stringifyStatic
}
transformHoist: stringifyStatic,
},
).code
expect(code).toMatch(`_createStaticVNode`)
expect(code).toMatchSnapshot()
@ -94,7 +94,7 @@ describe('compiler sfc: transform srcset', () => {
<img srcset="@/logo.png 1x, ./logo.png 2x"/>
`,
{ base: '/foo/' },
{ hoistStatic: true }
{ hoistStatic: true },
).code
expect(code).toMatchSnapshot()
})

View File

@ -1,7 +1,7 @@
import {
isRelativeUrl,
isDataUrl,
isExternalUrl,
isDataUrl
isRelativeUrl,
} from '../src/template/templateUtils'
describe('compiler sfc:templateUtils isRelativeUrl', () => {

View File

@ -1,8 +1,8 @@
import {
parse,
SFCScriptCompileOptions,
type SFCParseOptions,
type SFCScriptCompileOptions,
compileScript,
SFCParseOptions
parse,
} from '../src'
import { parse as babelParse } from '@babel/parser'
@ -11,7 +11,7 @@ export const mockId = 'xxxxxxxx'
export function compileSFCScript(
src: string,
options?: Partial<SFCScriptCompileOptions>,
parseOptions?: SFCParseOptions
parseOptions?: SFCParseOptions,
) {
const { descriptor, errors } = parse(src, parseOptions)
if (errors.length) {
@ -19,7 +19,7 @@ export function compileSFCScript(
}
return compileScript(descriptor, {
...options,
id: mockId
id: mockId,
})
}
@ -30,8 +30,8 @@ export function assertCode(code: string) {
sourceType: 'module',
plugins: [
'typescript',
['importAttributes', { deprecatedAssertSyntax: true }]
]
['importAttributes', { deprecatedAssertSyntax: true }],
],
})
} catch (e: any) {
console.log(code)

View File

@ -1,7 +1,7 @@
import { LRUCache } from 'lru-cache'
export function createCache<T extends {}>(
max = 500
max = 500,
): Map<string, T> | LRUCache<string, T> {
if (__GLOBAL__ || __ESM_BROWSER__) {
return new Map<string, T>()

Some files were not shown because too many files have changed in this diff Show More