@vue/language-service 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/language-blocks/zh-cn.json +6 -6
- package/data/model-modifiers/zh-cn.json +1 -1
- package/data/template/it.json +5 -5
- package/index.js +12 -8
- package/lib/ideFeatures/nameCasing.js +1 -1
- package/lib/plugins/utils.d.ts +3 -0
- package/lib/plugins/utils.js +14 -0
- package/lib/plugins/vue-autoinsert-dotvalue.d.ts +0 -9
- package/lib/plugins/vue-autoinsert-dotvalue.js +33 -50
- package/lib/plugins/vue-complete-define-assignment.js +3 -3
- package/lib/plugins/vue-document-drop.js +1 -1
- package/lib/plugins/vue-document-links.js +1 -1
- package/lib/plugins/vue-extract-file.d.ts +2 -1
- package/lib/plugins/vue-extract-file.js +10 -5
- package/lib/plugins/vue-inlayhints.d.ts +1 -1
- package/lib/plugins/vue-inlayhints.js +6 -6
- package/lib/plugins/vue-template.js +37 -47
- package/package.json +7 -7
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"name": "src",
|
|
9
9
|
"description": {
|
|
10
10
|
"kind": "markdown",
|
|
11
|
-
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```"
|
|
11
|
+
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```\n\n:::warning 注意\n在 `src` 中使用别名时,不要以 `~` 开头,后面的任何内容都会被解释为模块请求。这意味着你可以引用 node 模块中的资源:\n```vue\n<img src=\"~some-npm-package/foo.png\">\n```\n:::"
|
|
12
12
|
},
|
|
13
13
|
"references": "api/sfc-spec.html#src-imports"
|
|
14
14
|
},
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"name": "src",
|
|
43
43
|
"description": {
|
|
44
44
|
"kind": "markdown",
|
|
45
|
-
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```"
|
|
45
|
+
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```\n\n:::warning 注意\n在 `src` 中使用别名时,不要以 `~` 开头,后面的任何内容都会被解释为模块请求。这意味着你可以引用 node 模块中的资源:\n```vue\n<img src=\"~some-npm-package/foo.png\">\n```\n:::"
|
|
46
46
|
},
|
|
47
47
|
"references": "api/sfc-spec.html#src-imports"
|
|
48
48
|
},
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"name": "src",
|
|
104
104
|
"description": {
|
|
105
105
|
"kind": "markdown",
|
|
106
|
-
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```"
|
|
106
|
+
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```\n\n:::warning 注意\n在 `src` 中使用别名时,不要以 `~` 开头,后面的任何内容都会被解释为模块请求。这意味着你可以引用 node 模块中的资源:\n```vue\n<img src=\"~some-npm-package/foo.png\">\n```\n:::"
|
|
107
107
|
},
|
|
108
108
|
"references": "api/sfc-spec.html#src-imports"
|
|
109
109
|
},
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"valueSet": "v",
|
|
150
150
|
"description": {
|
|
151
151
|
"kind": "markdown",
|
|
152
|
-
"value": "一个 `<style module>` 标签会被编译为 [CSS Modules](https://github.com/css-modules/css-modules) 并且将生成的 CSS class 作为 `$style` 对象暴露给组件:\n\n```vue\n<template>\n <p :class=\"$style.red\">This should be red</p>\n</template>\n\n<style module>\n.red {\n color: red;\n}\n</style>\n```\n\n得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。\n\n参考 [CSS Modules spec](https://github.com/css-modules/css-modules) 以查看更多详情,例如 [global exceptions](https://github.com/css-modules/css-modules/blob/master/docs/composition.md#exceptions) 和 [composition](https://github.com/css-modules/css-modules/blob/master/docs/composition.md#composition)。\n\n### 自定义注入名称 \n\n你可以通过给 `module` attribute 一个值来自定义注入 class 对象的属性名:\n\n```vue\n<template>\n <p :class=\"classes.red\">red</p>\n</template>\n\n<style module=\"classes\">\n.red {\n color: red;\n}\n</style>\n```\n\n### 与组合式 API 一同使用 \n\n可以通过 `useCssModule` API 在 `setup()` 和 `<script setup>` 中访问注入的 class。对于使用了自定义注入名称的 `<style module>` 块,`useCssModule` 接收一个匹配的 `module` attribute 值作为第一个参数:\n\n```js\nimport { useCssModule } from 'vue'\n\n// 在 setup() 作用域中...\n// 默认情况下,返回 <style module> 的 class\nuseCssModule()\n\n// 具名情况下,返回 <style module=\"classes\"> 的 class\nuseCssModule('classes')\n```"
|
|
152
|
+
"value": "一个 `<style module>` 标签会被编译为 [CSS Modules](https://github.com/css-modules/css-modules) 并且将生成的 CSS class 作为 `$style` 对象暴露给组件:\n\n```vue\n<template>\n <p :class=\"$style.red\">This should be red</p>\n</template>\n\n<style module>\n.red {\n color: red;\n}\n</style>\n```\n\n得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。\n\n参考 [CSS Modules spec](https://github.com/css-modules/css-modules) 以查看更多详情,例如 [global exceptions](https://github.com/css-modules/css-modules/blob/master/docs/composition.md#exceptions) 和 [composition](https://github.com/css-modules/css-modules/blob/master/docs/composition.md#composition)。\n\n### 自定义注入名称 \n\n你可以通过给 `module` attribute 一个值来自定义注入 class 对象的属性名:\n\n```vue\n<template>\n <p :class=\"classes.red\">red</p>\n</template>\n\n<style module=\"classes\">\n.red {\n color: red;\n}\n</style>\n```\n\n### 与组合式 API 一同使用 \n\n可以通过 `useCssModule` API 在 `setup()` 和 `<script setup>` 中访问注入的 class。对于使用了自定义注入名称的 `<style module>` 块,`useCssModule` 接收一个匹配的 `module` attribute 值作为第一个参数:\n\n```js\nimport { useCssModule } from 'vue'\n\n// 在 setup() 作用域中...\n// 默认情况下,返回 <style module> 的 class\nuseCssModule()\n\n// 具名情况下,返回 <style module=\"classes\"> 的 class\nuseCssModule('classes')\n```\n\n- **示例**\n\n```vue\n<script setup lang=\"ts\">\nimport { useCssModule } from 'vue'\n\nconst classes = useCssModule()\n</script>\n\n<template>\n <p :class=\"classes.red\">red</p>\n</template>\n\n<style module>\n.red {\n color: red;\n}\n</style>\n```"
|
|
153
153
|
},
|
|
154
154
|
"references": "api/sfc-css-features.html#css-modules"
|
|
155
155
|
}
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
"name": "src",
|
|
168
168
|
"description": {
|
|
169
169
|
"kind": "markdown",
|
|
170
|
-
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```"
|
|
170
|
+
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```\n\n:::warning 注意\n在 `src` 中使用别名时,不要以 `~` 开头,后面的任何内容都会被解释为模块请求。这意味着你可以引用 node 模块中的资源:\n```vue\n<img src=\"~some-npm-package/foo.png\">\n```\n:::"
|
|
171
171
|
},
|
|
172
172
|
"references": "api/sfc-spec.html#src-imports"
|
|
173
173
|
}
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
"name": "src",
|
|
194
194
|
"description": {
|
|
195
195
|
"kind": "markdown",
|
|
196
|
-
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```"
|
|
196
|
+
"value": "如果你更喜欢将 `*.vue` 组件分散到多个文件中,可以为一个语块使用 `src` 这个 attribute 来导入一个外部文件:\n\n```vue\n<template src=\"./template.html\"></template>\n<style src=\"./style.css\"></style>\n<script src=\"./script.js\"></script>\n```\n\n请注意 `src` 导入和 JS 模块导入遵循相同的路径解析规则,这意味着:\n\n- 相对路径需要以 `./` 开头\n- 你也可以从 npm 依赖中导入资源\n\n```vue\n<!-- 从所安装的 \"todomvc-app-css\" npm 包中导入一个文件 -->\n<style src=\"todomvc-app-css/index.css\" />\n```\n\n`src` 导入对自定义语块也同样适用:\n\n```vue\n<unit-test src=\"./unit-test.js\">\n</unit-test>\n```\n\n:::warning 注意\n在 `src` 中使用别名时,不要以 `~` 开头,后面的任何内容都会被解释为模块请求。这意味着你可以引用 node 模块中的资源:\n```vue\n<img src=\"~some-npm-package/foo.png\">\n```\n:::"
|
|
197
197
|
},
|
|
198
198
|
"references": "api/sfc-spec.html#src-imports"
|
|
199
199
|
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"name": "number",
|
|
14
14
|
"description": {
|
|
15
15
|
"kind": "markdown",
|
|
16
|
-
"value": "如果你想让用户输入自动转换为数字,你可以在 `v-model` 后添加 `.number` 修饰符来管理输入:\n\n```html\n<input v-model.number=\"age\" />\n```\n\n如果该值无法被 `parseFloat()`
|
|
16
|
+
"value": "如果你想让用户输入自动转换为数字,你可以在 `v-model` 后添加 `.number` 修饰符来管理输入:\n\n```html\n<input v-model.number=\"age\" />\n```\n\n如果该值无法被 `parseFloat()` 处理,那么将返回原始值。特别是当输入为空时 (例如用户清空输入字段之后),会返回一个空字符串。这种行为与 [DOM 属性 valueAsNumber](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLInputElement#valueasnumber) 有所不同。\n\n`number` 修饰符会在输入框有 `type=\"number\"` 时自动启用。"
|
|
17
17
|
},
|
|
18
18
|
"references": "guide/essentials/forms.html#number"
|
|
19
19
|
},
|
package/data/template/it.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Transition",
|
|
6
6
|
"description": {
|
|
7
7
|
"kind": "markdown",
|
|
8
|
-
"value": "\
|
|
8
|
+
"value": "\nFornisce un'animazione di transizione a un **solo** elemento o componente.\n\n- **Props**\n\n ```ts\n interface TransitionProps {\n /**\n * Usato per generare automaticamente classi CSS per le transizioni.\n * Per esempio `name: 'fade'` verrà automaticamente espanso in `.fade-enter`,\n * `.fade-enter-active`, etc.\n */\n name?: string\n /**\n * Definisce se applicare le classi di transizione CSS.\n * Predefinito: true\n */\n css?: boolean\n /**\n * Specifica il tipo di evento di transizione da attendere\n * per determinare la tempistica della fine della transizione.\n * Il comportamento predefinito rileva automaticamente il tipo che ha\n * la durata maggiore.\n */\n type?: 'transition' | 'animation'\n /**\n * Specifica esplicitamente la durata della transizione.\n * Il comportamento predefinito è di attendere il primo evento\n * `transitionend` o `animationend` nel root dell'elemento transition.\n */\n duration?: number | { enter: number; leave: number }\n /**\n * Controlla la sequenza temporale delle transizioni di uscita/entrata.\n * Il comportamento predefinito è simultaneo\n */\n mode?: 'in-out' | 'out-in' | 'default'\n /**\n * Definisce se applicare la transizione al rendering iniziale.\n * Predefinito: false\n */\n appear?: boolean\n\n /**\n * Props per personalizzare le classi di transizione.\n * Usa il kebab-case nei template, per esempio enter-from-class=\"xxx\"\n */\n enterFromClass?: string\n enterActiveClass?: string\n enterToClass?: string\n appearFromClass?: string\n appearActiveClass?: string\n appearToClass?: string\n leaveFromClass?: string\n leaveActiveClass?: string\n leaveToClass?: string\n }\n ```\n\n- **Eventi**\n\n - `@before-enter`\n - `@before-leave`\n - `@enter`\n - `@leave`\n - `@appear`\n - `@after-enter`\n - `@after-leave`\n - `@after-appear`\n - `@enter-cancelled`\n - `@leave-cancelled` (solo `v-show`)\n - `@appear-cancelled`\n\n- **Esempio**\n\n Elemento semplice:\n\n ```html\n <Transition>\n <div v-if=\"ok\">contenuto attivato</div>\n </Transition>\n ```\n\n Forzare una transizione cambiando l'attributo `key`:\n\n ```html\n <Transition>\n <div :key=\"text\">{{ text }}</div>\n </Transition>\n ```\n\n Componente dinamico, con modalità di transizione + animazione in entrata:\n\n ```html\n <Transition name=\"fade\" mode=\"out-in\" appear>\n <component :is=\"view\"></component>\n </Transition>\n ```\n\n Ascolto eventi transizione:\n\n ```html\n <Transition @after-enter=\"onTransitionComplete\">\n <div v-show=\"ok\">toggled content</div>\n </Transition>\n ```\n\n- **Vedi anche** [Guida `<Transition>`](https://it.vuejs.org/guide/built-ins/transition.html)\n"
|
|
9
9
|
},
|
|
10
10
|
"attributes": [],
|
|
11
11
|
"references": "api/built-in-components.html#transition"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"name": "TransitionGroup",
|
|
15
15
|
"description": {
|
|
16
16
|
"kind": "markdown",
|
|
17
|
-
"value": "\
|
|
17
|
+
"value": "\nFornisce effetti di transizione per elementi **multipli** o componenti in un elenco.\n\n- **Props**\n\n `<TransitionGroup>` accetta le stesse props di `<Transition>` tranne `mode`, più due prop aggiuntive:\n\n ```ts\n interface TransitionGroupProps extends Omit<TransitionProps, 'mode'> {\n /**\n * Se non definito, renderizza come un fragment\n */\n tag?: string\n /**\n * Per personalizzare la classe CSS applicata durante la transizione.\n * Usa il kebab-case nel template, per esempio move-class=\"xxx\"\n */\n moveClass?: string\n }\n ```\n\n- **Eventi**\n\n `<TransitionGroup>` emette gli stessi eventi di `<Transition>`.\n\n- **Dettagli**\n\n Di default, `<TransitionGroup>` non renderizza un elemento DOM wrapper, ma uno può essere definito attraverso la prop `tag`.\n\n Nota che ogni figlio in `<transition-group>` deve avere una [**chiave univoca**](https://it.vuejs.org/guide/essentials/list.html#maintaining-state-with-key) per l'animazione per funzionare correttamente.\n\n `<TransitionGroup>` supporta le transizioni tramite trasformazione CSS. Quando la posizione di un figlio nello schermo cambia dopo un aggiornamento, gli verrà applicata una classe CSS di movimento (generata automaticamente dall'attributo `name` o configurato con la prop `move-class`). Se la proprietà CSS `transform` è \"transition-able\" quando la classe di movimento è applicata, l'elemento verrà animato fluidamente alla sua destinazione usando la [tecnica FLIP](https://aerotwist.com/blog/flip-your-animations/).\n\n- **Esempio**\n\n ```html\n <TransitionGroup tag=\"ul\" name=\"slide\">\n <li v-for=\"item in items\" :key=\"item.id\">\n {{ item.text }}\n </li>\n </TransitionGroup>\n ```\n\n- **Vedi anche** [Guida - TransitionGroup](https://it.vuejs.org/guide/built-ins/transition-group.html)\n"
|
|
18
18
|
},
|
|
19
19
|
"attributes": [],
|
|
20
20
|
"references": "api/built-in-components.html#transitiongroup"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"name": "KeepAlive",
|
|
24
24
|
"description": {
|
|
25
25
|
"kind": "markdown",
|
|
26
|
-
"value": "\
|
|
26
|
+
"value": "\nMemorizza nella cache i componenti attivati/disattivati dinamicamente racchiusi all'interno.\n\n- **Props**\n\n ```ts\n interface KeepAliveProps {\n /**\n * Se specificata, solo i componenti con gli stessi nomi corrispondenti a \n * `include` saranno memorizzati nella cache.\n */\n include?: MatchPattern\n /**\n * Qualsiasi componente con un nome corrispondente a `exclude`\n * non verrà memorizzato nella cache.\n */\n exclude?: MatchPattern\n /**\n * Il numero massimo di istanze del componente da memorizzare nella cache.\n */\n max?: number | string\n }\n\n type MatchPattern = string | RegExp | (string | RegExp)[]\n ```\n\n- **Dettagli**\n\n Quando racchiuso in un componente dinamico, `<KeepAlive>` memorizza nella cache le istanze dei componenti inattivi senza distruggerle.\n\n Ci può essere solo un'istanza di un componente come figlio diretto di `<KeepAlive>` in qualsiasi momento.\n\n Quando un componente è azionato dentro `<KeepAlive>`, i suoi lifecycle hooks `activated` e `deactivated` verranno richiamati di conseguenza, offrendo un alternativa a `mounted` e `unmounted`, che non sono chiamati. Questo si applica ai figli diretti di `<KeepAlive>` e anche a tutti i suoi discendenti.\n\n- **Esempio**\n\n Utilizzo Base:\n\n ```html\n <KeepAlive>\n <component :is=\"view\"></component>\n </KeepAlive>\n ```\n Quando usato con `v-if` / `v-else`, ci deve essere solo un componente renderizzato alla volta:\n\n ```html\n <KeepAlive>\n <comp-a v-if=\"a > 1\"></comp-a>\n <comp-b v-else></comp-b>\n </KeepAlive>\n ```\n Usato insieme a `<Transition>`:\n\n ```html\n <Transition>\n <KeepAlive>\n <component :is=\"view\"></component>\n </KeepAlive>\n </Transition>\n ```\n Usando `include` / `exclude`: \n\n ```html\n <!-- stringa con delimitatore virgola -->\n <KeepAlive include=\"a,b\">\n <component :is=\"view\"></component>\n </KeepAlive>\n\n <!-- regex (usando `v-bind`) -->\n <KeepAlive :include=\"/a|b/\">\n <component :is=\"view\"></component>\n </KeepAlive>\n\n <!-- Array (usando `v-bind`) -->\n <KeepAlive :include=\"['a', 'b']\">\n <component :is=\"view\"></component>\n </KeepAlive>\n ```\n Utilizzo con `max`:\n\n ```html\n <KeepAlive :max=\"10\">\n <component :is=\"view\"></component>\n </KeepAlive>\n ```\n\n- **Vedi anche** [Guida - KeepAlive](https://it.vuejs.org/guide/built-ins/keep-alive.html)\n"
|
|
27
27
|
},
|
|
28
28
|
"attributes": [],
|
|
29
29
|
"references": "api/built-in-components.html#keepalive"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"name": "Teleport",
|
|
33
33
|
"description": {
|
|
34
34
|
"kind": "markdown",
|
|
35
|
-
"value": "\
|
|
35
|
+
"value": "\nRenderizza il contenuto dello slot in un' altra parte del DOM.\n\n- **Props**\n\n ```ts\n interface TeleportProps {\n /**\n * Obbligatoria. Specifica il container di destinazione.\n * Può essere sia un selettore o un elemento reale.\n */\n to: string | HTMLElement\n /**\n * Quando `true`, il contenuto resterà nella posizione\n * originale invece di essere spostato nel container di destinazione.\n * Può essere cambiato dinamicamente.\n */\n disabled?: boolean\n }\n ```\n\n- **Esempio**\n\n Specificando un container di destinazione\n\n ```html\n <teleport to=\"#some-id\" />\n <teleport to=\".some-class\" />\n <teleport to=\"[data-teleport]\" />\n ```\n Disabilitazione condizionale:\n\n ```html\n <teleport to=\"#popup\" :disabled=\"displayVideoInline\">\n <video src=\"./my-movie.mp4\">\n </teleport>\n ```\n\n- **Vedi anche** [Guida - Teleport](https://it.vuejs.org/guide/built-ins/teleport.html)\n"
|
|
36
36
|
},
|
|
37
37
|
"attributes": [],
|
|
38
38
|
"references": "api/built-in-components.html#teleport"
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"name": "Suspense",
|
|
42
42
|
"description": {
|
|
43
43
|
"kind": "markdown",
|
|
44
|
-
"value": "\
|
|
44
|
+
"value": "\nUsato per orchestrare dipendenze asincrone annidate in un albero di componenti.\n\n- **Props**\n\n ```ts\n interface SuspenseProps {\n timeout?: string | number\n }\n ```\n\n- **Eventi**\n\n - `@resolve`\n - `@pending`\n - `@fallback`\n\n- **Dettagli**\n\n `<Suspense>` accetta due slots: lo slot di `#default` e lo slot `#fallback`. Mostrerà il contenuto dello slot di fallback mentre renderizza lo slot default in memoria.\n\n Se incontra dipendenze asincrone ([Componente asincrono](https://it.vuejs.org/guide/components/async.html) e componenti con [`async setup()`](https://it.vuejs.org/guide/built-ins/suspense.html#async-setup)) mentre renderizza lo slot di default, aspetterà fino a quando tutti sono risolti prima di visualizzare lo slot di default.\n\n- **Vedi anche** [Guida - Suspense](https://it.vuejs.org/guide/built-ins/suspense.html)\n"
|
|
45
45
|
},
|
|
46
46
|
"attributes": [],
|
|
47
47
|
"references": "api/built-in-components.html#suspense"
|
package/index.js
CHANGED
|
@@ -44,7 +44,11 @@ const vue_twoslash_queries_1 = require("./lib/plugins/vue-twoslash-queries");
|
|
|
44
44
|
const language_core_1 = require("@vue/language-core");
|
|
45
45
|
const common_1 = require("@vue/typescript-plugin/lib/common");
|
|
46
46
|
const collectExtractProps_1 = require("@vue/typescript-plugin/lib/requests/collectExtractProps");
|
|
47
|
-
const
|
|
47
|
+
const getComponentDirectives_1 = require("@vue/typescript-plugin/lib/requests/getComponentDirectives");
|
|
48
|
+
const getComponentEvents_1 = require("@vue/typescript-plugin/lib/requests/getComponentEvents");
|
|
49
|
+
const getComponentNames_1 = require("@vue/typescript-plugin/lib/requests/getComponentNames");
|
|
50
|
+
const getComponentProps_1 = require("@vue/typescript-plugin/lib/requests/getComponentProps");
|
|
51
|
+
const getElementAttrs_1 = require("@vue/typescript-plugin/lib/requests/getElementAttrs");
|
|
48
52
|
const getImportPathForFile_1 = require("@vue/typescript-plugin/lib/requests/getImportPathForFile");
|
|
49
53
|
const getPropertiesAtLocation_1 = require("@vue/typescript-plugin/lib/requests/getPropertiesAtLocation");
|
|
50
54
|
const vscode_uri_1 = require("vscode-uri");
|
|
@@ -106,19 +110,19 @@ function getFullLanguageServicePlugins(ts, { disableAutoImportCache } = {}) {
|
|
|
106
110
|
return await getImportPathForFile_1.getImportPathForFile.apply(requestContext, args);
|
|
107
111
|
},
|
|
108
112
|
async getComponentEvents(...args) {
|
|
109
|
-
return await
|
|
113
|
+
return await getComponentEvents_1.getComponentEvents.apply(requestContext, args);
|
|
114
|
+
},
|
|
115
|
+
async getComponentDirectives(...args) {
|
|
116
|
+
return await getComponentDirectives_1.getComponentDirectives.apply(requestContext, args);
|
|
110
117
|
},
|
|
111
118
|
async getComponentNames(...args) {
|
|
112
|
-
return await
|
|
119
|
+
return await getComponentNames_1.getComponentNames.apply(requestContext, args);
|
|
113
120
|
},
|
|
114
121
|
async getComponentProps(...args) {
|
|
115
|
-
return await
|
|
122
|
+
return await getComponentProps_1.getComponentProps.apply(requestContext, args);
|
|
116
123
|
},
|
|
117
124
|
async getElementAttrs(...args) {
|
|
118
|
-
return await
|
|
119
|
-
},
|
|
120
|
-
async getTemplateContextProps(...args) {
|
|
121
|
-
return await componentInfos_1.getTemplateContextProps.apply(requestContext, args);
|
|
125
|
+
return await getElementAttrs_1.getElementAttrs.apply(requestContext, args);
|
|
122
126
|
},
|
|
123
127
|
async getQuickInfoAtPosition(fileName, position) {
|
|
124
128
|
const languageService = context.getLanguageService();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sleep = sleep;
|
|
4
|
+
exports.isTsDocument = isTsDocument;
|
|
5
|
+
function sleep(ms) {
|
|
6
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
7
|
+
}
|
|
8
|
+
function isTsDocument(document) {
|
|
9
|
+
return document.languageId === 'javascript' ||
|
|
10
|
+
document.languageId === 'typescript' ||
|
|
11
|
+
document.languageId === 'javascriptreact' ||
|
|
12
|
+
document.languageId === 'typescriptreact';
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -1,11 +1,2 @@
|
|
|
1
1
|
import type { LanguageServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
-
import type * as ts from 'typescript';
|
|
3
|
-
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
4
2
|
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined): LanguageServicePlugin;
|
|
5
|
-
export declare function isTsDocument(document: TextDocument): boolean;
|
|
6
|
-
export declare function isCharacterTyping(document: TextDocument, change: {
|
|
7
|
-
text: string;
|
|
8
|
-
rangeOffset: number;
|
|
9
|
-
rangeLength: number;
|
|
10
|
-
}): boolean;
|
|
11
|
-
export declare function isBlacklistNode(ts: typeof import('typescript'), node: ts.Node, pos: number, allowAccessDotValue: boolean): boolean;
|
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.create = create;
|
|
4
|
-
exports.isTsDocument = isTsDocument;
|
|
5
|
-
exports.isCharacterTyping = isCharacterTyping;
|
|
6
|
-
exports.isBlacklistNode = isBlacklistNode;
|
|
7
4
|
const language_core_1 = require("@vue/language-core");
|
|
8
5
|
const vscode_uri_1 = require("vscode-uri");
|
|
9
|
-
const
|
|
10
|
-
function getAst(ts, fileName, snapshot, scriptKind) {
|
|
11
|
-
let ast = asts.get(snapshot);
|
|
12
|
-
if (!ast) {
|
|
13
|
-
ast = ts.createSourceFile(fileName, snapshot.getText(0, snapshot.getLength()), ts.ScriptTarget.Latest, undefined, scriptKind);
|
|
14
|
-
asts.set(snapshot, ast);
|
|
15
|
-
}
|
|
16
|
-
return ast;
|
|
17
|
-
}
|
|
6
|
+
const utils_1 = require("./utils");
|
|
18
7
|
function create(ts, getTsPluginClient) {
|
|
19
8
|
return {
|
|
20
9
|
name: 'vue-autoinsert-dotvalue',
|
|
@@ -33,7 +22,7 @@ function create(ts, getTsPluginClient) {
|
|
|
33
22
|
if (document.offsetAt(selection) !== change.rangeOffset + change.text.length) {
|
|
34
23
|
return;
|
|
35
24
|
}
|
|
36
|
-
if (!isTsDocument(document)) {
|
|
25
|
+
if (!(0, utils_1.isTsDocument)(document)) {
|
|
37
26
|
return;
|
|
38
27
|
}
|
|
39
28
|
if (!isCharacterTyping(document, change)) {
|
|
@@ -41,7 +30,7 @@ function create(ts, getTsPluginClient) {
|
|
|
41
30
|
}
|
|
42
31
|
const req = ++currentReq;
|
|
43
32
|
// Wait for tsserver to sync
|
|
44
|
-
await sleep(250);
|
|
33
|
+
await (0, utils_1.sleep)(250);
|
|
45
34
|
if (req !== currentReq) {
|
|
46
35
|
return;
|
|
47
36
|
}
|
|
@@ -53,41 +42,44 @@ function create(ts, getTsPluginClient) {
|
|
|
53
42
|
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
54
43
|
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
|
|
55
44
|
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
|
|
56
|
-
if (!sourceScript) {
|
|
45
|
+
if (!sourceScript?.generated || !virtualCode) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const root = sourceScript.generated.root;
|
|
49
|
+
if (!(root instanceof language_core_1.VueVirtualCode)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const blocks = [
|
|
53
|
+
root._sfc.script,
|
|
54
|
+
root._sfc.scriptSetup,
|
|
55
|
+
].filter(block => !!block);
|
|
56
|
+
if (!blocks.length) {
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
|
-
let ast;
|
|
60
59
|
let sourceCodeOffset = document.offsetAt(selection);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
ast = getAst(ts, fileName, virtualCode.snapshot, serviceScript.scriptKind);
|
|
69
|
-
let mapped = false;
|
|
70
|
-
for (const [_sourceScript, map] of context.language.maps.forEach(virtualCode)) {
|
|
71
|
-
for (const [sourceOffset] of map.toSourceLocation(document.offsetAt(selection))) {
|
|
72
|
-
sourceCodeOffset = sourceOffset;
|
|
73
|
-
mapped = true;
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
if (mapped) {
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
60
|
+
let mapped = false;
|
|
61
|
+
for (const [, map] of context.language.maps.forEach(virtualCode)) {
|
|
62
|
+
for (const [sourceOffset] of map.toSourceLocation(sourceCodeOffset)) {
|
|
63
|
+
sourceCodeOffset = sourceOffset;
|
|
64
|
+
mapped = true;
|
|
65
|
+
break;
|
|
79
66
|
}
|
|
80
|
-
if (
|
|
81
|
-
|
|
67
|
+
if (mapped) {
|
|
68
|
+
break;
|
|
82
69
|
}
|
|
83
70
|
}
|
|
84
|
-
|
|
85
|
-
ast = getAst(ts, fileName, sourceScript.snapshot);
|
|
86
|
-
}
|
|
87
|
-
if (isBlacklistNode(ts, ast, document.offsetAt(selection), false)) {
|
|
71
|
+
if (!mapped) {
|
|
88
72
|
return;
|
|
89
73
|
}
|
|
90
|
-
const
|
|
74
|
+
for (const { ast, startTagEnd, endTagStart } of blocks) {
|
|
75
|
+
if (sourceCodeOffset < startTagEnd || sourceCodeOffset > endTagStart) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (isBlacklistNode(ts, ast, sourceCodeOffset - startTagEnd, false)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const props = await tsPluginClient?.getPropertiesAtLocation(root.fileName, sourceCodeOffset) ?? [];
|
|
91
83
|
if (props.some(prop => prop === 'value')) {
|
|
92
84
|
return '${1:.value}';
|
|
93
85
|
}
|
|
@@ -96,15 +88,6 @@ function create(ts, getTsPluginClient) {
|
|
|
96
88
|
},
|
|
97
89
|
};
|
|
98
90
|
}
|
|
99
|
-
function sleep(ms) {
|
|
100
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
101
|
-
}
|
|
102
|
-
function isTsDocument(document) {
|
|
103
|
-
return document.languageId === 'javascript' ||
|
|
104
|
-
document.languageId === 'typescript' ||
|
|
105
|
-
document.languageId === 'javascriptreact' ||
|
|
106
|
-
document.languageId === 'typescriptreact';
|
|
107
|
-
}
|
|
108
91
|
const charReg = /\w/;
|
|
109
92
|
function isCharacterTyping(document, change) {
|
|
110
93
|
const lastCharacter = change.text[change.text.length - 1];
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.create = create;
|
|
4
4
|
const language_core_1 = require("@vue/language-core");
|
|
5
5
|
const vscode_uri_1 = require("vscode-uri");
|
|
6
|
-
const
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
7
|
function create() {
|
|
8
8
|
return {
|
|
9
9
|
name: 'vue-complete-define-assignment',
|
|
@@ -14,7 +14,7 @@ function create() {
|
|
|
14
14
|
return {
|
|
15
15
|
isAdditionalCompletion: true,
|
|
16
16
|
async provideCompletionItems(document) {
|
|
17
|
-
if (!(0,
|
|
17
|
+
if (!(0, utils_1.isTsDocument)(document)) {
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
const enabled = await context.env.getConfiguration?.('vue.complete.defineAssignment') ?? true;
|
|
@@ -34,7 +34,7 @@ function create() {
|
|
|
34
34
|
}
|
|
35
35
|
const codegen = language_core_1.tsCodegen.get(root._sfc);
|
|
36
36
|
const scriptSetup = root._sfc.scriptSetup;
|
|
37
|
-
const scriptSetupRanges = codegen?.
|
|
37
|
+
const scriptSetupRanges = codegen?.getScriptSetupRanges();
|
|
38
38
|
if (!scriptSetup || !scriptSetupRanges) {
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
@@ -91,7 +91,7 @@ function create(ts, getTsPluginClient) {
|
|
|
91
91
|
+ (lastImportNode ? '' : '\n'),
|
|
92
92
|
});
|
|
93
93
|
if (sfc.script) {
|
|
94
|
-
const edit = (0, vue_extract_file_1.createAddComponentToOptionEdit)(ts, sfc.script.ast, newName);
|
|
94
|
+
const edit = (0, vue_extract_file_1.createAddComponentToOptionEdit)(ts, sfc, sfc.script.ast, newName);
|
|
95
95
|
if (edit) {
|
|
96
96
|
additionalEdit.changes[embeddedDocumentUriStr].push({
|
|
97
97
|
range: {
|
|
@@ -25,7 +25,7 @@ function create() {
|
|
|
25
25
|
}
|
|
26
26
|
const result = [];
|
|
27
27
|
const codegen = language_core_1.tsCodegen.get(root._sfc);
|
|
28
|
-
const scopedClasses = codegen?.
|
|
28
|
+
const scopedClasses = codegen?.getGeneratedTemplate()?.scopedClasses ?? [];
|
|
29
29
|
const styleClasses = new Map();
|
|
30
30
|
const option = root.vueCompilerOptions.experimentalResolveStyleCssClasses;
|
|
31
31
|
for (let i = 0; i < root._sfc.styles.length; i++) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { LanguageServiceContext, LanguageServicePlugin } from '@volar/language-service';
|
|
2
|
+
import { Sfc } from '@vue/language-core';
|
|
2
3
|
import type * as ts from 'typescript';
|
|
3
4
|
export declare function create(ts: typeof import('typescript'), getTsPluginClient?: (context: LanguageServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined): LanguageServicePlugin;
|
|
4
5
|
export declare function getLastImportNode(ts: typeof import('typescript'), sourceFile: ts.SourceFile): ts.Node | undefined;
|
|
5
|
-
export declare function createAddComponentToOptionEdit(ts: typeof import('typescript'), ast: ts.SourceFile, componentName: string): {
|
|
6
|
+
export declare function createAddComponentToOptionEdit(ts: typeof import('typescript'), sfc: Sfc, ast: ts.SourceFile, componentName: string): {
|
|
6
7
|
range: import("@vue/language-core").TextRange;
|
|
7
8
|
newText: string;
|
|
8
9
|
} | undefined;
|
|
@@ -11,13 +11,17 @@ function create(ts, getTsPluginClient) {
|
|
|
11
11
|
name: 'vue-extract-file',
|
|
12
12
|
capabilities: {
|
|
13
13
|
codeActionProvider: {
|
|
14
|
+
codeActionKinds: ['refactor'],
|
|
14
15
|
resolveProvider: true,
|
|
15
16
|
},
|
|
16
17
|
},
|
|
17
18
|
create(context) {
|
|
18
19
|
const tsPluginClient = getTsPluginClient?.(context);
|
|
19
20
|
return {
|
|
20
|
-
provideCodeActions(document, range,
|
|
21
|
+
provideCodeActions(document, range, ctx) {
|
|
22
|
+
if (ctx.only && !ctx.only.includes('refactor')) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
21
25
|
const startOffset = document.offsetAt(range.start);
|
|
22
26
|
const endOffset = document.offsetAt(range.end);
|
|
23
27
|
if (startOffset === endOffset) {
|
|
@@ -118,7 +122,7 @@ function create(ts, getTsPluginClient) {
|
|
|
118
122
|
},
|
|
119
123
|
];
|
|
120
124
|
if (sfc.script) {
|
|
121
|
-
const edit = createAddComponentToOptionEdit(ts, sfc.script.ast, newName);
|
|
125
|
+
const edit = createAddComponentToOptionEdit(ts, sfc, sfc.script.ast, newName);
|
|
122
126
|
if (edit) {
|
|
123
127
|
sfcEdits.push({
|
|
124
128
|
range: {
|
|
@@ -247,11 +251,12 @@ function getLastImportNode(ts, sourceFile) {
|
|
|
247
251
|
}
|
|
248
252
|
return lastImportNode;
|
|
249
253
|
}
|
|
250
|
-
function createAddComponentToOptionEdit(ts, ast, componentName) {
|
|
251
|
-
const
|
|
252
|
-
if (!exportDefault) {
|
|
254
|
+
function createAddComponentToOptionEdit(ts, sfc, ast, componentName) {
|
|
255
|
+
const scriptRanges = language_core_1.tsCodegen.get(sfc)?.getScriptRanges();
|
|
256
|
+
if (!scriptRanges?.exportDefault) {
|
|
253
257
|
return;
|
|
254
258
|
}
|
|
259
|
+
const { exportDefault } = scriptRanges;
|
|
255
260
|
// https://github.com/microsoft/TypeScript/issues/36174
|
|
256
261
|
const printer = ts.createPrinter();
|
|
257
262
|
if (exportDefault.componentsOption && exportDefault.componentsOptionNode) {
|
|
@@ -4,4 +4,4 @@ export declare function create(ts: typeof import('typescript')): LanguageService
|
|
|
4
4
|
/**
|
|
5
5
|
* Refactored from https://github.com/vuejs/core/blob/main/packages/compiler-sfc/src/script/definePropsDestructure.ts
|
|
6
6
|
*/
|
|
7
|
-
export declare function findDestructuredProps(ts: typeof import('typescript'), ast: ts.SourceFile, props:
|
|
7
|
+
export declare function findDestructuredProps(ts: typeof import('typescript'), ast: ts.SourceFile, props: MapIterator<string>): [ts.Identifier, boolean][];
|
|
@@ -28,15 +28,15 @@ function create(ts) {
|
|
|
28
28
|
const result = [];
|
|
29
29
|
const codegen = language_core_1.tsCodegen.get(virtualCode._sfc);
|
|
30
30
|
const inlayHints = [
|
|
31
|
-
...codegen?.
|
|
32
|
-
...codegen?.
|
|
31
|
+
...codegen?.getGeneratedTemplate()?.inlayHints ?? [],
|
|
32
|
+
...codegen?.getGeneratedScript()?.inlayHints ?? [],
|
|
33
33
|
];
|
|
34
|
-
const scriptSetupRanges = codegen?.
|
|
34
|
+
const scriptSetupRanges = codegen?.getScriptSetupRanges();
|
|
35
35
|
if (scriptSetupRanges?.defineProps?.destructured && virtualCode._sfc.scriptSetup?.ast) {
|
|
36
36
|
const setting = 'vue.inlayHints.destructuredProps';
|
|
37
37
|
const enabled = await getSettingEnabled(setting);
|
|
38
38
|
if (enabled) {
|
|
39
|
-
for (const [prop, isShorthand] of findDestructuredProps(ts, virtualCode._sfc.scriptSetup.ast, scriptSetupRanges.defineProps.destructured)) {
|
|
39
|
+
for (const [prop, isShorthand] of findDestructuredProps(ts, virtualCode._sfc.scriptSetup.ast, scriptSetupRanges.defineProps.destructured.keys())) {
|
|
40
40
|
const name = prop.text;
|
|
41
41
|
const end = prop.getEnd();
|
|
42
42
|
const pos = isShorthand ? end : end - name.length;
|
|
@@ -148,7 +148,7 @@ function findDestructuredProps(ts, ast, props) {
|
|
|
148
148
|
&& initializer
|
|
149
149
|
&& ts.isCallExpression(initializer)
|
|
150
150
|
&& initializer.expression.getText(ast) === 'defineProps';
|
|
151
|
-
for (const
|
|
151
|
+
for (const { id } of (0, index_1.collectIdentifiers)(ts, name)) {
|
|
152
152
|
if (isDefineProps) {
|
|
153
153
|
excludedIds.add(id);
|
|
154
154
|
}
|
|
@@ -163,7 +163,7 @@ function findDestructuredProps(ts, ast, props) {
|
|
|
163
163
|
registerLocalBinding(name);
|
|
164
164
|
}
|
|
165
165
|
for (const p of parameters) {
|
|
166
|
-
for (const
|
|
166
|
+
for (const { id } of (0, index_1.collectIdentifiers)(ts, p)) {
|
|
167
167
|
registerLocalBinding(id);
|
|
168
168
|
}
|
|
169
169
|
}
|
|
@@ -30,7 +30,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
30
30
|
let customData = [];
|
|
31
31
|
let extraCustomData = [];
|
|
32
32
|
let lastCompletionComponentNames = new Set();
|
|
33
|
-
const
|
|
33
|
+
const cachedPropInfos = new Map();
|
|
34
34
|
const onDidChangeCustomDataListeners = new Set();
|
|
35
35
|
const onDidChangeCustomData = (listener) => {
|
|
36
36
|
onDidChangeCustomDataListeners.add(listener);
|
|
@@ -131,7 +131,6 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
131
131
|
if (!context.project.vue) {
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
|
-
const vueCompilerOptions = context.project.vue.compilerOptions;
|
|
135
134
|
let sync;
|
|
136
135
|
let currentVersion;
|
|
137
136
|
const uri = vscode_uri_1.URI.parse(document.uri);
|
|
@@ -141,7 +140,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
141
140
|
if (root instanceof language_core_1.VueVirtualCode) {
|
|
142
141
|
// #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver
|
|
143
142
|
baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
144
|
-
sync = (await provideHtmlData(
|
|
143
|
+
sync = (await provideHtmlData(sourceScript.id, root)).sync;
|
|
145
144
|
currentVersion = await sync();
|
|
146
145
|
}
|
|
147
146
|
let htmlComplete = await baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token);
|
|
@@ -378,7 +377,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
378
377
|
});
|
|
379
378
|
},
|
|
380
379
|
};
|
|
381
|
-
async function provideHtmlData(
|
|
380
|
+
async function provideHtmlData(sourceDocumentUri, vueCode) {
|
|
382
381
|
await (initializing ??= initialize());
|
|
383
382
|
const casing = await (0, nameCasing_1.getNameCasing)(context, sourceDocumentUri);
|
|
384
383
|
if (builtInData.tags) {
|
|
@@ -401,8 +400,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
401
400
|
const tagInfos = new Map();
|
|
402
401
|
let version = 0;
|
|
403
402
|
let components;
|
|
404
|
-
|
|
405
|
-
tsDocumentations.clear();
|
|
403
|
+
cachedPropInfos.clear();
|
|
406
404
|
updateExtraCustomData([
|
|
407
405
|
html.newHTMLDataProvider('vue-template-built-in', builtInData),
|
|
408
406
|
{
|
|
@@ -422,9 +420,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
422
420
|
})());
|
|
423
421
|
return [];
|
|
424
422
|
}
|
|
425
|
-
const scriptSetupRanges = vueCode._sfc
|
|
426
|
-
? (0, language_core_1.parseScriptSetupRanges)(ts, vueCode._sfc.scriptSetup.ast, vueCompilerOptions)
|
|
427
|
-
: undefined;
|
|
423
|
+
const scriptSetupRanges = language_core_1.tsCodegen.get(vueCode._sfc)?.getScriptSetupRanges();
|
|
428
424
|
const names = new Set();
|
|
429
425
|
const tags = [];
|
|
430
426
|
for (const tag of components) {
|
|
@@ -457,44 +453,24 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
457
453
|
if (!tagInfo) {
|
|
458
454
|
promises.push((async () => {
|
|
459
455
|
const attrs = await tsPluginClient?.getElementAttrs(vueCode.fileName, tag) ?? [];
|
|
460
|
-
const
|
|
456
|
+
const propInfos = await tsPluginClient?.getComponentProps(vueCode.fileName, tag) ?? [];
|
|
461
457
|
const events = await tsPluginClient?.getComponentEvents(vueCode.fileName, tag) ?? [];
|
|
458
|
+
const directives = await tsPluginClient?.getComponentDirectives(vueCode.fileName) ?? [];
|
|
462
459
|
tagInfos.set(tag, {
|
|
463
460
|
attrs,
|
|
464
|
-
|
|
461
|
+
propInfos: propInfos.filter(prop => !prop.name.startsWith('ref_')),
|
|
465
462
|
events,
|
|
463
|
+
directives,
|
|
466
464
|
});
|
|
467
465
|
version++;
|
|
468
466
|
})());
|
|
469
467
|
return [];
|
|
470
468
|
}
|
|
471
|
-
const { attrs,
|
|
472
|
-
const props =
|
|
469
|
+
const { attrs, propInfos, events, directives } = tagInfo;
|
|
470
|
+
const props = propInfos.map(prop => (0, language_core_1.hyphenateTag)(prop.name).startsWith('on-vnode-')
|
|
473
471
|
? 'onVue:' + prop.name.slice('onVnode'.length)
|
|
474
472
|
: prop.name);
|
|
475
473
|
const attributes = [];
|
|
476
|
-
const _tsCodegen = language_core_1.tsCodegen.get(vueCode._sfc);
|
|
477
|
-
if (_tsCodegen) {
|
|
478
|
-
if (!templateContextProps) {
|
|
479
|
-
promises.push((async () => {
|
|
480
|
-
templateContextProps = await tsPluginClient?.getTemplateContextProps(vueCode.fileName) ?? [];
|
|
481
|
-
version++;
|
|
482
|
-
})());
|
|
483
|
-
return [];
|
|
484
|
-
}
|
|
485
|
-
let ctxVars = [
|
|
486
|
-
..._tsCodegen.scriptRanges.get()?.bindings.map(({ range }) => vueCode._sfc.script.content.slice(range.start, range.end)) ?? [],
|
|
487
|
-
..._tsCodegen.scriptSetupRanges.get()?.bindings.map(({ range }) => vueCode._sfc.scriptSetup.content.slice(range.start, range.end)) ?? [],
|
|
488
|
-
...templateContextProps,
|
|
489
|
-
];
|
|
490
|
-
ctxVars = [...new Set(ctxVars)];
|
|
491
|
-
const dirs = ctxVars.map(language_core_1.hyphenateAttr).filter(v => v.startsWith('v-'));
|
|
492
|
-
for (const dir of dirs) {
|
|
493
|
-
attributes.push({
|
|
494
|
-
name: dir,
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
474
|
const propsSet = new Set(props);
|
|
499
475
|
for (const prop of [...props, ...attrs]) {
|
|
500
476
|
const isGlobal = !propsSet.has(prop);
|
|
@@ -515,13 +491,13 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
515
491
|
}
|
|
516
492
|
else {
|
|
517
493
|
const propName = name;
|
|
518
|
-
const
|
|
519
|
-
const propDescription = propsInfo.find(prop => {
|
|
494
|
+
const propInfo = propInfos.find(prop => {
|
|
520
495
|
const name = casing.attr === types_1.AttrNameCasing.Camel ? prop.name : (0, language_core_1.hyphenateAttr)(prop.name);
|
|
521
496
|
return name === propName;
|
|
522
|
-
})
|
|
523
|
-
|
|
524
|
-
|
|
497
|
+
});
|
|
498
|
+
const propKey = generateItemKey('componentProp', isGlobal ? '*' : tag, propName, propInfo?.deprecated);
|
|
499
|
+
if (propInfo) {
|
|
500
|
+
cachedPropInfos.set(propName, propInfo);
|
|
525
501
|
}
|
|
526
502
|
attributes.push({
|
|
527
503
|
name: propName,
|
|
@@ -546,6 +522,12 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
546
522
|
description: propKey,
|
|
547
523
|
});
|
|
548
524
|
}
|
|
525
|
+
for (const directive of directives) {
|
|
526
|
+
const name = (0, language_core_1.hyphenateAttr)(directive);
|
|
527
|
+
attributes.push({
|
|
528
|
+
name
|
|
529
|
+
});
|
|
530
|
+
}
|
|
549
531
|
const models = [];
|
|
550
532
|
for (const prop of [...props, ...attrs]) {
|
|
551
533
|
if (prop.startsWith('onUpdate:')) {
|
|
@@ -652,7 +634,7 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
652
634
|
const htmlDocumentations = new Map();
|
|
653
635
|
for (const item of completionList.items) {
|
|
654
636
|
const documentation = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
|
|
655
|
-
if (documentation && !isItemKey(documentation)
|
|
637
|
+
if (documentation && !isItemKey(documentation)) {
|
|
656
638
|
htmlDocumentations.set(item.label, documentation);
|
|
657
639
|
}
|
|
658
640
|
}
|
|
@@ -675,10 +657,12 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
675
657
|
}
|
|
676
658
|
const itemKeyStr = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
|
|
677
659
|
let parsedItemKey = itemKeyStr ? parseItemKey(itemKeyStr) : undefined;
|
|
660
|
+
let propInfo;
|
|
678
661
|
if (parsedItemKey) {
|
|
679
662
|
const documentations = [];
|
|
680
|
-
|
|
681
|
-
|
|
663
|
+
propInfo = cachedPropInfos.get(parsedItemKey.prop);
|
|
664
|
+
if (propInfo?.commentMarkdown) {
|
|
665
|
+
documentations.push(propInfo.commentMarkdown);
|
|
682
666
|
}
|
|
683
667
|
let { isEvent, propName } = getPropName(parsedItemKey);
|
|
684
668
|
if (isEvent) {
|
|
@@ -712,20 +696,25 @@ function create(mode, ts, getTsPluginClient) {
|
|
|
712
696
|
type: 'componentProp',
|
|
713
697
|
tag: '^',
|
|
714
698
|
prop: propName,
|
|
699
|
+
deprecated: false,
|
|
715
700
|
leadingSlash: false
|
|
716
701
|
};
|
|
717
702
|
}
|
|
718
|
-
|
|
703
|
+
propInfo = cachedPropInfos.get(propName);
|
|
704
|
+
if (propInfo?.commentMarkdown) {
|
|
719
705
|
const originalDocumentation = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value;
|
|
720
706
|
item.documentation = {
|
|
721
707
|
kind: 'markdown',
|
|
722
708
|
value: [
|
|
723
|
-
|
|
709
|
+
propInfo.commentMarkdown,
|
|
724
710
|
originalDocumentation,
|
|
725
711
|
].filter(str => !!str).join('\n\n'),
|
|
726
712
|
};
|
|
727
713
|
}
|
|
728
714
|
}
|
|
715
|
+
if (propInfo?.deprecated) {
|
|
716
|
+
item.tags = [1];
|
|
717
|
+
}
|
|
729
718
|
const tokens = [];
|
|
730
719
|
if (item.kind === 10
|
|
731
720
|
&& lastCompletionComponentNames.has((0, language_core_1.hyphenateTag)(item.label))) {
|
|
@@ -850,8 +839,8 @@ function parseLabel(label) {
|
|
|
850
839
|
leadingSlash
|
|
851
840
|
};
|
|
852
841
|
}
|
|
853
|
-
function generateItemKey(type, tag, prop) {
|
|
854
|
-
return
|
|
842
|
+
function generateItemKey(type, tag, prop, deprecated) {
|
|
843
|
+
return `__VLS_data=${type},${tag},${prop},${Number(deprecated)}`;
|
|
855
844
|
}
|
|
856
845
|
function isItemKey(key) {
|
|
857
846
|
return key.startsWith('__VLS_data=');
|
|
@@ -864,6 +853,7 @@ function parseItemKey(key) {
|
|
|
864
853
|
type: strs[0],
|
|
865
854
|
tag: strs[1],
|
|
866
855
|
prop: strs[2],
|
|
856
|
+
deprecated: strs[3] === '1',
|
|
867
857
|
leadingSlash
|
|
868
858
|
};
|
|
869
859
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/language-service",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"data",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"@volar/language-service": "~2.4.11",
|
|
22
22
|
"@volar/typescript": "~2.4.11",
|
|
23
23
|
"@vue/compiler-dom": "^3.5.0",
|
|
24
|
-
"@vue/language-core": "2.2.
|
|
24
|
+
"@vue/language-core": "2.2.2",
|
|
25
25
|
"@vue/shared": "^3.5.0",
|
|
26
|
-
"@vue/typescript-plugin": "2.2.
|
|
27
|
-
"alien-signals": "^0.
|
|
26
|
+
"@vue/typescript-plugin": "2.2.2",
|
|
27
|
+
"alien-signals": "^1.0.3",
|
|
28
28
|
"path-browserify": "^1.0.1",
|
|
29
29
|
"volar-service-css": "0.0.62",
|
|
30
30
|
"volar-service-emmet": "0.0.62",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"vscode-uri": "^3.0.8"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@types/node": "
|
|
43
|
-
"@types/path-browserify": "
|
|
42
|
+
"@types/node": "^22.10.4",
|
|
43
|
+
"@types/path-browserify": "^1.0.1",
|
|
44
44
|
"@volar/kit": "~2.4.11",
|
|
45
45
|
"vscode-languageserver-protocol": "^3.17.5"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "30757908b67f40f779c36795665163634fb81868"
|
|
48
48
|
}
|