mirror of https://github.com/vuejs/core.git
Merge remote-tracking branch 'upstream/minor'
This commit is contained in:
commit
d28d57bd3f
File diff suppressed because it is too large
Load Diff
|
@ -1796,166 +1796,167 @@ describe('compiler: parse', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test('self closing single tag', () => {
|
||||
const ast = baseParse('<div :class="{ some: condition }" />')
|
||||
describe('Edge Cases', () => {
|
||||
test('self closing single tag', () => {
|
||||
const ast = baseParse('<div :class="{ some: condition }" />')
|
||||
|
||||
expect(ast.children).toHaveLength(1)
|
||||
expect(ast.children[0]).toMatchObject({ tag: 'div' })
|
||||
})
|
||||
|
||||
test('self closing multiple tag', () => {
|
||||
const ast = baseParse(
|
||||
`<div :class="{ some: condition }" />\n` +
|
||||
`<p v-bind:style="{ color: 'red' }"/>`
|
||||
)
|
||||
|
||||
expect(ast).toMatchSnapshot()
|
||||
|
||||
expect(ast.children).toHaveLength(2)
|
||||
expect(ast.children[0]).toMatchObject({ tag: 'div' })
|
||||
expect(ast.children[1]).toMatchObject({ tag: 'p' })
|
||||
})
|
||||
|
||||
test('valid html', () => {
|
||||
const ast = baseParse(
|
||||
`<div :class="{ some: condition }">\n` +
|
||||
` <p v-bind:style="{ color: 'red' }"/>\n` +
|
||||
` <!-- a comment with <html> inside it -->\n` +
|
||||
`</div>`
|
||||
)
|
||||
|
||||
expect(ast).toMatchSnapshot()
|
||||
|
||||
expect(ast.children).toHaveLength(1)
|
||||
const el = ast.children[0] as any
|
||||
expect(el).toMatchObject({
|
||||
tag: 'div'
|
||||
})
|
||||
expect(el.children).toHaveLength(2)
|
||||
expect(el.children[0]).toMatchObject({
|
||||
tag: 'p'
|
||||
})
|
||||
expect(el.children[1]).toMatchObject({
|
||||
type: NodeTypes.COMMENT
|
||||
})
|
||||
})
|
||||
|
||||
test('invalid html', () => {
|
||||
expect(() => {
|
||||
baseParse(`<div>\n<span>\n</div>\n</span>`)
|
||||
}).toThrow('Element is missing end tag.')
|
||||
|
||||
const spy = vi.fn()
|
||||
const ast = baseParse(`<div>\n<span>\n</div>\n</span>`, {
|
||||
onError: spy
|
||||
expect(ast.children).toHaveLength(1)
|
||||
expect(ast.children[0]).toMatchObject({ tag: 'div' })
|
||||
})
|
||||
|
||||
expect(spy.mock.calls).toMatchObject([
|
||||
[
|
||||
{
|
||||
code: ErrorCodes.X_MISSING_END_TAG,
|
||||
loc: {
|
||||
start: {
|
||||
offset: 6,
|
||||
line: 2,
|
||||
column: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
code: ErrorCodes.X_INVALID_END_TAG,
|
||||
loc: {
|
||||
start: {
|
||||
offset: 20,
|
||||
line: 4,
|
||||
column: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
])
|
||||
test('self closing multiple tag', () => {
|
||||
const ast = baseParse(
|
||||
`<div :class="{ some: condition }" />\n` +
|
||||
`<p v-bind:style="{ color: 'red' }"/>`
|
||||
)
|
||||
|
||||
expect(ast).toMatchSnapshot()
|
||||
})
|
||||
expect(ast).toMatchSnapshot()
|
||||
|
||||
test('parse with correct location info', () => {
|
||||
const fooSrc = `foo
|
||||
is `
|
||||
const barSrc = `{{ bar }}`
|
||||
const butSrc = ` but `
|
||||
const bazSrc = `{{ baz }}`
|
||||
const [foo, bar, but, baz] = baseParse(
|
||||
fooSrc + barSrc + butSrc + bazSrc
|
||||
).children
|
||||
expect(ast.children).toHaveLength(2)
|
||||
expect(ast.children[0]).toMatchObject({ tag: 'div' })
|
||||
expect(ast.children[1]).toMatchObject({ tag: 'p' })
|
||||
})
|
||||
|
||||
let offset = 0
|
||||
expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
|
||||
offset += fooSrc.length
|
||||
expect(foo.loc.end).toEqual({ line: 2, column: 5, offset })
|
||||
test('valid html', () => {
|
||||
const ast = baseParse(
|
||||
`<div :class="{ some: condition }">\n` +
|
||||
` <p v-bind:style="{ color: 'red' }"/>\n` +
|
||||
` <!-- a comment with <html> inside it -->\n` +
|
||||
`</div>`
|
||||
)
|
||||
|
||||
expect(bar.loc.start).toEqual({ line: 2, column: 5, offset })
|
||||
const barInner = (bar as InterpolationNode).content
|
||||
offset += 3
|
||||
expect(barInner.loc.start).toEqual({ line: 2, column: 8, offset })
|
||||
offset += 3
|
||||
expect(barInner.loc.end).toEqual({ line: 2, column: 11, offset })
|
||||
offset += 3
|
||||
expect(bar.loc.end).toEqual({ line: 2, column: 14, offset })
|
||||
expect(ast).toMatchSnapshot()
|
||||
|
||||
expect(but.loc.start).toEqual({ line: 2, column: 14, offset })
|
||||
offset += butSrc.length
|
||||
expect(but.loc.end).toEqual({ line: 2, column: 19, offset })
|
||||
expect(ast.children).toHaveLength(1)
|
||||
const el = ast.children[0] as any
|
||||
expect(el).toMatchObject({
|
||||
tag: 'div'
|
||||
})
|
||||
expect(el.children).toHaveLength(2)
|
||||
expect(el.children[0]).toMatchObject({
|
||||
tag: 'p'
|
||||
})
|
||||
expect(el.children[1]).toMatchObject({
|
||||
type: NodeTypes.COMMENT
|
||||
})
|
||||
})
|
||||
|
||||
expect(baz.loc.start).toEqual({ line: 2, column: 19, offset })
|
||||
const bazInner = (baz as InterpolationNode).content
|
||||
offset += 3
|
||||
expect(bazInner.loc.start).toEqual({ line: 2, column: 22, offset })
|
||||
offset += 3
|
||||
expect(bazInner.loc.end).toEqual({ line: 2, column: 25, offset })
|
||||
offset += 3
|
||||
expect(baz.loc.end).toEqual({ line: 2, column: 28, offset })
|
||||
})
|
||||
test('invalid html', () => {
|
||||
expect(() => {
|
||||
baseParse(`<div>\n<span>\n</div>\n</span>`)
|
||||
}).toThrow('Element is missing end tag.')
|
||||
|
||||
// With standard HTML parsing, the following input would ignore the slash
|
||||
// and treat "<" and "template" as attributes on the open tag of "Hello",
|
||||
// causing `<template>` to fail to close, and `<script>` being parsed as its
|
||||
// child. This is would never be intended in actual templates, but is a common
|
||||
// intermediate state from user input when parsing for IDE support. We want
|
||||
// the `<script>` to be at root-level to keep the SFC structure stable for
|
||||
// Volar to do incremental computations.
|
||||
test('tag termination handling for IDE', () => {
|
||||
const spy = vi.fn()
|
||||
const ast = baseParse(
|
||||
`<template><Hello\n</template><script>console.log(1)</script>`,
|
||||
{
|
||||
const spy = vi.fn()
|
||||
const ast = baseParse(`<div>\n<span>\n</div>\n</span>`, {
|
||||
onError: spy
|
||||
}
|
||||
)
|
||||
//
|
||||
expect(ast.children.length).toBe(2)
|
||||
expect(ast.children[1]).toMatchObject({
|
||||
type: NodeTypes.ELEMENT,
|
||||
tag: 'script'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('arg should be undefined on shorthand dirs with no arg', () => {
|
||||
const ast = baseParse(`<template #></template>`)
|
||||
const el = ast.children[0] as ElementNode
|
||||
expect(el.props[0]).toMatchObject({
|
||||
type: NodeTypes.DIRECTIVE,
|
||||
name: 'slot',
|
||||
exp: undefined,
|
||||
arg: undefined
|
||||
})
|
||||
})
|
||||
expect(spy.mock.calls).toMatchObject([
|
||||
[
|
||||
{
|
||||
code: ErrorCodes.X_MISSING_END_TAG,
|
||||
loc: {
|
||||
start: {
|
||||
offset: 6,
|
||||
line: 2,
|
||||
column: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
code: ErrorCodes.X_INVALID_END_TAG,
|
||||
loc: {
|
||||
start: {
|
||||
offset: 20,
|
||||
line: 4,
|
||||
column: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
// edge case found in vue-macros where the input is TS or JSX
|
||||
test('should reset inRCDATA state', () => {
|
||||
baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
|
||||
expect(() => baseParse(`{ foo }`)).not.toThrow()
|
||||
expect(ast).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('parse with correct location info', () => {
|
||||
const fooSrc = `foo\n is `
|
||||
const barSrc = `{{ bar }}`
|
||||
const butSrc = ` but `
|
||||
const bazSrc = `{{ baz }}`
|
||||
const [foo, bar, but, baz] = baseParse(
|
||||
fooSrc + barSrc + butSrc + bazSrc
|
||||
).children
|
||||
|
||||
let offset = 0
|
||||
expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
|
||||
offset += fooSrc.length
|
||||
expect(foo.loc.end).toEqual({ line: 2, column: 5, offset })
|
||||
|
||||
expect(bar.loc.start).toEqual({ line: 2, column: 5, offset })
|
||||
const barInner = (bar as InterpolationNode).content
|
||||
offset += 3
|
||||
expect(barInner.loc.start).toEqual({ line: 2, column: 8, offset })
|
||||
offset += 3
|
||||
expect(barInner.loc.end).toEqual({ line: 2, column: 11, offset })
|
||||
offset += 3
|
||||
expect(bar.loc.end).toEqual({ line: 2, column: 14, offset })
|
||||
|
||||
expect(but.loc.start).toEqual({ line: 2, column: 14, offset })
|
||||
offset += butSrc.length
|
||||
expect(but.loc.end).toEqual({ line: 2, column: 19, offset })
|
||||
|
||||
expect(baz.loc.start).toEqual({ line: 2, column: 19, offset })
|
||||
const bazInner = (baz as InterpolationNode).content
|
||||
offset += 3
|
||||
expect(bazInner.loc.start).toEqual({ line: 2, column: 22, offset })
|
||||
offset += 3
|
||||
expect(bazInner.loc.end).toEqual({ line: 2, column: 25, offset })
|
||||
offset += 3
|
||||
expect(baz.loc.end).toEqual({ line: 2, column: 28, offset })
|
||||
})
|
||||
|
||||
// With standard HTML parsing, the following input would ignore the slash
|
||||
// and treat "<" and "template" as attributes on the open tag of "Hello",
|
||||
// causing `<template>` to fail to close, and `<script>` being parsed as its
|
||||
// child. This is would never be intended in actual templates, but is a common
|
||||
// intermediate state from user input when parsing for IDE support. We want
|
||||
// the `<script>` to be at root-level to keep the SFC structure stable for
|
||||
// Volar to do incremental computations.
|
||||
test('tag termination handling for IDE', () => {
|
||||
const spy = vi.fn()
|
||||
const ast = baseParse(
|
||||
`<template><Hello\n</template><script>console.log(1)</script>`,
|
||||
{
|
||||
onError: spy
|
||||
}
|
||||
)
|
||||
//
|
||||
expect(ast.children.length).toBe(2)
|
||||
expect(ast.children[1]).toMatchObject({
|
||||
type: NodeTypes.ELEMENT,
|
||||
tag: 'script'
|
||||
})
|
||||
})
|
||||
|
||||
test('arg should be undefined on shorthand dirs with no arg', () => {
|
||||
const ast = baseParse(`<template #></template>`)
|
||||
const el = ast.children[0] as ElementNode
|
||||
expect(el.props[0]).toMatchObject({
|
||||
type: NodeTypes.DIRECTIVE,
|
||||
name: 'slot',
|
||||
exp: undefined,
|
||||
arg: undefined
|
||||
})
|
||||
})
|
||||
|
||||
// edge case found in vue-macros where the input is TS or JSX
|
||||
test('should reset inRCDATA state', () => {
|
||||
baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
|
||||
expect(() => baseParse(`{ foo }`)).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('decodeEntities option', () => {
|
||||
|
|
|
@ -161,6 +161,14 @@ describe('compiler: expression transform', () => {
|
|||
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||
children: [{ content: `Math` }, `.`, { content: `max` }, `(1, 2)`]
|
||||
})
|
||||
|
||||
expect(
|
||||
(parseWithExpressionTransform(`{{ new Error() }}`) as InterpolationNode)
|
||||
.content
|
||||
).toMatchObject({
|
||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||
children: ['new ', { content: 'Error' }, '()']
|
||||
})
|
||||
})
|
||||
|
||||
test('should not prefix reserved literals', () => {
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
"lru-cache": "^10.1.0",
|
||||
"merge-source-map": "^1.1.0",
|
||||
"minimatch": "^9.0.3",
|
||||
"postcss-modules": "^4.3.1",
|
||||
"postcss-modules": "^6.0.0",
|
||||
"postcss-selector-parser": "^6.0.13",
|
||||
"pug": "^3.0.2",
|
||||
"sass": "^1.69.5"
|
||||
|
|
|
@ -3,7 +3,7 @@ import { makeMap } from './makeMap'
|
|||
const GLOBALS_ALLOWED =
|
||||
'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
|
||||
'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
|
||||
'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console'
|
||||
'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error'
|
||||
|
||||
export const isGloballyAllowed = /*#__PURE__*/ makeMap(GLOBALS_ALLOWED)
|
||||
|
||||
|
|
|
@ -245,8 +245,8 @@ importers:
|
|||
specifier: ^9.0.3
|
||||
version: 9.0.3
|
||||
postcss-modules:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1(postcss@8.4.31)
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(postcss@8.4.31)
|
||||
postcss-selector-parser:
|
||||
specifier: ^6.0.13
|
||||
version: 6.0.13
|
||||
|
@ -3689,10 +3689,6 @@ packages:
|
|||
safer-buffer: 2.1.2
|
||||
dev: true
|
||||
|
||||
/icss-replace-symbols@1.1.0:
|
||||
resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==}
|
||||
dev: true
|
||||
|
||||
/icss-utils@5.1.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==}
|
||||
engines: {node: ^10 || ^12 || >= 14}
|
||||
|
@ -4917,13 +4913,13 @@ packages:
|
|||
postcss: 8.4.31
|
||||
dev: true
|
||||
|
||||
/postcss-modules@4.3.1(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==}
|
||||
/postcss-modules@6.0.0(postcss@8.4.31):
|
||||
resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==}
|
||||
peerDependencies:
|
||||
postcss: ^8.0.0
|
||||
dependencies:
|
||||
generic-names: 4.0.0
|
||||
icss-replace-symbols: 1.1.0
|
||||
icss-utils: 5.1.0(postcss@8.4.31)
|
||||
lodash.camelcase: 4.3.0
|
||||
postcss: 8.4.31
|
||||
postcss-modules-extract-imports: 3.0.0(postcss@8.4.31)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-check
|
||||
import assert from 'node:assert/strict'
|
||||
import { createRequire } from 'node:module'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'node:path'
|
||||
|
@ -14,6 +15,14 @@ import alias from '@rollup/plugin-alias'
|
|||
import { entries } from './scripts/aliases.js'
|
||||
import { inlineEnums } from './scripts/inline-enums.js'
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef { Omit<T, K> & Required<Pick<T, K>> } MarkRequired
|
||||
*/
|
||||
/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime'} PackageFormat */
|
||||
/** @typedef {MarkRequired<import('rollup').OutputOptions, 'file' | 'format'>} OutputOptions */
|
||||
|
||||
if (!process.env.TARGET) {
|
||||
throw new Error('TARGET package must be specified via --environment flag.')
|
||||
}
|
||||
|
@ -27,45 +36,35 @@ const consolidatePkg = require('@vue/consolidate/package.json')
|
|||
const packagesDir = path.resolve(__dirname, 'packages')
|
||||
const packageDir = path.resolve(packagesDir, process.env.TARGET)
|
||||
|
||||
/** @param {string} p */
|
||||
const resolve = p => path.resolve(packageDir, p)
|
||||
const resolve = (/** @type {string} */ p) => path.resolve(packageDir, p)
|
||||
const pkg = require(resolve(`package.json`))
|
||||
const packageOptions = pkg.buildOptions || {}
|
||||
const name = packageOptions.filename || path.basename(packageDir)
|
||||
|
||||
const [enumPlugin, enumDefines] = inlineEnums()
|
||||
|
||||
/**
|
||||
* @typedef { Omit<T, K> & Required<Pick<T, K>> } MarkRequired
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
*/
|
||||
|
||||
/** @typedef {import('rollup').ModuleFormat} Format */
|
||||
/** @typedef {MarkRequired<import('rollup').OutputOptions, 'file'>} Output */
|
||||
|
||||
/** @type {Record<string, Output>} */
|
||||
/** @type {Record<PackageFormat, OutputOptions>} */
|
||||
const outputConfigs = {
|
||||
'esm-bundler': {
|
||||
file: resolve(`dist/${name}.esm-bundler.js`),
|
||||
format: `es`
|
||||
format: 'es'
|
||||
},
|
||||
'esm-browser': {
|
||||
file: resolve(`dist/${name}.esm-browser.js`),
|
||||
format: `es`
|
||||
format: 'es'
|
||||
},
|
||||
cjs: {
|
||||
file: resolve(`dist/${name}.cjs.js`),
|
||||
format: `cjs`
|
||||
format: 'cjs'
|
||||
},
|
||||
global: {
|
||||
file: resolve(`dist/${name}.global.js`),
|
||||
format: `iife`
|
||||
format: 'iife'
|
||||
},
|
||||
// runtime-only builds, for main "vue" package only
|
||||
'esm-bundler-runtime': {
|
||||
file: resolve(`dist/${name}.runtime.esm-bundler.js`),
|
||||
format: `es`
|
||||
format: 'es'
|
||||
},
|
||||
'esm-browser-runtime': {
|
||||
file: resolve(`dist/${name}.runtime.esm-browser.js`),
|
||||
|
@ -77,40 +76,39 @@ const outputConfigs = {
|
|||
}
|
||||
}
|
||||
|
||||
/** @type {ReadonlyArray<PackageFormat>} */
|
||||
const defaultFormats = ['esm-bundler', 'cjs']
|
||||
const inlineFormats = process.env.FORMATS && process.env.FORMATS.split(',')
|
||||
/** @type {ReadonlyArray<PackageFormat>} */
|
||||
const inlineFormats = /** @type {any} */ (
|
||||
process.env.FORMATS && process.env.FORMATS.split(',')
|
||||
)
|
||||
/** @type {ReadonlyArray<PackageFormat>} */
|
||||
const packageFormats = inlineFormats || packageOptions.formats || defaultFormats
|
||||
const packageConfigs = process.env.PROD_ONLY
|
||||
? []
|
||||
: packageFormats.map(
|
||||
/** @param {Format} format */
|
||||
format => createConfig(format, outputConfigs[format])
|
||||
)
|
||||
: packageFormats.map(format => createConfig(format, outputConfigs[format]))
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
packageFormats.forEach(
|
||||
/** @param {Format} format */
|
||||
format => {
|
||||
if (packageOptions.prod === false) {
|
||||
return
|
||||
}
|
||||
if (format === 'cjs') {
|
||||
packageConfigs.push(createProductionConfig(format))
|
||||
}
|
||||
if (/^(global|esm-browser)(-runtime)?/.test(format)) {
|
||||
packageConfigs.push(createMinifiedConfig(format))
|
||||
}
|
||||
packageFormats.forEach(format => {
|
||||
if (packageOptions.prod === false) {
|
||||
return
|
||||
}
|
||||
)
|
||||
if (format === 'cjs') {
|
||||
packageConfigs.push(createProductionConfig(format))
|
||||
}
|
||||
if (/^(global|esm-browser)(-runtime)?/.test(format)) {
|
||||
packageConfigs.push(createMinifiedConfig(format))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default packageConfigs
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Format} format
|
||||
* @param {Output} output
|
||||
* @param {import('rollup').Plugin[]} plugins
|
||||
* @param {PackageFormat} format
|
||||
* @param {OutputOptions} output
|
||||
* @param {ReadonlyArray<import('rollup').Plugin>} plugins
|
||||
* @returns {import('rollup').RollupOptions}
|
||||
*/
|
||||
function createConfig(format, output, plugins = []) {
|
||||
|
@ -180,7 +178,7 @@ function createConfig(format, output, plugins = []) {
|
|||
],
|
||||
output,
|
||||
onwarn(msg, warn) {
|
||||
if (!/Circular/.test(msg.message)) {
|
||||
if (msg.code !== 'CIRCULAR_DEPENDENCY') {
|
||||
warn(msg)
|
||||
}
|
||||
},
|
||||
|
@ -221,7 +219,6 @@ function createConfig(format, output, plugins = []) {
|
|||
|
||||
if (!isBundlerESMBuild) {
|
||||
// hard coded dev/prod builds
|
||||
// @ts-ignore
|
||||
replacements.__DEV__ = String(!isProductionBuild)
|
||||
}
|
||||
|
||||
|
@ -229,7 +226,9 @@ function createConfig(format, output, plugins = []) {
|
|||
//__RUNTIME_COMPILE__=true pnpm build runtime-core
|
||||
Object.keys(replacements).forEach(key => {
|
||||
if (key in process.env) {
|
||||
replacements[key] = /** @type {string} */ (process.env[key])
|
||||
const value = process.env[key]
|
||||
assert(typeof value === 'string')
|
||||
replacements[key] = value
|
||||
}
|
||||
})
|
||||
return replacements
|
||||
|
@ -266,7 +265,6 @@ function createConfig(format, output, plugins = []) {
|
|||
}
|
||||
|
||||
if (Object.keys(replacements).length) {
|
||||
// @ts-ignore
|
||||
return [replace({ values: replacements, preventAssignment: true })]
|
||||
} else {
|
||||
return []
|
||||
|
@ -304,7 +302,7 @@ function createConfig(format, output, plugins = []) {
|
|||
function resolveNodePlugins() {
|
||||
// we are bundling forked consolidate.js in compiler-sfc which dynamically
|
||||
// requires a ton of template engines which should be ignored.
|
||||
/** @type { string[] } */
|
||||
/** @type {ReadonlyArray<string>} */
|
||||
let cjsIgnores = []
|
||||
if (
|
||||
pkg.name === '@vue/compiler-sfc' ||
|
||||
|
@ -339,20 +337,14 @@ function createConfig(format, output, plugins = []) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Format} format
|
||||
*/
|
||||
function createProductionConfig(format) {
|
||||
function createProductionConfig(/** @type {PackageFormat} */ format) {
|
||||
return createConfig(format, {
|
||||
...outputConfigs[format],
|
||||
file: resolve(`dist/${name}.${format}.prod.js`)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Format} format
|
||||
*/
|
||||
function createMinifiedConfig(format) {
|
||||
function createMinifiedConfig(/** @type {PackageFormat} */ format) {
|
||||
return createConfig(
|
||||
format,
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @ts-check
|
||||
import assert from 'node:assert/strict'
|
||||
import { parse } from '@babel/parser'
|
||||
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs'
|
||||
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import MagicString from 'magic-string'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
|
||||
|
@ -70,15 +71,16 @@ function patchTypes(pkg) {
|
|||
if (!node.id) {
|
||||
return
|
||||
}
|
||||
// @ts-ignore
|
||||
assert(node.id.type === 'Identifier')
|
||||
const name = node.id.name
|
||||
if (name.startsWith('_')) {
|
||||
return
|
||||
}
|
||||
shouldRemoveExport.add(name)
|
||||
if (isExported.has(name)) {
|
||||
// @ts-ignore
|
||||
s.prependLeft((parentDecl || node).start, `export `)
|
||||
const start = (parentDecl || node).start
|
||||
assert(typeof start === 'number')
|
||||
s.prependLeft(start, `export `)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,9 +104,10 @@ function patchTypes(pkg) {
|
|||
if (node.type === 'VariableDeclaration') {
|
||||
processDeclaration(node.declarations[0], node)
|
||||
if (node.declarations.length > 1) {
|
||||
assert(typeof node.start === 'number')
|
||||
assert(typeof node.end === 'number')
|
||||
throw new Error(
|
||||
`unhandled declare const with more than one declarators:\n${code.slice(
|
||||
// @ts-ignore
|
||||
node.start,
|
||||
node.end
|
||||
)}`
|
||||
|
@ -131,7 +134,7 @@ function patchTypes(pkg) {
|
|||
spec.type === 'ExportSpecifier' &&
|
||||
shouldRemoveExport.has(spec.local.name)
|
||||
) {
|
||||
// @ts-ignore
|
||||
assert(spec.exported.type === 'Identifier')
|
||||
const exported = spec.exported.name
|
||||
if (exported !== spec.local.name) {
|
||||
// this only happens if we have something like
|
||||
|
@ -141,19 +144,27 @@ function patchTypes(pkg) {
|
|||
}
|
||||
const next = node.specifiers[i + 1]
|
||||
if (next) {
|
||||
// @ts-ignore
|
||||
assert(typeof spec.start === 'number')
|
||||
assert(typeof next.start === 'number')
|
||||
s.remove(spec.start, next.start)
|
||||
} else {
|
||||
// last one
|
||||
const prev = node.specifiers[i - 1]
|
||||
// @ts-ignore
|
||||
s.remove(prev ? prev.end : spec.start, spec.end)
|
||||
assert(typeof spec.start === 'number')
|
||||
assert(typeof spec.end === 'number')
|
||||
s.remove(
|
||||
prev
|
||||
? (assert(typeof prev.end === 'number'), prev.end)
|
||||
: spec.start,
|
||||
spec.end
|
||||
)
|
||||
}
|
||||
removed++
|
||||
}
|
||||
}
|
||||
if (removed === node.specifiers.length) {
|
||||
// @ts-ignore
|
||||
assert(typeof node.start === 'number')
|
||||
assert(typeof node.end === 'number')
|
||||
s.remove(node.start, node.end)
|
||||
}
|
||||
}
|
||||
|
@ -186,11 +197,8 @@ function copyMts() {
|
|||
return {
|
||||
name: 'copy-vue-mts',
|
||||
writeBundle(_, bundle) {
|
||||
writeFileSync(
|
||||
'packages/vue/dist/vue.d.mts',
|
||||
// @ts-ignore
|
||||
bundle['vue.d.ts'].code
|
||||
)
|
||||
assert('code' in bundle['vue.d.ts'])
|
||||
writeFileSync('packages/vue/dist/vue.d.mts', bundle['vue.d.ts'].code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { readdirSync, statSync } from 'node:fs'
|
|||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const resolveEntryForPkg = p =>
|
||||
const resolveEntryForPkg = (/** @type {string} */ p) =>
|
||||
path.resolve(
|
||||
fileURLToPath(import.meta.url),
|
||||
`../../packages/${p}/src/index.ts`
|
||||
|
@ -12,6 +12,7 @@ const resolveEntryForPkg = p =>
|
|||
|
||||
const dirs = readdirSync(new URL('../packages', import.meta.url))
|
||||
|
||||
/** @type {Record<string, string>} */
|
||||
const entries = {
|
||||
vue: resolveEntryForPkg('vue'),
|
||||
'vue/compiler-sfc': resolveEntryForPkg('compiler-sfc'),
|
||||
|
|
|
@ -38,6 +38,7 @@ const prodOnly = !devOnly && (args.prodOnly || args.p)
|
|||
const buildTypes = args.withTypes || args.t
|
||||
const sourceMap = args.sourcemap || args.s
|
||||
const isRelease = args.release
|
||||
/** @type {boolean | undefined} */
|
||||
const buildAllMatching = args.all || args.a
|
||||
const writeSize = args.size
|
||||
const commit = execaSync('git', ['rev-parse', '--short=7', 'HEAD']).stdout
|
||||
|
@ -102,7 +103,9 @@ async function runParallel(maxConcurrency, source, iteratorFn) {
|
|||
ret.push(p)
|
||||
|
||||
if (maxConcurrency <= source.length) {
|
||||
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
|
||||
const e = p.then(() => {
|
||||
executing.splice(executing.indexOf(e), 1)
|
||||
})
|
||||
executing.push(e)
|
||||
if (executing.length >= maxConcurrency) {
|
||||
await Promise.race(executing)
|
||||
|
|
|
@ -9,6 +9,15 @@ import { execa } from 'execa'
|
|||
import { createRequire } from 'node:module'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* name: string
|
||||
* version: string
|
||||
* dependencies?: { [dependenciesPackageName: string]: string }
|
||||
* peerDependencies?: { [peerDependenciesPackageName: string]: string }
|
||||
* }} Package
|
||||
*/
|
||||
|
||||
let versionUpdated = false
|
||||
|
||||
const { prompt } = enquirer
|
||||
|
@ -25,6 +34,7 @@ const args = minimist(process.argv.slice(2), {
|
|||
|
||||
const preId = args.preid || semver.prerelease(currentVersion)?.[0]
|
||||
const isDryRun = args.dry
|
||||
/** @type {boolean | undefined} */
|
||||
let skipTests = args.skipTests
|
||||
const skipBuild = args.skipBuild
|
||||
const isCanary = args.canary
|
||||
|
@ -43,7 +53,7 @@ const packages = fs
|
|||
}
|
||||
})
|
||||
|
||||
const isCorePackage = pkgName => {
|
||||
const isCorePackage = (/** @type {string} */ pkgName) => {
|
||||
if (!pkgName) return
|
||||
|
||||
if (pkgName === 'vue' || pkgName === '@vue/compat') {
|
||||
|
@ -56,7 +66,7 @@ const isCorePackage = pkgName => {
|
|||
)
|
||||
}
|
||||
|
||||
const renamePackageToCanary = pkgName => {
|
||||
const renamePackageToCanary = (/** @type {string} */ pkgName) => {
|
||||
if (pkgName === 'vue') {
|
||||
return '@vue/canary'
|
||||
}
|
||||
|
@ -68,25 +78,37 @@ const renamePackageToCanary = pkgName => {
|
|||
return pkgName
|
||||
}
|
||||
|
||||
const keepThePackageName = pkgName => pkgName
|
||||
const keepThePackageName = (/** @type {string} */ pkgName) => pkgName
|
||||
|
||||
/** @type {string[]} */
|
||||
const skippedPackages = []
|
||||
|
||||
/** @type {ReadonlyArray<import('semver').ReleaseType>} */
|
||||
const versionIncrements = [
|
||||
'patch',
|
||||
'minor',
|
||||
'major',
|
||||
...(preId ? ['prepatch', 'preminor', 'premajor', 'prerelease'] : [])
|
||||
...(preId
|
||||
? /** @type {const} */ (['prepatch', 'preminor', 'premajor', 'prerelease'])
|
||||
: [])
|
||||
]
|
||||
|
||||
const inc = i => semver.inc(currentVersion, i, preId)
|
||||
const run = (bin, args, opts = {}) =>
|
||||
execa(bin, args, { stdio: 'inherit', ...opts })
|
||||
const dryRun = (bin, args, opts = {}) =>
|
||||
console.log(pico.blue(`[dryrun] ${bin} ${args.join(' ')}`), opts)
|
||||
const inc = (/** @type {import('semver').ReleaseType} */ i) =>
|
||||
semver.inc(currentVersion, i, preId)
|
||||
const run = async (
|
||||
/** @type {string} */ bin,
|
||||
/** @type {ReadonlyArray<string>} */ args,
|
||||
/** @type {import('execa').Options} */ opts = {}
|
||||
) => execa(bin, args, { stdio: 'inherit', ...opts })
|
||||
const dryRun = async (
|
||||
/** @type {string} */ bin,
|
||||
/** @type {ReadonlyArray<string>} */ args,
|
||||
/** @type {import('execa').Options} */ opts = {}
|
||||
) => console.log(pico.blue(`[dryrun] ${bin} ${args.join(' ')}`), opts)
|
||||
const runIfNotDry = isDryRun ? dryRun : run
|
||||
const getPkgRoot = pkg => path.resolve(__dirname, '../packages/' + pkg)
|
||||
const step = msg => console.log(pico.cyan(msg))
|
||||
const getPkgRoot = (/** @type {string} */ pkg) =>
|
||||
path.resolve(__dirname, '../packages/' + pkg)
|
||||
const step = (/** @type {string} */ msg) => console.log(pico.cyan(msg))
|
||||
|
||||
async function main() {
|
||||
if (!(await isInSyncWithRemote())) {
|
||||
|
@ -137,7 +159,7 @@ async function main() {
|
|||
semver.inc(latestSameDayPatch, 'prerelease', args.tag)
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (/** @type {any} */ e) {
|
||||
if (/E404/.test(e.message)) {
|
||||
// the first patch version on that day
|
||||
} else {
|
||||
|
@ -150,7 +172,7 @@ async function main() {
|
|||
|
||||
if (!targetVersion) {
|
||||
// no explicit version, offer suggestions
|
||||
// @ts-ignore
|
||||
/** @type {{ release: string }} */
|
||||
const { release } = await prompt({
|
||||
type: 'select',
|
||||
name: 'release',
|
||||
|
@ -159,16 +181,16 @@ async function main() {
|
|||
})
|
||||
|
||||
if (release === 'custom') {
|
||||
/** @type {{ version: string }} */
|
||||
const result = await prompt({
|
||||
type: 'input',
|
||||
name: 'version',
|
||||
message: 'Input custom version',
|
||||
initial: currentVersion
|
||||
})
|
||||
// @ts-ignore
|
||||
targetVersion = result.version
|
||||
} else {
|
||||
targetVersion = release.match(/\((.*)\)/)[1]
|
||||
targetVersion = release.match(/\((.*)\)/)?.[1] ?? ''
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +205,7 @@ async function main() {
|
|||
: `Releasing v${targetVersion}...`
|
||||
)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
/** @type {{ yes: boolean }} */
|
||||
const { yes: confirmRelease } = await prompt({
|
||||
type: 'confirm',
|
||||
name: 'yes',
|
||||
|
@ -201,7 +223,7 @@ async function main() {
|
|||
skipTests ||= isCIPassed
|
||||
|
||||
if (isCIPassed && !skipPrompts) {
|
||||
// @ts-ignore
|
||||
/** @type {{ yes: boolean }} */
|
||||
const { yes: promptSkipTests } = await prompt({
|
||||
type: 'confirm',
|
||||
name: 'yes',
|
||||
|
@ -246,7 +268,7 @@ async function main() {
|
|||
await run(`pnpm`, ['run', 'changelog'])
|
||||
|
||||
if (!skipPrompts) {
|
||||
// @ts-ignore
|
||||
/** @type {{ yes: boolean }} */
|
||||
const { yes: changelogOk } = await prompt({
|
||||
type: 'confirm',
|
||||
name: 'yes',
|
||||
|
@ -346,7 +368,7 @@ async function isInSyncWithRemote() {
|
|||
if (data.sha === (await getSha())) {
|
||||
return true
|
||||
} else {
|
||||
// @ts-ignore
|
||||
/** @type {{ yes: boolean }} */
|
||||
const { yes } = await prompt({
|
||||
type: 'confirm',
|
||||
name: 'yes',
|
||||
|
@ -372,6 +394,10 @@ async function getBranch() {
|
|||
return (await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).stdout
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} version
|
||||
* @param {(pkgName: string) => string} getNewPackageName
|
||||
*/
|
||||
function updateVersions(version, getNewPackageName = keepThePackageName) {
|
||||
// 1. update root package.json
|
||||
updatePackage(path.resolve(__dirname, '..'), version, getNewPackageName)
|
||||
|
@ -381,8 +407,14 @@ function updateVersions(version, getNewPackageName = keepThePackageName) {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} pkgRoot
|
||||
* @param {string} version
|
||||
* @param {(pkgName: string) => string} getNewPackageName
|
||||
*/
|
||||
function updatePackage(pkgRoot, version, getNewPackageName) {
|
||||
const pkgPath = path.resolve(pkgRoot, 'package.json')
|
||||
/** @type {Package} */
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
|
||||
pkg.name = getNewPackageName(pkg.name)
|
||||
pkg.version = version
|
||||
|
@ -393,6 +425,12 @@ function updatePackage(pkgRoot, version, getNewPackageName) {
|
|||
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Package} pkg
|
||||
* @param {'dependencies' | 'peerDependencies'} depType
|
||||
* @param {string} version
|
||||
* @param {(pkgName: string) => string} getNewPackageName
|
||||
*/
|
||||
function updateDeps(pkg, depType, version, getNewPackageName) {
|
||||
const deps = pkg[depType]
|
||||
if (!deps) return
|
||||
|
@ -408,6 +446,11 @@ function updateDeps(pkg, depType, version, getNewPackageName) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} pkgName
|
||||
* @param {string} version
|
||||
* @param {ReadonlyArray<string>} additionalFlags
|
||||
*/
|
||||
async function publishPackage(pkgName, version, additionalFlags) {
|
||||
if (skippedPackages.includes(pkgName)) {
|
||||
return
|
||||
|
@ -443,7 +486,7 @@ async function publishPackage(pkgName, version, additionalFlags) {
|
|||
}
|
||||
)
|
||||
console.log(pico.green(`Successfully published ${pkgName}@${version}`))
|
||||
} catch (e) {
|
||||
} catch (/** @type {any} */ e) {
|
||||
if (e.stderr.match(/previously published/)) {
|
||||
console.log(pico.red(`Skipping already published: ${pkgName}`))
|
||||
} else {
|
||||
|
|
|
@ -16,7 +16,13 @@ export const targets = fs.readdirSync('packages').filter(f => {
|
|||
return true
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ReadonlyArray<string>} partialTargets
|
||||
* @param {boolean | undefined} includeAllMatching
|
||||
*/
|
||||
export function fuzzyMatchTarget(partialTargets, includeAllMatching) {
|
||||
/** @type {Array<string>} */
|
||||
const matched = []
|
||||
partialTargets.forEach(partialTarget => {
|
||||
for (const target of targets) {
|
||||
|
@ -34,7 +40,7 @@ export function fuzzyMatchTarget(partialTargets, includeAllMatching) {
|
|||
console.log()
|
||||
console.error(
|
||||
` ${pico.white(pico.bgRed(' ERROR '))} ${pico.red(
|
||||
`Target ${pico.underline(partialTargets)} not found!`
|
||||
`Target ${pico.underline(partialTargets.toString())} not found!`
|
||||
)}`
|
||||
)
|
||||
console.log()
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
"packages/template-explorer",
|
||||
"packages/sfc-playground",
|
||||
"packages/dts-test",
|
||||
"rollup.config.js",
|
||||
"scripts/*",
|
||||
"playground"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
"packages/*/__tests__",
|
||||
"packages/dts-test",
|
||||
"packages/vue/jsx-runtime",
|
||||
"scripts/*",
|
||||
"rollup.*.js",
|
||||
"playground"
|
||||
],
|
||||
"exclude": ["rollup.config.js"]
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue