Skip to content

Commit c67eeaa

Browse files
authored
Merge branch 'vuejs:master' into master
2 parents b15c512 + 9b6911a commit c67eeaa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+818
-442
lines changed

.github/workflows/auto-fix.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ name: auto-fix
33
on:
44
push:
55
branches:
6-
- 'master'
6+
- master
7+
pull_request_target:
8+
branches:
9+
- master
10+
11+
permissions:
12+
contents: write
713

814
jobs:
915
auto-fix:
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Auto close issues with "can't reproduce" label
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 * * *'
6+
7+
permissions:
8+
issues: write
9+
10+
jobs:
11+
close-issues:
12+
if: github.repository == 'vuejs/language-tools'
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: can't reproduce
16+
uses: actions-cool/issues-helper@v3
17+
with:
18+
actions: close-issues
19+
token: ${{ secrets.GITHUB_TOKEN }}
20+
labels: "can't reproduce"
21+
inactive-day: 3

.github/workflows/pkg.pr.new.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
name: publish-any-commit
2+
23
on: [push, pull_request]
34

45
jobs:

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@
22

33
> [Join the Insiders Program](https://github.com/vuejs/language-tools/wiki/Get-Insiders-Edition) for more exclusive features and updates.
44
5+
## 2.2.8 <sup>official</sup>, 2.2.9 <sup>insiders</sup> (2025-03-02)
6+
7+
### Bug Fixes
8+
9+
- revert "fix(language-core): validate `v-model` variable against model type"
10+
11+
## 2.2.6 <sup>official</sup>, 2.2.7 <sup>insiders</sup> (2025-03-01)
12+
13+
### Features
14+
15+
- feat(language-core): infer prop JSDoc from `defineModel`'s leading comments (#5211) - Thanks to @KazariEX!
16+
17+
### Bug Fixes
18+
19+
- fix(language-core): map camelized prop name correctly (#5207) - Thanks to @KazariEX!
20+
- fix(component-meta): resolve `defineModel` options to collect `default` value (#5209) - Thanks to @KazariEX!
21+
- fix(language-core): avoid duplicate generation of `defineExpose`'s codes - Thanks to @KazariEX!
22+
- fix(language-core): generate camelized prop name for `defineModel` (#5213) - Thanks to @KazariEX!
23+
- fix(language-core): validate `v-model` variable against model type (#5214) - Thanks to @KazariEX!
24+
- fix(language-core): use keywords instead of semicolons to separate script sections (#5217) - Thanks to @KazariEX!
25+
26+
### Other Changes
27+
28+
- ci: auto close issues with `can't reproduce` label - Thanks to @KazariEX!
29+
- refactor(language-core): defer the calculation of `linkedCodeMappings` offsets (#5220) - Thanks to @KazariEX!
30+
531
## 2.2.4 <sup>official</sup>, 2.2.5 <sup>insiders</sup> (2025-02-22)
632

733
### Features

extensions/vscode/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"name": "volar",
4-
"version": "2.2.4",
4+
"version": "2.2.8",
55
"repository": {
66
"type": "git",
77
"url": "https://github.com/vuejs/language-tools.git",
@@ -567,9 +567,9 @@
567567
"@types/vscode": "^1.82.0",
568568
"@volar/vscode": "~2.4.11",
569569
"@vscode/vsce": "^3.2.1",
570-
"@vue/language-core": "2.2.4",
571-
"@vue/language-server": "2.2.4",
572-
"@vue/typescript-plugin": "2.2.4",
570+
"@vue/language-core": "2.2.8",
571+
"@vue/language-server": "2.2.8",
572+
"@vue/typescript-plugin": "2.2.8",
573573
"esbuild": "^0.25.0",
574574
"esbuild-visualizer": "^0.7.0",
575575
"reactive-vscode": "^0.2.9",

insiders.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
{
2-
"latest": "2.2.5",
2+
"latest": "2.2.9",
33
"versions": [
4+
{
5+
"version": "2.2.9",
6+
"date": "2025-03-02",
7+
"downloads": {
8+
"GitHub": "https://github.com/volarjs/insiders/releases/tag/v2.2.9",
9+
"AFDIAN": "https://afdian.com/p/d78b61e8f75011ef812652540025c377"
10+
}
11+
},
12+
{
13+
"version": "2.2.7",
14+
"date": "2025-03-01",
15+
"downloads": {
16+
"GitHub": "https://github.com/volarjs/insiders/releases/tag/v2.2.7",
17+
"AFDIAN": "https://afdian.com/p/f5f588def68311efb21b52540025c377"
18+
}
19+
},
420
{
521
"version": "2.2.5",
622
"date": "2025-02-22",

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
"packages/*",
77
"test-workspace"
88
],
9-
"version": "2.2.4"
9+
"version": "2.2.8"
1010
}

packages/component-meta/lib/base.ts

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ ${commandLine.vueOptions.target < 3 ? vue2TypeHelpersCode : typeHelpersCode}
416416
const type = typeChecker.getTypeOfSymbolAtLocation($exposed, symbolNode);
417417
const properties = type.getProperties().filter(prop =>
418418
// only exposed props will not have a valueDeclaration
419-
!(prop as any).valueDeclaration
419+
!prop.valueDeclaration
420420
);
421421

422422
return properties.map(prop => {
@@ -728,10 +728,10 @@ function readVueComponentDefaultProps(
728728

729729
function scriptSetupWorker() {
730730

731-
const ast = sfc.scriptSetup?.ast;
732-
if (!ast) {
731+
if (!sfc.scriptSetup) {
733732
return;
734733
}
734+
const { ast } = sfc.scriptSetup;
735735

736736
const codegen = vue.tsCodegen.get(sfc);
737737
const scriptSetupRanges = codegen?.getScriptSetupRanges();
@@ -762,10 +762,22 @@ function readVueComponentDefaultProps(
762762
}
763763
}
764764
else if (scriptSetupRanges?.defineProps?.destructured) {
765-
for (const [prop, initializer] of scriptSetupRanges.defineProps.destructured) {
765+
for (const [name, initializer] of scriptSetupRanges.defineProps.destructured) {
766766
if (initializer) {
767767
const expText = printer?.printNode(ts.EmitHint.Expression, initializer, ast) ?? initializer.getText(ast);
768-
result[prop] = { default: expText };
768+
result[name] = {
769+
default: expText
770+
};
771+
}
772+
}
773+
}
774+
775+
if (scriptSetupRanges?.defineProp) {
776+
for (const defineProp of scriptSetupRanges.defineProp) {
777+
const obj = defineProp.argNode ? findObjectLiteralExpression(defineProp.argNode) : undefined;
778+
if (obj) {
779+
const name = defineProp.name ? sfc.scriptSetup.content.slice(defineProp.name.start, defineProp.name.end).slice(1, -1) : 'modelValue';
780+
result[name] = resolveModelOption(ast, obj, printer, ts);
769781
}
770782
}
771783
}
@@ -786,10 +798,10 @@ function readVueComponentDefaultProps(
786798

787799
function scriptWorker() {
788800

789-
const ast = sfc.script?.ast;
790-
if (!ast) {
801+
if (!sfc.script) {
791802
return;
792803
}
804+
const { ast } = sfc.script;
793805

794806
const scriptResult = readTsComponentDefaultProps(ast, 'default', printer, ts);
795807
for (const [key, value] of Object.entries(scriptResult)) {
@@ -899,7 +911,7 @@ function resolvePropsOption(
899911
result[name].required = exp === 'true';
900912
}
901913
if (defaultProp) {
902-
const expNode = resolveDefaultOptionExpression((defaultProp as any).initializer, ts);
914+
const expNode = resolveDefaultOptionExpression(defaultProp.initializer, ts);
903915
const expText = printer?.printNode(ts.EmitHint.Expression, expNode, ast) ?? expNode.getText(ast);
904916
result[name].default = expText;
905917
}
@@ -910,6 +922,28 @@ function resolvePropsOption(
910922
return result;
911923
}
912924

925+
function resolveModelOption(
926+
ast: ts.SourceFile,
927+
options: ts.ObjectLiteralExpression,
928+
printer: ts.Printer | undefined,
929+
ts: typeof import('typescript')
930+
) {
931+
const result: { default?: string; } = {};
932+
933+
for (const prop of options.properties) {
934+
if (ts.isPropertyAssignment(prop)) {
935+
const name = prop.name.getText(ast);
936+
if (name === 'default') {
937+
const expNode = resolveDefaultOptionExpression(prop.initializer, ts);
938+
const expText = printer?.printNode(ts.EmitHint.Expression, expNode, ast) ?? expNode.getText(ast);
939+
result.default = expText;
940+
}
941+
}
942+
}
943+
944+
return result;
945+
}
946+
913947
function resolveDefaultOptionExpression(
914948
_default: ts.Expression,
915949
ts: typeof import('typescript')

packages/component-meta/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-component-meta",
3-
"version": "2.2.4",
3+
"version": "2.2.8",
44
"license": "MIT",
55
"files": [
66
"**/*.js",
@@ -14,9 +14,9 @@
1414
},
1515
"dependencies": {
1616
"@volar/typescript": "~2.4.11",
17-
"@vue/language-core": "2.2.4",
17+
"@vue/language-core": "2.2.8",
1818
"path-browserify": "^1.0.1",
19-
"vue-component-type-helpers": "2.2.4"
19+
"vue-component-type-helpers": "2.2.8"
2020
},
2121
"peerDependencies": {
2222
"typescript": "*"

packages/component-meta/tests/index.spec.ts

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,49 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ
2525

2626
// expect(meta.type).toEqual(TypeMeta.Class);
2727

28+
const modelValue = meta.props.find(prop => prop.name === 'modelValue');
29+
const onUpdateModelValue = meta.events.find(event => event.name === 'update:modelValue');
30+
2831
const foo = meta.props.find(prop => prop.name === 'foo');
2932
const onUpdateFoo = meta.events.find(event => event.name === 'update:foo');
3033

3134
const bar = meta.props.find(prop => prop.name === 'bar');
32-
const onUpdateBar = meta.events.find(event => event.name === 'update:bar');
35+
const barModifiers = meta.props.find(prop => prop.name === 'barModifiers');
36+
const onUpdateBaz = meta.events.find(event => event.name === 'update:bar');
3337

34-
const qux = meta.props.find(prop => prop.name === 'qux');
35-
const quxModifiers = meta.props.find(prop => prop.name === 'quxModifiers');
36-
const onUpdateQux = meta.events.find(event => event.name === 'update:qux');
38+
expect(modelValue).toBeDefined();
39+
expect(modelValue?.default).toBeUndefined();
40+
expect(modelValue?.required).toBeTruthy();
41+
expect(modelValue?.type).toEqual('number');
42+
expect(modelValue?.description).toEqual('required number modelValue');
43+
expect(modelValue?.schema).toEqual('number');
44+
expect(onUpdateModelValue).toBeDefined();
3745

3846
expect(foo).toBeDefined();
39-
expect(bar).toBeDefined();
40-
expect(qux).toBeDefined();
41-
expect(quxModifiers).toBeDefined();
47+
expect(foo?.default).toBe('false');
48+
expect(foo?.required).toBeFalsy();
49+
expect(foo?.type).toEqual('boolean | undefined');
50+
expect(foo?.description).toEqual('optional boolean foo with default false');
51+
expect(foo?.schema).toEqual({
52+
kind: 'enum',
53+
type: 'boolean | undefined',
54+
schema: ['undefined', 'false', 'true'],
55+
});
4256
expect(onUpdateFoo).toBeDefined();
43-
expect(onUpdateBar).toBeDefined();
44-
expect(onUpdateQux).toBeDefined();
57+
58+
expect(bar).toBeDefined();
59+
expect(bar?.default).toBeUndefined();
60+
expect(bar?.required).toBeFalsy();
61+
expect(bar?.type).toEqual('string | undefined');
62+
expect(bar?.description).toEqual('optional string bar with lazy and trim modifiers');
63+
expect(bar?.schema).toEqual({
64+
kind: 'enum',
65+
type: 'string | undefined',
66+
schema: ['undefined', 'string'],
67+
});
68+
// TODO: The types of modifiers are inconsistent in the two running results
69+
expect(barModifiers).toBeDefined();
70+
expect(onUpdateBaz).toBeDefined();
4571
});
4672

4773
test('reference-type-props', () => {

packages/component-type-helpers/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-component-type-helpers",
3-
"version": "2.2.4",
3+
"version": "2.2.8",
44
"license": "MIT",
55
"files": [
66
"**/*.js",

packages/language-core/lib/codegen/globalTypes.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ export function getGlobalTypesFileName({
1414
checkUnknownProps,
1515
checkUnknownEvents,
1616
checkUnknownComponents,
17-
].map(v => {
18-
if (typeof v === 'boolean') {
19-
return v ? 1 : 0;
20-
}
21-
return v;
22-
}).join('_') + '.d.ts';
17+
].map(v => (typeof v === 'boolean' ? Number(v) : v)).join('_') + '.d.ts';
2318
}
2419

2520
export function generateGlobalTypes({

packages/language-core/lib/codegen/script/component.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ export function* generateComponent(
3232
yield `},${newLine}`;
3333
if (!ctx.bypassDefineComponent) {
3434
const emitOptionCodes = [...generateEmitsOption(options, scriptSetupRanges)];
35-
for (const code of emitOptionCodes) {
36-
yield code;
37-
}
35+
yield* emitOptionCodes;
3836
yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, !!emitOptionCodes.length, true);
3937
}
4038
if (

packages/language-core/lib/codegen/script/componentSelf.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,19 @@ export function* generateComponentSelf(
3333
if (!templateUsageVars.has(varName) && !templateCodegenCtx.accessExternalVariables.has(varName)) {
3434
continue;
3535
}
36-
const templateOffset = options.getGeneratedLength();
37-
yield `${varName}: ${varName} as typeof `;
3836

39-
const scriptOffset = options.getGeneratedLength();
37+
const token = Symbol(varName.length);
38+
yield ['', undefined, 0, { __linkedToken: token }];
39+
yield `${varName}: ${varName} as typeof `;
40+
yield ['', undefined, 0, { __linkedToken: token }];
4041
yield `${varName},${newLine}`;
41-
42-
options.linkedCodeMappings.push({
43-
sourceOffsets: [scriptOffset],
44-
generatedOffsets: [templateOffset],
45-
lengths: [varName.length],
46-
data: undefined,
47-
});
4842
}
4943
}
5044
yield `}${endOfLine}`; // return {
5145
yield `},${newLine}`; // setup() {
5246
if (options.sfc.scriptSetup && options.scriptSetupRanges && !ctx.bypassDefineComponent) {
5347
const emitOptionCodes = [...generateEmitsOption(options, options.scriptSetupRanges)];
54-
for (const code of emitOptionCodes) {
55-
yield code;
56-
}
48+
yield* emitOptionCodes;
5749
yield* generatePropsOption(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges, !!emitOptionCodes.length, false);
5850
}
5951
if (options.sfc.script && options.scriptRanges?.exportDefault?.args) {

packages/language-core/lib/codegen/script/context.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export function createScriptCodegenContext(options: ScriptCodegenOptions) {
1818
return {
1919
generatedTemplate: false,
2020
generatedPropsType: false,
21-
scriptSetupGeneratedOffset: undefined as number | undefined,
2221
bypassDefineComponent: options.lang === 'js' || options.lang === 'jsx',
2322
bindingNames: new Set([
2423
...options.scriptRanges?.bindings.map(

0 commit comments

Comments
 (0)