first commit

This commit is contained in:
2026-07-17 17:45:56 +08:00
commit 04c487823b
5873 changed files with 12227228 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Johnson Chu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+161
View File
@@ -0,0 +1,161 @@
# @vue/language-core
<p>
<a href="https://www.npmjs.com/package/@vue/language-core"><img src="https://img.shields.io/npm/v/@vue/language-core.svg?labelColor=18181B&color=1584FC" alt="NPM version"></a>
<a href="https://github.com/vuejs/language-tools/blob/master/LICENSE"><img src="https://img.shields.io/github/license/vuejs/language-tools.svg?labelColor=18181B&color=1584FC" alt="License"></a>
</p>
The core module for Vue Language Tools, responsible for parsing Vue Single File Components (SFCs) and transforming them into virtual code structures that TypeScript can understand. This package is a low-level dependency for `@vue/language-server` and `vue-tsc`.
## Installation
```bash
npm install @vue/language-core
```
## Core API
### `createVueLanguagePlugin`
Creates a Vue language plugin for integration with Volar language services.
```typescript
import { createVueLanguagePlugin } from '@vue/language-core';
import type { LanguagePlugin } from '@volar/language-core';
import ts from 'typescript';
const plugin: LanguagePlugin<string> = createVueLanguagePlugin(
ts,
compilerOptions, // ts.CompilerOptions
vueCompilerOptions, // VueCompilerOptions
(scriptId) => scriptId // asFileName: Converts scriptId to a file name
);
```
### `createParsedCommandLine`
Parses TypeScript and Vue compiler options from `tsconfig.json`.
```typescript
import { createParsedCommandLine } from '@vue/language-core';
import ts from 'typescript';
const parsed = createParsedCommandLine(ts, ts.sys, '/path/to/tsconfig.json');
// parsed.options: ts.CompilerOptions
// parsed.vueOptions: VueCompilerOptions
```
### `parse`
Parses Vue SFC source code and returns an `SFCParseResult`.
```typescript
import { parse } from '@vue/language-core';
const result = parse(`
<template>
<div>{{ msg }}</div>
</template>
<script setup lang="ts">
const msg = 'Hello'
</script>
`);
// result.descriptor.template
// result.descriptor.scriptSetup
// result.descriptor.styles
// result.errors
```
## `vueCompilerOptions`
Configure Vue compiler behavior through the `vueCompilerOptions` field in `tsconfig.json`:
```jsonc
{
"compilerOptions": { /* ... */ },
"vueCompilerOptions": {
"target": 3.5,
"strictTemplates": true,
"plugins": ["@vue/language-plugin-pug"]
}
}
```
### File Handling Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `target` | `number \| 'auto'` | `'auto'` | Vue version. `'auto'` reads from `node_modules/vue/package.json`. |
| `extensions` | `string[]` | `['.vue']` | File extensions to be treated as Vue SFCs. |
| `vitePressExtensions` | `string[]` | `[]` | File extensions to be treated as VitePress Markdown. |
| `petiteVueExtensions` | `string[]` | `[]` | File extensions to be treated as Petite Vue HTML. |
| `plugins` | `string[]` | `[]` | Custom language plugins, e.g., [`@vue/language-plugin-pug`](../language-plugin-pug). |
### Type Checking Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `strictTemplates` | `boolean` | `false` | A convenience option that enables the four `check*` options below and `strictVModel`. |
| `checkUnknownProps` | `boolean` | `false` | Check for unknown props. |
| `checkUnknownEvents` | `boolean` | `false` | Check for unknown events. |
| `checkUnknownComponents` | `boolean` | `false` | Check for unknown components. |
| `checkUnknownDirectives` | `boolean` | `false` | Check for unknown directives. |
| `strictVModel` | `boolean` | `false` | Strictly check v-model bindings. |
| `strictCssModules` | `boolean` | `false` | Strictly check CSS Modules class names (not affected by `strictTemplates`). |
### Advanced Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `lib` | `string` | `'vue'` | Vue package name, used for generating import statements. |
| `skipTemplateCodegen` | `boolean` | `false` | Skip virtual code generation for templates. |
| `fallthroughAttributes` | `boolean` | `false` | Enable type inference for fallthrough attributes. |
| `checkRequiredFallthroughAttributes` | `boolean` | `false` | Check required fallthrough attributes. |
| `jsxSlots` | `boolean` | `false` | Use JSX-style slots types. |
| `dataAttributes` | `string[]` | `[]` | Allowed data-* attribute patterns. |
| `htmlAttributes` | `string[]` | `['aria-*']` | Allowed HTML attribute patterns. |
| `resolveStyleImports` | `boolean` | `false` | Resolve import statements in styles. |
| `resolveStyleClassNames` | `boolean \| 'scoped'` | `'scoped'` | Resolve class names in styles. |
## Built-in Plugins
This package includes the following built-in plugins to handle different file types and blocks:
### File Parsing Plugins
| Plugin | Function | Controlled By |
| :--- | :--- | :--- |
| `file-vue` | Parses `.vue` files into an SFC structure. | `extensions` |
| `file-md` | Parses Markdown files into an SFC structure. | `vitePressExtensions` |
| `file-html` | Parses HTML files into an SFC structure. | `petiteVueExtensions` |
### Virtual Code Generation Plugins
| Plugin | Function |
| :--- | :--- |
| `vue-tsx` | Generates TypeScript virtual code from an SFC. |
| `vue-template-html` | Compiles HTML templates. |
| `vue-template-inline-ts` | Handles TypeScript expressions in templates. |
| `vue-template-inline-css` | Handles inline styles in templates. |
| `vue-style-css` | Compiles CSS styles. |
| `vue-script-js` | Handles JavaScript script blocks. |
### Embedded Code Extraction Plugins
| Plugin | Function |
| :--- | :--- |
| `vue-sfc-template` | Extracts the `<template>` block. |
| `vue-sfc-styles` | Extracts `<style>` blocks. |
| `vue-sfc-scripts` | Extracts `<script>` blocks (for formatting). |
| `vue-sfc-customblocks` | Extracts custom blocks. |
## Related Packages
- [`@vue/language-server`](../language-server) - Language Server
- [`@vue/language-service`](../language-service) - Language Service
- [`vue-tsc`](../tsc) - Command-line Type Checker
## License
[MIT](https://github.com/vuejs/language-tools/blob/master/LICENSE) License
+16
View File
@@ -0,0 +1,16 @@
export * from './lib/codegen/template';
export * from './lib/compilerOptions';
export * from './lib/languagePlugin';
export * from './lib/parsers/scriptRanges';
export * from './lib/parsers/scriptSetupRanges';
export * from './lib/plugins';
export * from './lib/template/compile';
export * from './lib/types';
export * from './lib/utils/collectBindings';
export * from './lib/utils/forEachTemplateNode';
export * from './lib/utils/parseSfc';
export * from './lib/utils/shared';
export * from './lib/virtualCode';
export { names } from './lib/codegen/names';
export { tsCodegen } from './lib/plugins/vue-tsx';
export * from '@volar/language-core';
+36
View File
@@ -0,0 +1,36 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.tsCodegen = exports.names = void 0;
__exportStar(require("./lib/codegen/template"), exports);
__exportStar(require("./lib/compilerOptions"), exports);
__exportStar(require("./lib/languagePlugin"), exports);
__exportStar(require("./lib/parsers/scriptRanges"), exports);
__exportStar(require("./lib/parsers/scriptSetupRanges"), exports);
__exportStar(require("./lib/plugins"), exports);
__exportStar(require("./lib/template/compile"), exports);
__exportStar(require("./lib/types"), exports);
__exportStar(require("./lib/utils/collectBindings"), exports);
__exportStar(require("./lib/utils/forEachTemplateNode"), exports);
__exportStar(require("./lib/utils/parseSfc"), exports);
__exportStar(require("./lib/utils/shared"), exports);
__exportStar(require("./lib/virtualCode"), exports);
var names_1 = require("./lib/codegen/names");
Object.defineProperty(exports, "names", { enumerable: true, get: function () { return names_1.names; } });
var vue_tsx_1 = require("./lib/plugins/vue-tsx");
Object.defineProperty(exports, "tsCodegen", { enumerable: true, get: function () { return vue_tsx_1.tsCodegen; } });
__exportStar(require("@volar/language-core"), exports);
//# sourceMappingURL=index.js.map
+86
View File
@@ -0,0 +1,86 @@
import type { VueCodeInformation } from '../types';
declare const raw: {
all: {
verification: true;
completion: true;
semantic: true;
navigation: true;
};
importCompletionOnly: {
__importCompletion: true;
};
verification: {
verification: true;
};
completion: {
completion: true;
};
withoutCompletion: {
verification: true;
semantic: true;
navigation: true;
};
navigation: {
navigation: true;
};
navigationWithoutRename: {
navigation: {
shouldRename: () => false;
};
};
navigationAndCompletion: {
navigation: true;
completion: true;
};
navigationAndVerification: {
navigation: true;
verification: true;
};
withoutNavigation: {
verification: true;
completion: true;
semantic: true;
};
semanticWithoutHighlight: {
semantic: {
shouldHighlight: () => false;
};
};
withoutHighlight: {
semantic: {
shouldHighlight: () => false;
};
verification: true;
navigation: true;
completion: true;
};
withoutHighlightAndCompletion: {
semantic: {
shouldHighlight: () => false;
};
verification: true;
navigation: true;
};
withoutSemantic: {
verification: true;
navigation: true;
completion: true;
};
doNotReportTs2339AndTs2551: {
verification: {
shouldReport: (_source: string | undefined, code: string | number | undefined) => boolean;
};
};
doNotReportTs2353AndTs2561: {
verification: {
shouldReport: (_source: string | undefined, code: string | number | undefined) => boolean;
};
};
doNotReportTs6133: {
verification: {
shouldReport: (_source: string | undefined, code: string | number | undefined) => boolean;
};
};
};
export declare const codeFeatures: { [K in keyof typeof raw]: VueCodeInformation; };
export {};
+85
View File
@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.codeFeatures = void 0;
const raw = {
all: {
verification: true,
completion: true,
semantic: true,
navigation: true,
},
importCompletionOnly: {
__importCompletion: true,
},
verification: {
verification: true,
},
completion: {
completion: true,
},
withoutCompletion: {
verification: true,
semantic: true,
navigation: true,
},
navigation: {
navigation: true,
},
navigationWithoutRename: {
navigation: { shouldRename: () => false },
},
navigationAndCompletion: {
navigation: true,
completion: true,
},
navigationAndVerification: {
navigation: true,
verification: true,
},
withoutNavigation: {
verification: true,
completion: true,
semantic: true,
},
semanticWithoutHighlight: {
semantic: { shouldHighlight: () => false },
},
withoutHighlight: {
semantic: { shouldHighlight: () => false },
verification: true,
navigation: true,
completion: true,
},
withoutHighlightAndCompletion: {
semantic: { shouldHighlight: () => false },
verification: true,
navigation: true,
},
withoutSemantic: {
verification: true,
navigation: true,
completion: true,
},
doNotReportTs2339AndTs2551: {
verification: {
// https://typescript.tv/errors/#ts2339
// https://typescript.tv/errors/#ts2551
shouldReport: (_source, code) => String(code) !== '2339' && String(code) !== '2551',
},
},
doNotReportTs2353AndTs2561: {
verification: {
// https://typescript.tv/errors/#ts2353
// https://typescript.tv/errors/#ts2561
shouldReport: (_source, code) => String(code) !== '2353' && String(code) !== '2561',
},
},
doNotReportTs6133: {
verification: {
// https://typescript.tv/errors/#ts6133
shouldReport: (_source, code) => String(code) !== '6133',
},
},
};
exports.codeFeatures = raw;
//# sourceMappingURL=codeFeatures.js.map
+11
View File
@@ -0,0 +1,11 @@
import type * as CompilerDOM from '@vue/compiler-dom';
export interface InlayHintInfo {
blockName: string;
offset: number;
setting: string;
label: string;
tooltip?: string;
paddingRight?: boolean;
paddingLeft?: boolean;
}
export declare function createVBindShorthandInlayHintInfo(loc: CompilerDOM.SourceLocation, variableName: string): InlayHintInfo;
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVBindShorthandInlayHintInfo = createVBindShorthandInlayHintInfo;
function createVBindShorthandInlayHintInfo(loc, variableName) {
return {
blockName: 'template',
offset: loc.end.offset,
setting: 'vue.inlayHints.vBindShorthand',
label: `="${variableName}"`,
tooltip: [
`This is a shorthand for \`${loc.source}="${variableName}"\`.`,
'To hide this hint, set `vue.inlayHints.vBindShorthand` to `false` in IDE settings.',
'[More info](https://github.com/vuejs/core/pull/9451)',
].join('\n\n'),
};
}
//# sourceMappingURL=inlayHints.js.map
+10
View File
@@ -0,0 +1,10 @@
import type { VueCompilerOptions } from '../types';
export declare function getLocalTypesGenerator(vueCompilerOptions: VueCompilerOptions): {
generate: () => Generator<string, void, unknown>;
readonly PrettifyLocal: string;
readonly WithDefaults: string;
readonly WithSlots: string;
readonly PropsChildren: string;
readonly TypePropsToOption: string;
readonly OmitIndexSignature: string;
};
+91
View File
@@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalTypesGenerator = getLocalTypesGenerator;
const utils_1 = require("./utils");
function getLocalTypesGenerator(vueCompilerOptions) {
const used = new Set();
const WithDefaults = defineHelper(`__VLS_WithDefaults`, () => `
type __VLS_WithDefaults<P, D> = {
[K in keyof Pick<P, keyof P>]: K extends keyof D
? ${PrettifyLocal.name}<P[K] & { default: D[K] }>
: P[K]
};
`.trimStart());
const PrettifyLocal = defineHelper(`__VLS_PrettifyLocal`, () => `type __VLS_PrettifyLocal<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {}${utils_1.endOfLine}`);
const WithSlots = defineHelper(`__VLS_WithSlots`, () => `
type __VLS_WithSlots<T, S> = T & {
new(): {
$slots: S;
}
};
`.trimStart());
const PropsChildren = defineHelper(`__VLS_PropsChildren`, () => `
type __VLS_PropsChildren<S> = {
[K in keyof (
boolean extends (
// @ts-ignore
JSX.ElementChildrenAttribute extends never
? true
: false
)
? never
// @ts-ignore
: JSX.ElementChildrenAttribute
)]?: S;
};
`.trimStart());
const TypePropsToOption = defineHelper(`__VLS_TypePropsToOption`, () => `
type __VLS_TypePropsToOption<T> = {
[K in keyof T]-?: {} extends Pick<T, K>
? { type: import('${vueCompilerOptions.lib}').PropType<Required<T>[K]> }
: { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true }
};
`.trimStart());
const OmitIndexSignature = defineHelper(`__VLS_OmitIndexSignature`, () => `type __VLS_OmitIndexSignature<T> = { [K in keyof T as {} extends Record<K, unknown> ? never : K]: T[K]; }${utils_1.endOfLine}`);
const helpers = {
[PrettifyLocal.name]: PrettifyLocal,
[WithDefaults.name]: WithDefaults,
[WithSlots.name]: WithSlots,
[PropsChildren.name]: PropsChildren,
[TypePropsToOption.name]: TypePropsToOption,
[OmitIndexSignature.name]: OmitIndexSignature,
};
used.clear();
return {
generate,
get PrettifyLocal() {
return PrettifyLocal.name;
},
get WithDefaults() {
return WithDefaults.name;
},
get WithSlots() {
return WithSlots.name;
},
get PropsChildren() {
return PropsChildren.name;
},
get TypePropsToOption() {
return TypePropsToOption.name;
},
get OmitIndexSignature() {
return OmitIndexSignature.name;
},
};
function* generate() {
for (const name of used) {
yield helpers[name].generate();
}
used.clear();
}
function defineHelper(name, generate) {
return {
get name() {
used.add(name);
return name;
},
generate,
};
}
}
//# sourceMappingURL=localTypes.js.map
+74
View File
@@ -0,0 +1,74 @@
declare const raw: {
base: string;
export: string;
components: string;
componentsOption: string;
ctx: string;
defaultModels: string;
defaults: string;
directives: string;
directivesOption: string;
dollars: string;
emit: string;
exposed: string;
intrinsics: string;
modelEmit: string;
props: string;
propsOption: string;
self: string;
setup: string;
slots: string;
src: string;
Emit: string;
EmitProps: string;
GlobalComponents: string;
InheritedAttrs: string;
LocalComponents: string;
LocalDirectives: string;
ModelEmit: string;
ModelProps: string;
Props: string;
PublicProps: string;
RootEl: string;
SetupExposed: string;
Slots: string;
StyleModules: string;
StyleScopedClasses: string;
TemplateRefs: string;
asFunctionalComponent0: string;
asFunctionalComponent1: string;
asFunctionalDirective: string;
asFunctionalElement0: string;
asFunctionalElement1: string;
asFunctionalSlot: string;
directiveBindingRestFields: string;
functionalComponentArgsRest: string;
omit: string;
tryAsConstant: string;
vFor: string;
vSlot: string;
ConstructorOverloads: string;
Elements: string;
EmitsToProps: string;
FunctionalComponent0: string;
FunctionalComponent1: string;
FunctionalComponentCtx: string;
FunctionalComponentProps: string;
IsAny: string;
IsFunction: string;
NormalizeEmits: string;
OverloadUnion: string;
OverloadUnionInner: string;
PickNotAny: string;
PrettifyGlobal: string;
ResolveDirectives: string;
ResolveEmits: string;
ResolveEvent: string;
ShortEmits: string;
ShortEmitsToObject: string;
SpreadMerge: string;
UnionToIntersection: string;
WithComponent: string;
};
export declare const names: typeof raw;
export {};
+79
View File
@@ -0,0 +1,79 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.names = void 0;
const raw = {
base: '',
export: '',
components: '',
componentsOption: '',
ctx: '',
defaultModels: '',
defaults: '',
directives: '',
directivesOption: '',
dollars: '',
emit: '',
exposed: '',
intrinsics: '',
modelEmit: '',
props: '',
propsOption: '',
self: '',
setup: '',
slots: '',
src: '',
Emit: '',
EmitProps: '',
GlobalComponents: '',
InheritedAttrs: '',
LocalComponents: '',
LocalDirectives: '',
ModelEmit: '',
ModelProps: '',
Props: '',
PublicProps: '',
RootEl: '',
SetupExposed: '',
Slots: '',
StyleModules: '',
StyleScopedClasses: '',
TemplateRefs: '',
// #region template helpers
asFunctionalComponent0: '',
asFunctionalComponent1: '',
asFunctionalDirective: '',
asFunctionalElement0: '',
asFunctionalElement1: '',
asFunctionalSlot: '',
directiveBindingRestFields: '',
functionalComponentArgsRest: '',
omit: '',
tryAsConstant: '',
vFor: '',
vSlot: '',
ConstructorOverloads: '',
Elements: '',
EmitsToProps: '',
FunctionalComponent0: '',
FunctionalComponent1: '',
FunctionalComponentCtx: '',
FunctionalComponentProps: '',
IsAny: '',
IsFunction: '',
NormalizeEmits: '',
OverloadUnion: '',
OverloadUnionInner: '',
PickNotAny: '',
PrettifyGlobal: '',
ResolveDirectives: '',
ResolveEmits: '',
ResolveEvent: '',
ShortEmits: '',
ShortEmitsToObject: '',
SpreadMerge: '',
UnionToIntersection: '',
WithComponent: '',
// #endregion
};
exports.names = Object.fromEntries(Object.keys(raw).map(key => [key, `__VLS_${key}`]));
//# sourceMappingURL=names.js.map
@@ -0,0 +1,5 @@
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
import type { Code, IRScriptSetup } from '../../types';
import type { ScriptCodegenContext } from './context';
import type { ScriptCodegenOptions } from './index';
export declare function generateComponent(options: ScriptCodegenOptions, ctx: ScriptCodegenContext, scriptSetup: IRScriptSetup, scriptSetupRanges: ScriptSetupRanges): Generator<Code>;
+114
View File
@@ -0,0 +1,114 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateComponent = generateComponent;
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const merge_1 = require("../utils/merge");
function* generateComponent(options, ctx, scriptSetup, scriptSetupRanges) {
yield `(await import('${options.vueCompilerOptions.lib}')).defineComponent({${utils_1.newLine}`;
if (scriptSetupRanges.defineExpose) {
yield `setup: () => ${names_1.names.exposed},${utils_1.newLine}`;
}
const emitOptionCodes = [...generateEmitsOption(options, scriptSetupRanges)];
yield* emitOptionCodes;
yield* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, !!emitOptionCodes.length);
if (options.vueCompilerOptions.target >= 3.5
&& options.vueCompilerOptions.inferComponentDollarRefs
&& options.templateAndStyleTypes.has(names_1.names.TemplateRefs)) {
yield `__typeRefs: {} as ${names_1.names.TemplateRefs},${utils_1.newLine}`;
}
if (options.vueCompilerOptions.target >= 3.5
&& options.vueCompilerOptions.inferComponentDollarEl
&& options.templateAndStyleTypes.has(names_1.names.RootEl)) {
yield `__typeEl: {} as ${names_1.names.RootEl},${utils_1.newLine}`;
}
yield `})`;
}
function* generateEmitsOption(options, scriptSetupRanges) {
const typeCodes = options.vueCompilerOptions.target >= 3.5 && !scriptSetupRanges.defineEmits?.hasUnionTypeArg
? [...generateTypeEmitsOption(scriptSetupRanges)]
: [];
const runtimeCodes = !typeCodes.length
? [...generateRuntimeEmitsOption(scriptSetupRanges)]
: [];
if (typeCodes.length) {
yield `__typeEmits: {} as `;
yield* (0, merge_1.generateIntersectMerge)(...typeCodes);
yield `,${utils_1.newLine}`;
}
else if (runtimeCodes.length) {
yield `emits: `;
yield* (0, merge_1.generateSpreadMerge)(...runtimeCodes);
yield `,${utils_1.newLine}`;
}
}
function* generateTypeEmitsOption(scriptSetupRanges) {
if (scriptSetupRanges.defineModel.length) {
yield names_1.names.ModelEmit;
}
if (scriptSetupRanges.defineEmits?.typeArg) {
yield names_1.names.Emit;
}
}
function* generateRuntimeEmitsOption(scriptSetupRanges) {
if (scriptSetupRanges.defineModel.length) {
yield `{} as ${names_1.names.NormalizeEmits}<typeof ${names_1.names.modelEmit}>`;
}
if (scriptSetupRanges.defineEmits) {
yield `{} as ${names_1.names.NormalizeEmits}<typeof ${scriptSetupRanges.defineEmits.name ?? names_1.names.emit}>`;
}
}
function* generatePropsOption(options, ctx, scriptSetup, scriptSetupRanges, hasEmitsOption) {
const typeCodes = options.vueCompilerOptions.target >= 3.5 && !scriptSetupRanges.defineProps?.arg
? [...generateTypePropsOption(options, ctx, hasEmitsOption)]
: [];
const runtimeCodes = scriptSetupRanges.withDefaults || !typeCodes.length
? [...generateRuntimePropsOption(options, ctx, scriptSetup, scriptSetupRanges, hasEmitsOption)]
: [];
if (typeCodes.length) {
if (options.vueCompilerOptions.target >= 3.6 && scriptSetupRanges.withDefaults?.arg) {
yield `__defaults: ${names_1.names.defaults},${utils_1.newLine}`;
}
yield `__typeProps: `;
yield* (0, merge_1.generateSpreadMerge)(...typeCodes);
yield `,${utils_1.newLine}`;
}
if (runtimeCodes.length) {
yield `props: `;
yield* (0, merge_1.generateSpreadMerge)(...runtimeCodes);
yield `,${utils_1.newLine}`;
}
}
function* generateTypePropsOption(options, ctx, hasEmitsOption) {
if (options.templateAndStyleTypes.has(names_1.names.InheritedAttrs)) {
const attrsType = hasEmitsOption
? `Omit<${names_1.names.InheritedAttrs}, keyof ${names_1.names.EmitProps}>`
: names_1.names.InheritedAttrs;
yield `{} as ${attrsType}`;
}
if (ctx.generatedTypes.has(names_1.names.PublicProps)) {
yield `{} as ${names_1.names.PublicProps}`;
}
}
function* generateRuntimePropsOption(options, ctx, scriptSetup, scriptSetupRanges, hasEmitsOption) {
if (options.templateAndStyleTypes.has(names_1.names.InheritedAttrs)) {
const attrsType = hasEmitsOption
? `Omit<${names_1.names.InheritedAttrs}, keyof ${names_1.names.EmitProps}>`
: names_1.names.InheritedAttrs;
const propsType = `${ctx.localTypes.TypePropsToOption}<${names_1.names.PickNotAny}<${ctx.localTypes.OmitIndexSignature}<${attrsType}>, {}>>`;
yield `{} as ${propsType}`;
}
if (ctx.generatedTypes.has(names_1.names.PublicProps) && options.vueCompilerOptions.target < 3.6) {
let propsType = `${ctx.localTypes.TypePropsToOption}<${names_1.names.PublicProps}>`;
if (scriptSetupRanges.withDefaults?.arg) {
propsType = `${ctx.localTypes.WithDefaults}<${propsType}, typeof ${names_1.names.defaults}>`;
}
yield `{} as ${propsType}`;
}
if (scriptSetupRanges.defineProps?.arg) {
const { arg } = scriptSetupRanges.defineProps;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, arg.start, arg.end, codeFeatures_1.codeFeatures.navigation);
}
}
//# sourceMappingURL=component.js.map
+16
View File
@@ -0,0 +1,16 @@
import type { InlayHintInfo } from '../inlayHints';
import type { ScriptCodegenOptions } from './index';
export type ScriptCodegenContext = ReturnType<typeof createScriptCodegenContext>;
export declare function createScriptCodegenContext(options: ScriptCodegenOptions): {
generatedTypes: Set<string>;
localTypes: {
generate: () => Generator<string, void, unknown>;
readonly PrettifyLocal: string;
readonly WithDefaults: string;
readonly WithSlots: string;
readonly PropsChildren: string;
readonly TypePropsToOption: string;
readonly OmitIndexSignature: string;
};
inlayHints: InlayHintInfo[];
};
+14
View File
@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createScriptCodegenContext = createScriptCodegenContext;
const localTypes_1 = require("../localTypes");
function createScriptCodegenContext(options) {
const localTypes = (0, localTypes_1.getLocalTypesGenerator)(options.vueCompilerOptions);
const inlayHints = [];
return {
generatedTypes: new Set(),
localTypes,
inlayHints,
};
}
//# sourceMappingURL=context.js.map
+29
View File
@@ -0,0 +1,29 @@
import type { ScriptRanges } from '../../parsers/scriptRanges';
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
import type { Code, IRScript, IRScriptSetup, VueCompilerOptions } from '../../types';
export interface ScriptCodegenOptions {
vueCompilerOptions: VueCompilerOptions;
script: IRScript | undefined;
scriptSetup: IRScriptSetup | undefined;
fileName: string;
scriptRanges: ScriptRanges | undefined;
scriptSetupRanges: ScriptSetupRanges | undefined;
templateAndStyleTypes: Set<string>;
templateAndStyleCodes: Code[];
exposed: Set<string>;
}
export { generate as generateScript };
declare function generate(options: ScriptCodegenOptions): {
generatedTypes: Set<string>;
localTypes: {
generate: () => Generator<string, void, unknown>;
readonly PrettifyLocal: string;
readonly WithDefaults: string;
readonly WithSlots: string;
readonly PropsChildren: string;
readonly TypePropsToOption: string;
readonly OmitIndexSignature: string;
};
inlayHints: import("../inlayHints").InlayHintInfo[];
codes: Code[];
};
+202
View File
@@ -0,0 +1,202 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateScript = generate;
const path = __importStar(require("path-browserify"));
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const context_1 = require("./context");
const scriptSetup_1 = require("./scriptSetup");
const template_1 = require("./template");
const exportExpression = `{} as typeof ${names_1.names.export}`;
function generate(options) {
const ctx = (0, context_1.createScriptCodegenContext)(options);
const codeGenerator = generateWorker(options, ctx);
return { ...ctx, codes: [...codeGenerator] };
}
function* generateWorker(options, ctx) {
const { script, scriptRanges, scriptSetup, scriptSetupRanges, vueCompilerOptions, fileName } = options;
yield* generateGlobalTypesReference(vueCompilerOptions, fileName);
// <script src="">
if (typeof script?.src === 'object') {
let src = script.src.text;
if (src.endsWith('.ts') && !src.endsWith('.d.ts')) {
src = src.slice(0, -'.ts'.length) + '.js';
}
else if (src.endsWith('.tsx')) {
src = src.slice(0, -'.tsx'.length) + '.jsx';
}
yield `import ${names_1.names.src} from `;
const token = yield* (0, boundary_1.startBoundary)('main', script.src.offset, {
...codeFeatures_1.codeFeatures.all,
...src !== script.src.text ? codeFeatures_1.codeFeatures.navigationWithoutRename : {},
});
yield `'`;
yield [src.slice(0, script.src.text.length), 'main', script.src.offset, { __combineToken: token }];
yield src.slice(script.src.text.length);
yield `'`;
yield (0, boundary_1.endBoundary)(token, script.src.offset + script.src.text.length);
yield utils_1.endOfLine;
yield `export default ${names_1.names.src}${utils_1.endOfLine}`;
yield* (0, template_1.generateTemplate)(options, ctx, names_1.names.src);
}
// <script> + <script setup>
else if (script && scriptRanges && scriptSetup && scriptSetupRanges) {
yield* (0, scriptSetup_1.generateScriptSetupImports)(scriptSetup, scriptSetupRanges);
// <script>
let selfType;
const { exportDefault } = scriptRanges;
if (exportDefault) {
yield* generateScriptWithExportDefault(ctx, script, scriptRanges, exportDefault, vueCompilerOptions, selfType = names_1.names.self);
}
else {
yield* (0, utils_1.generateSfcBlockSection)(script, 0, script.content.length, codeFeatures_1.codeFeatures.all);
yield `export default ${exportExpression}${utils_1.endOfLine}`;
}
// <script setup>
yield* generateExportDeclareEqual(scriptSetup, names_1.names.export);
if (scriptSetup.generic) {
yield* (0, scriptSetup_1.generateGeneric)(options, ctx, scriptSetup, scriptSetupRanges, scriptSetup.generic, (0, scriptSetup_1.generateSetupFunction)(options, ctx, scriptSetup, scriptSetupRanges, (0, template_1.generateTemplate)(options, ctx, selfType)));
}
else {
yield `await (async () => {${utils_1.newLine}`;
yield* (0, scriptSetup_1.generateSetupFunction)(options, ctx, scriptSetup, scriptSetupRanges, (0, template_1.generateTemplate)(options, ctx, selfType), [`return `]);
yield `})()${utils_1.endOfLine}`;
}
}
// only <script setup>
else if (scriptSetup && scriptSetupRanges) {
yield* (0, scriptSetup_1.generateScriptSetupImports)(scriptSetup, scriptSetupRanges);
if (scriptSetup.generic) {
yield* generateExportDeclareEqual(scriptSetup, names_1.names.export);
yield* (0, scriptSetup_1.generateGeneric)(options, ctx, scriptSetup, scriptSetupRanges, scriptSetup.generic, (0, scriptSetup_1.generateSetupFunction)(options, ctx, scriptSetup, scriptSetupRanges, (0, template_1.generateTemplate)(options, ctx)));
}
else {
// no script block, generate script setup code at root
yield* (0, scriptSetup_1.generateSetupFunction)(options, ctx, scriptSetup, scriptSetupRanges, (0, template_1.generateTemplate)(options, ctx), generateExportDeclareEqual(scriptSetup, names_1.names.export));
}
yield `export default ${exportExpression}${utils_1.endOfLine}`;
}
// only <script>
else if (script && scriptRanges) {
const { exportDefault } = scriptRanges;
if (exportDefault) {
yield* generateScriptWithExportDefault(ctx, script, scriptRanges, exportDefault, vueCompilerOptions, names_1.names.export, (0, template_1.generateTemplate)(options, ctx, names_1.names.export));
}
else {
yield* (0, utils_1.generateSfcBlockSection)(script, 0, script.content.length, codeFeatures_1.codeFeatures.all);
yield* generateExportDeclareEqual(script, names_1.names.export);
yield `(await import('${vueCompilerOptions.lib}')).defineComponent({})${utils_1.endOfLine}`;
yield* (0, template_1.generateTemplate)(options, ctx, names_1.names.export);
yield `export default ${exportExpression}${utils_1.endOfLine}`;
}
}
yield* ctx.localTypes.generate();
}
function* generateScriptWithExportDefault(ctx, script, scriptRanges, exportDefault, vueCompilerOptions, varName, templateGenerator) {
const componentOptions = scriptRanges.exportDefault?.options;
const { expression, isObjectLiteral } = componentOptions ?? exportDefault;
let wrapLeft;
let wrapRight;
if (isObjectLiteral
&& vueCompilerOptions.optionsWrapper.length) {
[wrapLeft, wrapRight] = vueCompilerOptions.optionsWrapper;
ctx.inlayHints.push({
blockName: script.name,
offset: expression.start,
setting: 'vue.inlayHints.optionsWrapper',
label: wrapLeft || '[Missing optionsWrapper[0]]',
tooltip: [
'This is virtual code that is automatically wrapped for type support, it does not affect your runtime behavior, you can customize it via `vueCompilerOptions.optionsWrapper` option in tsconfig / jsconfig.',
'To hide it, you can set `"vue.inlayHints.optionsWrapper": false` in IDE settings.',
].join('\n\n'),
}, {
blockName: script.name,
offset: expression.end,
setting: 'vue.inlayHints.optionsWrapper',
label: wrapRight || '[Missing optionsWrapper[1]]',
});
}
yield* (0, utils_1.generateSfcBlockSection)(script, 0, expression.start, codeFeatures_1.codeFeatures.all);
yield exportExpression;
yield* (0, utils_1.generateSfcBlockSection)(script, expression.end, exportDefault.end, codeFeatures_1.codeFeatures.all);
yield utils_1.endOfLine;
if (templateGenerator) {
yield* templateGenerator;
}
yield* generateExportDeclareEqual(script, varName);
if (wrapLeft && wrapRight) {
yield wrapLeft;
yield* (0, utils_1.generateSfcBlockSection)(script, expression.start, expression.end, codeFeatures_1.codeFeatures.all);
yield wrapRight;
}
else {
yield* (0, utils_1.generateSfcBlockSection)(script, expression.start, expression.end, codeFeatures_1.codeFeatures.all);
}
yield utils_1.endOfLine;
yield* (0, utils_1.generateSfcBlockSection)(script, exportDefault.end, script.content.length, codeFeatures_1.codeFeatures.all);
}
function* generateGlobalTypesReference({ typesRoot, lib, target, checkUnknownProps }, fileName) {
let typesPath;
if (path.isAbsolute(typesRoot)) {
let relativePath = path.relative(path.dirname(fileName), typesRoot);
if (relativePath !== typesRoot
&& !relativePath.startsWith('./')
&& !relativePath.startsWith('../')) {
relativePath = './' + relativePath;
}
typesPath = relativePath;
}
else {
typesPath = typesRoot;
}
yield `/// <reference types=${JSON.stringify(typesPath + '/template-helpers.d.ts')} />${utils_1.newLine}`;
if (!checkUnknownProps) {
yield `/// <reference types=${JSON.stringify(typesPath + '/props-fallback.d.ts')} />${utils_1.newLine}`;
}
if (lib === 'vue' && target < 3.5) {
yield `/// <reference types=${JSON.stringify(typesPath + '/vue-3.4-shims.d.ts')} />${utils_1.newLine}`;
}
}
function* generateExportDeclareEqual(block, name) {
yield `const `;
const token = yield* (0, boundary_1.startBoundary)(block.name, 0, codeFeatures_1.codeFeatures.doNotReportTs6133);
yield name;
yield (0, boundary_1.endBoundary)(token, block.content.length);
yield ` = `;
}
//# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
import type { Code, IRScriptSetup } from '../../types';
import type { ScriptCodegenContext } from './context';
import type { ScriptCodegenOptions } from './index';
export declare function generateScriptSetupImports(scriptSetup: IRScriptSetup, scriptSetupRanges: ScriptSetupRanges): Generator<Code>;
export declare function generateGeneric(options: ScriptCodegenOptions, ctx: ScriptCodegenContext, scriptSetup: IRScriptSetup, scriptSetupRanges: ScriptSetupRanges, generic: NonNullable<IRScriptSetup['generic']>, body: Iterable<Code>): Generator<Code>;
export declare function generateSetupFunction(options: ScriptCodegenOptions, ctx: ScriptCodegenContext, scriptSetup: IRScriptSetup, scriptSetupRanges: ScriptSetupRanges, body: Iterable<Code>, output?: Iterable<Code>): Generator<Code>;
+391
View File
@@ -0,0 +1,391 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateScriptSetupImports = generateScriptSetupImports;
exports.generateGeneric = generateGeneric;
exports.generateSetupFunction = generateSetupFunction;
const shared_1 = require("@vue/shared");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const camelized_1 = require("../utils/camelized");
const transform_1 = require("../utils/transform");
const component_1 = require("./component");
function* generateScriptSetupImports(scriptSetup, scriptSetupRanges) {
yield [
scriptSetup.content.slice(0, Math.max(scriptSetupRanges.importSectionEndOffset, scriptSetupRanges.leadingCommentEndOffset)),
'scriptSetup',
0,
codeFeatures_1.codeFeatures.all,
];
}
function* generateGeneric(options, ctx, scriptSetup, scriptSetupRanges, generic, body) {
yield `(`;
if (typeof generic === 'object') {
yield `<`;
yield [generic.text, 'main', generic.offset, codeFeatures_1.codeFeatures.all];
if (!generic.text.endsWith(`,`)) {
yield `,`;
}
yield `>`;
}
yield `(${utils_1.newLine}`
+ ` ${names_1.names.props}: NonNullable<Awaited<typeof ${names_1.names.setup}>>['props'],${utils_1.newLine}`
+ ` ${names_1.names.ctx}?: ${ctx.localTypes.PrettifyLocal}<Pick<NonNullable<Awaited<typeof ${names_1.names.setup}>>, 'attrs' | 'emit' | 'slots'>>,${utils_1.newLine}`
+ ` ${names_1.names.exposed}?: NonNullable<Awaited<typeof ${names_1.names.setup}>>['expose'],${utils_1.newLine}`
+ ` ${names_1.names.setup} = (async () => {${utils_1.newLine}`;
yield* body;
const propTypes = [];
const emitTypes = [];
const { vueCompilerOptions } = options;
if (ctx.generatedTypes.has(names_1.names.PublicProps)) {
propTypes.push(names_1.names.PublicProps);
}
if (scriptSetupRanges.defineProps?.arg) {
yield `const ${names_1.names.propsOption} = `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, scriptSetupRanges.defineProps.arg.start, scriptSetupRanges.defineProps.arg.end, codeFeatures_1.codeFeatures.navigation);
yield utils_1.endOfLine;
propTypes.push(`import('${vueCompilerOptions.lib}').${vueCompilerOptions.target >= 3.3 ? `ExtractPublicPropTypes` : `ExtractPropTypes`}<typeof ${names_1.names.propsOption}>`);
}
if (scriptSetupRanges.defineEmits || scriptSetupRanges.defineModel.length) {
propTypes.push(names_1.names.EmitProps);
}
if (options.templateAndStyleTypes.has(names_1.names.InheritedAttrs)) {
propTypes.push(names_1.names.InheritedAttrs);
}
if (scriptSetupRanges.defineEmits) {
emitTypes.push(`typeof ${scriptSetupRanges.defineEmits.name ?? names_1.names.emit}`);
}
if (scriptSetupRanges.defineModel.length) {
emitTypes.push(`typeof ${names_1.names.modelEmit}`);
}
yield `return {} as {${utils_1.newLine}`;
yield ` props: `;
yield vueCompilerOptions.target >= 3.4
? `import('${vueCompilerOptions.lib}').PublicProps`
: vueCompilerOptions.target >= 3
? `import('${vueCompilerOptions.lib}').VNodeProps`
+ ` & import('${vueCompilerOptions.lib}').AllowedComponentProps`
+ ` & import('${vueCompilerOptions.lib}').ComponentCustomProps`
: `globalThis.JSX.IntrinsicAttributes`;
if (propTypes.length) {
yield ` & ${ctx.localTypes.PrettifyLocal}<${propTypes.join(` & `)}>`;
}
yield ` & (typeof globalThis extends { __VLS_PROPS_FALLBACK: infer P } ? P : {})${utils_1.endOfLine}`;
yield ` expose: (exposed: `;
yield scriptSetupRanges.defineExpose
? `import('${vueCompilerOptions.lib}').ShallowUnwrapRef<typeof ${names_1.names.exposed}>`
: `{}`;
if (options.vueCompilerOptions.inferComponentDollarRefs
&& options.templateAndStyleTypes.has(names_1.names.TemplateRefs)) {
yield ` & { $refs: ${names_1.names.TemplateRefs}; }`;
}
if (options.vueCompilerOptions.inferComponentDollarEl
&& options.templateAndStyleTypes.has(names_1.names.RootEl)) {
yield ` & { $el: ${names_1.names.RootEl}; }`;
}
yield `) => void${utils_1.endOfLine}`;
yield ` attrs: any${utils_1.endOfLine}`;
yield ` slots: ${hasSlotsType(options) ? names_1.names.Slots : `{}`}${utils_1.endOfLine}`;
yield ` emit: ${emitTypes.length ? emitTypes.join(` & `) : `{}`}${utils_1.endOfLine}`;
yield `}${utils_1.endOfLine}`;
yield `})(),${utils_1.newLine}`; // __VLS_setup = (async () => {
yield `) => ({} as import('${vueCompilerOptions.lib}').VNode & { __ctx?: Awaited<typeof ${names_1.names.setup}> }))${utils_1.endOfLine}`;
}
function* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, body, output) {
const transforms = [];
if (scriptSetupRanges.defineProps) {
const { name, statement, callExp, typeArg } = scriptSetupRanges.defineProps;
const _callExp = scriptSetupRanges.withDefaults?.callExp ?? callExp;
transforms.push(...generateDefineWithTypeTransforms(scriptSetup, statement, _callExp, typeArg, name, names_1.names.props, names_1.names.Props));
}
if (scriptSetupRanges.defineEmits) {
const { name, statement, callExp, typeArg } = scriptSetupRanges.defineEmits;
transforms.push(...generateDefineWithTypeTransforms(scriptSetup, statement, callExp, typeArg, name, names_1.names.emit, names_1.names.Emit));
}
if (scriptSetupRanges.defineSlots) {
const { name, statement, callExp, typeArg } = scriptSetupRanges.defineSlots;
transforms.push(...generateDefineWithTypeTransforms(scriptSetup, statement, callExp, typeArg, name, names_1.names.slots, names_1.names.Slots));
}
if (scriptSetupRanges.defineExpose) {
const { callExp, arg, typeArg } = scriptSetupRanges.defineExpose;
if (typeArg) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `let ${names_1.names.exposed}!: `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, typeArg.start, typeArg.end, codeFeatures_1.codeFeatures.all);
yield utils_1.endOfLine;
}), (0, transform_1.replace)(typeArg.start, typeArg.end, function* () {
yield `typeof ${names_1.names.exposed}`;
}));
}
else if (arg) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `const ${names_1.names.exposed} = `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, arg.start, arg.end, codeFeatures_1.codeFeatures.all);
yield utils_1.endOfLine;
}), (0, transform_1.replace)(arg.start, arg.end, function* () {
yield names_1.names.exposed;
}));
}
else {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `const ${names_1.names.exposed} = {}${utils_1.endOfLine}`;
}));
}
}
if (options.vueCompilerOptions.inferTemplateDollarAttrs) {
for (const { callExp } of scriptSetupRanges.useAttrs) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `(`;
}), (0, transform_1.insert)(callExp.end, function* () {
yield ` as typeof ${names_1.names.dollars}.$attrs)`;
}));
}
}
for (const { callExp, exp, arg } of scriptSetupRanges.useCssModule) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `(`;
}));
const type = options.templateAndStyleTypes.has(names_1.names.StyleModules)
? names_1.names.StyleModules
: `{}`;
if (arg) {
transforms.push((0, transform_1.insert)(callExp.end, function* () {
yield ` as Omit<${type}, '$style'>[`;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, arg.start, arg.end, codeFeatures_1.codeFeatures.withoutSemantic);
yield `])`;
}), (0, transform_1.replace)(arg.start, arg.end, function* () {
yield `{} as any`;
}));
}
else {
transforms.push((0, transform_1.insert)(callExp.end, function* () {
yield ` as ${type}[`;
const token = yield* (0, boundary_1.startBoundary)(scriptSetup.name, exp.start, codeFeatures_1.codeFeatures.verification);
yield `'$style'`;
yield (0, boundary_1.endBoundary)(token, exp.end);
yield `])`;
}));
}
}
if (options.vueCompilerOptions.inferTemplateDollarSlots) {
for (const { callExp } of scriptSetupRanges.useSlots) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `(`;
}), (0, transform_1.insert)(callExp.end, function* () {
yield ` as typeof ${names_1.names.dollars}.$slots)`;
}));
}
}
for (const { callExp, arg } of scriptSetupRanges.useTemplateRef) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield `(`;
}), (0, transform_1.insert)(callExp.end, function* () {
yield ` as Readonly<import('${options.vueCompilerOptions.lib}').ShallowRef<`;
if (arg) {
yield names_1.names.TemplateRefs;
yield `[`;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, arg.start, arg.end, codeFeatures_1.codeFeatures.withoutSemantic);
yield `]`;
}
else {
yield `unknown`;
}
yield ` | null>>)`;
}));
if (arg) {
transforms.push((0, transform_1.replace)(arg.start, arg.end, function* () {
yield `{} as any`;
}));
}
}
yield* (0, transform_1.generateCodeWithTransforms)(Math.max(scriptSetupRanges.importSectionEndOffset, scriptSetupRanges.leadingCommentEndOffset), scriptSetup.content.length, transforms, (start, end) => (0, utils_1.generateSfcBlockSection)(scriptSetup, start, end, codeFeatures_1.codeFeatures.all));
yield* generateMacros(options);
yield* generateModels(scriptSetup, scriptSetupRanges);
yield* generatePublicProps(options, ctx, scriptSetup, scriptSetupRanges);
yield* body;
if (output) {
if (hasSlotsType(options)) {
yield `const ${names_1.names.base} = `;
yield* (0, component_1.generateComponent)(options, ctx, scriptSetup, scriptSetupRanges);
yield utils_1.endOfLine;
yield* output;
yield `{} as ${ctx.localTypes.WithSlots}<typeof ${names_1.names.base}, ${names_1.names.Slots}>${utils_1.endOfLine}`;
}
else {
yield* output;
yield* (0, component_1.generateComponent)(options, ctx, scriptSetup, scriptSetupRanges);
yield utils_1.endOfLine;
}
}
}
function* generateMacros(options) {
if (options.vueCompilerOptions.target >= 3.3) {
yield `// @ts-ignore${utils_1.newLine}`;
yield `declare const { `;
for (const macro of Object.keys(options.vueCompilerOptions.macros)) {
if (!options.exposed.has(macro)) {
yield `${macro}, `;
}
}
yield `}: typeof import('${options.vueCompilerOptions.lib}')${utils_1.endOfLine}`;
}
}
function* generateDefineWithTypeTransforms(scriptSetup, statement, callExp, typeArg, name, defaultName, typeName) {
if (typeArg) {
yield (0, transform_1.insert)(statement.start, function* () {
yield `type ${typeName} = `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, typeArg.start, typeArg.end, codeFeatures_1.codeFeatures.all);
yield utils_1.endOfLine;
});
yield (0, transform_1.replace)(typeArg.start, typeArg.end, function* () {
yield typeName;
});
}
if (!name) {
if (statement.start === callExp.start && statement.end === callExp.end) {
yield (0, transform_1.insert)(callExp.start, function* () {
yield `const ${defaultName} = `;
});
}
else if (typeArg) {
yield (0, transform_1.replace)(statement.start, typeArg.start, function* () {
yield `const ${defaultName} = `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, callExp.start, typeArg.start, codeFeatures_1.codeFeatures.all);
});
yield (0, transform_1.replace)(typeArg.end, callExp.end, function* () {
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, typeArg.end, callExp.end, codeFeatures_1.codeFeatures.all);
yield utils_1.endOfLine;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, statement.start, callExp.start, codeFeatures_1.codeFeatures.all);
yield defaultName;
});
}
else {
yield (0, transform_1.replace)(statement.start, callExp.end, function* () {
yield `const ${defaultName} = `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, callExp.start, callExp.end, codeFeatures_1.codeFeatures.all);
yield utils_1.endOfLine;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, statement.start, callExp.start, codeFeatures_1.codeFeatures.all);
yield defaultName;
});
}
}
else if (!utils_1.identifierRegex.test(name)) {
yield (0, transform_1.replace)(statement.start, callExp.start, function* () {
yield `const ${defaultName} = `;
});
yield (0, transform_1.insert)(statement.end, function* () {
yield utils_1.endOfLine;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, statement.start, callExp.start, codeFeatures_1.codeFeatures.all);
yield defaultName;
});
}
}
function* generatePublicProps(options, ctx, scriptSetup, scriptSetupRanges) {
if (scriptSetupRanges.defineProps?.typeArg && scriptSetupRanges.withDefaults?.arg) {
yield `const ${names_1.names.defaults} = `;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, scriptSetupRanges.withDefaults.arg.start, scriptSetupRanges.withDefaults.arg.end, codeFeatures_1.codeFeatures.navigation);
yield utils_1.endOfLine;
}
const propTypes = [];
if (options.vueCompilerOptions.jsxSlots && hasSlotsType(options)) {
propTypes.push(`${ctx.localTypes.PropsChildren}<${names_1.names.Slots}>`);
}
if (scriptSetupRanges.defineProps?.typeArg) {
propTypes.push(names_1.names.Props);
}
if (scriptSetupRanges.defineModel.length) {
propTypes.push(names_1.names.ModelProps);
}
if (propTypes.length) {
yield `type ${names_1.names.PublicProps} = ${propTypes.join(` & `)}${utils_1.endOfLine}`;
ctx.generatedTypes.add(names_1.names.PublicProps);
}
}
function hasSlotsType(options) {
return !!(options.scriptSetupRanges?.defineSlots
|| options.templateAndStyleTypes.has(names_1.names.Slots));
}
function* generateModels(scriptSetup, scriptSetupRanges) {
if (!scriptSetupRanges.defineModel.length) {
return;
}
const defaultCodes = [];
const propCodes = [];
const emitCodes = [];
for (const defineModel of scriptSetupRanges.defineModel) {
const propName = defineModel.name
? (0, shared_1.camelize)(getRangeText(scriptSetup, defineModel.name).slice(1, -1))
: 'modelValue';
let modelType;
if (defineModel.type) {
// Infer from defineModel<T>
modelType = getRangeText(scriptSetup, defineModel.type);
}
else if (defineModel.runtimeType && defineModel.localName) {
// Infer from actual prop declaration code
modelType = `typeof ${getRangeText(scriptSetup, defineModel.localName)}['value']`;
}
else if (defineModel.defaultValue && propName) {
// Infer from defineModel({ default: T })
modelType = `typeof ${names_1.names.defaultModels}['${propName}']`;
}
else {
modelType = `any`;
}
if (defineModel.defaultValue) {
defaultCodes.push(`'${propName}': ${getRangeText(scriptSetup, defineModel.defaultValue)},${utils_1.newLine}`);
}
propCodes.push(generateModelProp(scriptSetup, defineModel, propName, modelType));
emitCodes.push(generateModelEmit(defineModel, propName, modelType));
}
if (defaultCodes.length) {
yield `const ${names_1.names.defaultModels} = {${utils_1.newLine}`;
yield* defaultCodes;
yield `}${utils_1.endOfLine}`;
}
yield `type ${names_1.names.ModelProps} = {${utils_1.newLine}`;
for (const codes of propCodes) {
yield* codes;
}
yield `}${utils_1.endOfLine}`;
yield `type ${names_1.names.ModelEmit} = {${utils_1.newLine}`;
for (const codes of emitCodes) {
yield* codes;
}
yield `}${utils_1.endOfLine}`;
// avoid `defineModel<...>()` to prevent JS AST issues
yield `let ${names_1.names.modelEmit}!: ${names_1.names.ShortEmits}<${names_1.names.ModelEmit}>${utils_1.endOfLine}`;
}
function* generateModelProp(scriptSetup, defineModel, propName, modelType) {
if (defineModel.comments) {
yield scriptSetup.content.slice(defineModel.comments.start, defineModel.comments.end);
yield utils_1.newLine;
}
if (defineModel.name) {
yield* (0, camelized_1.generateCamelized)(getRangeText(scriptSetup, defineModel.name), scriptSetup.name, defineModel.name.start, codeFeatures_1.codeFeatures.navigation);
}
else {
yield propName;
}
yield defineModel.required ? `: ` : `?: `;
yield modelType;
yield utils_1.endOfLine;
if (defineModel.modifierType) {
const modifierName = `${propName === 'modelValue' ? 'model' : propName}Modifiers`;
const modifierType = getRangeText(scriptSetup, defineModel.modifierType);
yield `'${modifierName}'?: Partial<Record<${modifierType}, true>>${utils_1.endOfLine}`;
}
}
function* generateModelEmit(defineModel, propName, modelType) {
yield `'update:${propName}': [value: `;
yield modelType;
if (!defineModel.required && !defineModel.defaultValue) {
yield ` | undefined`;
}
yield `]${utils_1.endOfLine}`;
}
function getRangeText(scriptSetup, range) {
return scriptSetup.content.slice(range.start, range.end);
}
//# sourceMappingURL=scriptSetup.js.map
+4
View File
@@ -0,0 +1,4 @@
import type { Code } from '../../types';
import type { ScriptCodegenContext } from './context';
import type { ScriptCodegenOptions } from './index';
export declare function generateTemplate(options: ScriptCodegenOptions, ctx: ScriptCodegenContext, selfType?: string): Generator<Code>;
+115
View File
@@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateTemplate = generateTemplate;
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const merge_1 = require("../utils/merge");
function* generateTemplate(options, ctx, selfType) {
yield* generateSetupExposed(options, ctx);
yield* generateTemplateCtx(options, ctx, selfType);
yield* generateTemplateComponents(options, ctx);
yield* generateTemplateDirectives(options, ctx);
if (options.templateAndStyleCodes.length) {
yield* options.templateAndStyleCodes;
}
}
function* generateTemplateCtx({ vueCompilerOptions, templateAndStyleTypes, scriptSetupRanges, fileName }, ctx, selfType) {
const exps = [];
const emitTypes = [];
const propTypes = [];
if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) {
exps.push(`globalThis`);
}
if (selfType) {
exps.push(`{} as InstanceType<${names_1.names.PickNotAny}<typeof ${selfType}, new () => {}>>`);
}
else {
exps.push(`{} as import('${vueCompilerOptions.lib}').ComponentPublicInstance`);
}
if (templateAndStyleTypes.has(names_1.names.StyleModules)) {
exps.push(`{} as ${names_1.names.StyleModules}`);
}
if (scriptSetupRanges?.defineEmits) {
emitTypes.push(`typeof ${scriptSetupRanges.defineEmits.name ?? names_1.names.emit}`);
}
if (scriptSetupRanges?.defineModel.length) {
emitTypes.push(`typeof ${names_1.names.modelEmit}`);
}
if (emitTypes.length) {
yield `type ${names_1.names.EmitProps} = ${names_1.names.EmitsToProps}<${names_1.names.NormalizeEmits}<${emitTypes.join(` & `)}>>${utils_1.endOfLine}`;
exps.push(`{} as { $emit: ${emitTypes.join(` & `)} }`);
}
if (scriptSetupRanges?.defineProps) {
propTypes.push(`typeof ${scriptSetupRanges.defineProps.name ?? names_1.names.props}`);
}
if (scriptSetupRanges?.defineModel.length) {
propTypes.push(names_1.names.ModelProps);
}
if (emitTypes.length) {
propTypes.push(names_1.names.EmitProps);
}
if (propTypes.length) {
exps.push(`{} as { $props: ${propTypes.join(` & `)} }`);
exps.push(`{} as ${propTypes.join(` & `)}`);
}
if (ctx.generatedTypes.has(names_1.names.SetupExposed)) {
exps.push(`{} as ${names_1.names.SetupExposed}`);
}
yield `const ${names_1.names.ctx} = `;
yield* (0, merge_1.generateSpreadMerge)(...exps);
yield utils_1.endOfLine;
}
function* generateTemplateComponents({ vueCompilerOptions, script, scriptRanges }, ctx) {
const types = [];
if (ctx.generatedTypes.has(names_1.names.SetupExposed)) {
types.push(names_1.names.SetupExposed);
}
if (script && scriptRanges?.exportDefault?.options?.components) {
const { components } = scriptRanges.exportDefault.options;
yield `const ${names_1.names.componentsOption} = `;
yield* (0, utils_1.generateSfcBlockSection)(script, components.start, components.end, codeFeatures_1.codeFeatures.navigation);
yield utils_1.endOfLine;
types.push(`typeof ${names_1.names.componentsOption}`);
}
yield `type ${names_1.names.LocalComponents} = ${types.length ? types.join(` & `) : `{}`}${utils_1.endOfLine}`;
yield `type ${names_1.names.GlobalComponents} = ${vueCompilerOptions.target >= 3.5
? `import('${vueCompilerOptions.lib}').GlobalComponents`
: `import('${vueCompilerOptions.lib}').GlobalComponents & Pick<typeof import('${vueCompilerOptions.lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>`}${utils_1.endOfLine}`;
yield `let ${names_1.names.components}!: ${names_1.names.LocalComponents} & ${names_1.names.GlobalComponents}${utils_1.endOfLine}`;
yield `let ${names_1.names.intrinsics}!: ${vueCompilerOptions.target >= 3.3
? `import('${vueCompilerOptions.lib}/jsx-runtime').JSX.IntrinsicElements`
: `globalThis.JSX.IntrinsicElements`}${utils_1.endOfLine}`;
}
function* generateTemplateDirectives({ vueCompilerOptions, script, scriptRanges }, ctx) {
const types = [];
if (ctx.generatedTypes.has(names_1.names.SetupExposed)) {
types.push(names_1.names.SetupExposed);
}
if (script && scriptRanges?.exportDefault?.options?.directives) {
const { directives } = scriptRanges.exportDefault.options;
yield `const ${names_1.names.directivesOption} = `;
yield* (0, utils_1.generateSfcBlockSection)(script, directives.start, directives.end, codeFeatures_1.codeFeatures.navigation);
yield utils_1.endOfLine;
types.push(`${names_1.names.ResolveDirectives}<typeof ${names_1.names.directivesOption}>`);
}
yield `type ${names_1.names.LocalDirectives} = ${types.length ? types.join(` & `) : `{}`}${utils_1.endOfLine}`;
yield `let ${names_1.names.directives}!: ${names_1.names.LocalDirectives} & import('${vueCompilerOptions.lib}').GlobalDirectives${utils_1.endOfLine}`;
}
function* generateSetupExposed({ vueCompilerOptions, exposed }, ctx) {
if (!exposed.size) {
return;
}
ctx.generatedTypes.add(names_1.names.SetupExposed);
yield `type ${names_1.names.SetupExposed} = import('${vueCompilerOptions.lib}').ShallowUnwrapRef<{${utils_1.newLine}`;
for (const bindingName of exposed) {
const token = Symbol(bindingName.length);
yield ['', undefined, 0, { __linkedToken: token }];
yield `${bindingName}: typeof `;
yield ['', undefined, 0, { __linkedToken: token }];
yield bindingName;
yield utils_1.endOfLine;
}
yield `}>${utils_1.endOfLine}`;
}
//# sourceMappingURL=template.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { Code, IRStyle } from '../../types';
export declare function generateClassProperty(source: string, classNameWithDot: string, offset: number, propertyType: string): Generator<Code>;
export declare function generateStyleImports(style: IRStyle): Generator<Code>;
+43
View File
@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateClassProperty = generateClassProperty;
exports.generateStyleImports = generateStyleImports;
const codeFeatures_1 = require("../codeFeatures");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
function* generateClassProperty(source, classNameWithDot, offset, propertyType) {
yield `${utils_1.newLine} & { `;
const token = yield* (0, boundary_1.startBoundary)(source, offset, codeFeatures_1.codeFeatures.navigation);
yield `'`;
yield [classNameWithDot.slice(1), source, offset + 1, { __combineToken: token }];
yield `'`;
yield (0, boundary_1.endBoundary)(token, offset + classNameWithDot.length);
yield `: ${propertyType}`;
yield ` }`;
}
function* generateStyleImports(style) {
const features = {
navigation: true,
verification: true,
};
if (typeof style.src === 'object') {
yield `${utils_1.newLine} & typeof import(`;
const token = yield* (0, boundary_1.startBoundary)('main', style.src.offset, features);
yield `'`;
yield [style.src.text, 'main', style.src.offset, { __combineToken: token }];
yield `'`;
yield (0, boundary_1.endBoundary)(token, style.src.offset + style.src.text.length);
yield `).default`;
}
for (const { text, offset } of style.imports) {
yield `${utils_1.newLine} & typeof import('`;
yield [
text,
style.name,
offset,
features,
];
yield `').default`;
}
}
//# sourceMappingURL=common.js.map
+60
View File
@@ -0,0 +1,60 @@
import type { Code, IRStyle, VueCompilerOptions } from '../../types';
export interface StyleCodegenOptions {
typescript: typeof import('typescript');
vueCompilerOptions: VueCompilerOptions;
styles: readonly IRStyle[];
setupRefs: Set<string>;
setupConsts: Set<string>;
}
export { generate as generateStyle };
declare function generate(options: StyleCodegenOptions): {
generatedTypes: Set<string>;
currentInfo: {
ignoreError?: boolean;
expectError?: {
token: number;
node: import("@vue/compiler-dom").CommentNode;
};
generic?: {
content: string;
offset: number;
};
};
resolveCodeFeatures: (features: import("../../types").VueCodeInformation) => import("../../types").VueCodeInformation;
inVFor: boolean;
slots: {
name: string;
offset?: number;
tagRange: [number, number];
nodeLoc: any;
propsVar: string;
}[];
dynamicSlots: {
expVar: string;
propsVar: string;
}[];
dollarVars: Set<string>;
componentAccessMap: Map<string, Map<string, Set<number>>>;
blockConditions: string[];
inlayHints: import("../inlayHints").InlayHintInfo[];
inheritedAttrVars: Set<string>;
templateRefs: Map<string, {
typeExp: string;
offset: number;
}[]>;
singleRootElTypes: Set<string>;
singleRootNodes: Set<import("@vue/compiler-dom").ElementNode | null>;
addTemplateRef(name: string, typeExp: string, offset: number): void;
recordComponentAccess(source: string, name: string, offset?: number): void;
scopes: Set<string>[];
components: (() => string)[];
declare(...varNames: string[]): void;
startScope(): () => Generator<Code, any, any>;
getInternalVariable(): string;
getHoistVariable(originalVar: string): string;
generateHoistVariables(): Generator<string, void, unknown>;
generateConditionGuards(): Generator<string, void, unknown>;
enter(node: import("@vue/compiler-dom").RootNode | import("@vue/compiler-dom").TemplateChildNode | import("@vue/compiler-dom").SimpleExpressionNode): boolean;
exit(): Generator<Code>;
codes: Code[];
};
+38
View File
@@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateStyle = generate;
const codeFeatures_1 = require("../codeFeatures");
const modules_1 = require("../style/modules");
const scopedClasses_1 = require("../style/scopedClasses");
const context_1 = require("../template/context");
const interpolation_1 = require("../template/interpolation");
const utils_1 = require("../utils");
function generate(options) {
const ctx = (0, context_1.createTemplateCodegenContext)();
const codeGenerator = generateWorker(options, ctx);
const codes = [];
for (const code of codeGenerator) {
if (typeof code === 'object') {
code[3] = ctx.resolveCodeFeatures(code[3]);
}
codes.push(code);
}
return { ...ctx, codes };
}
function* generateWorker(options, ctx) {
const endScope = ctx.startScope();
ctx.declare(...options.setupConsts);
yield* (0, scopedClasses_1.generateStyleScopedClasses)(options);
yield* (0, modules_1.generateStyleModules)(options, ctx);
yield* generateCssVars(options, ctx);
yield* endScope();
}
function* generateCssVars(options, ctx) {
for (const style of options.styles) {
for (const binding of style.bindings) {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, style, codeFeatures_1.codeFeatures.all, binding.text, binding.offset, `(`, `)`);
yield utils_1.endOfLine;
}
}
}
//# sourceMappingURL=index.js.map
+4
View File
@@ -0,0 +1,4 @@
import type { Code } from '../../types';
import type { TemplateCodegenContext } from '../template/context';
import type { StyleCodegenOptions } from '.';
export declare function generateStyleModules({ styles, vueCompilerOptions }: StyleCodegenOptions, ctx: TemplateCodegenContext): Generator<Code>;
+43
View File
@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateStyleModules = generateStyleModules;
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const common_1 = require("./common");
function* generateStyleModules({ styles, vueCompilerOptions }, ctx) {
const styleModules = styles.filter(style => style.module);
if (!styleModules.length) {
return;
}
ctx.generatedTypes.add(names_1.names.StyleModules);
yield `type ${names_1.names.StyleModules} = {${utils_1.newLine}`;
for (const style of styleModules) {
if (style.module === true) {
yield `$style`;
}
else {
const { text, offset } = style.module;
yield [
text,
'main',
offset,
codeFeatures_1.codeFeatures.navigation,
];
}
yield `: `;
if (!vueCompilerOptions.strictCssModules) {
yield `Record<string, string> & `;
}
yield `${names_1.names.PrettifyGlobal}<{}`;
if (vueCompilerOptions.resolveStyleImports) {
yield* (0, common_1.generateStyleImports)(style);
}
for (const className of style.classNames) {
yield* (0, common_1.generateClassProperty)(style.name, className.text, className.offset, 'string');
}
yield `>${utils_1.endOfLine}`;
}
yield `}${utils_1.endOfLine}`;
}
//# sourceMappingURL=modules.js.map
@@ -0,0 +1,3 @@
import type { Code } from '../../types';
import type { StyleCodegenOptions } from '.';
export declare function generateStyleScopedClasses({ vueCompilerOptions, styles }: StyleCodegenOptions): Generator<Code>;
+39
View File
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateStyleScopedClasses = generateStyleScopedClasses;
const names_1 = require("../names");
const styleScopedClasses_1 = require("../template/styleScopedClasses");
const utils_1 = require("../utils");
const common_1 = require("./common");
function* generateStyleScopedClasses({ vueCompilerOptions, styles }) {
const { resolveStyleClassNames, resolveStyleImports } = vueCompilerOptions;
if (!resolveStyleClassNames) {
return;
}
const scopedStyles = styles.filter(style => resolveStyleClassNames === true || style.scoped);
if (!scopedStyles.length) {
return;
}
const visited = new Set();
const deferredGenerations = [];
yield `type ${names_1.names.StyleScopedClasses} = {}`;
for (const style of scopedStyles) {
if (resolveStyleImports) {
yield* (0, common_1.generateStyleImports)(style);
}
for (const className of style.classNames) {
if (!visited.has(className.text)) {
visited.add(className.text);
yield* (0, common_1.generateClassProperty)(style.name, className.text, className.offset, 'boolean');
}
else {
deferredGenerations.push((0, styleScopedClasses_1.generateStyleScopedClassReference)(style, className.text.slice(1), className.offset + 1));
}
}
}
yield utils_1.endOfLine;
for (const generate of deferredGenerations) {
yield* generate;
}
}
//# sourceMappingURL=scopedClasses.js.map
+151
View File
@@ -0,0 +1,151 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code, VueCodeInformation } from '../../types';
import type { InlayHintInfo } from '../inlayHints';
export type TemplateCodegenContext = ReturnType<typeof createTemplateCodegenContext>;
/**
* Creates and returns a Context object used for generating type-checkable TS code
* from the template section of a .vue file.
*
* ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives.
*
* Vue language tooling supports a number of directives for suppressing diagnostics within
* Vue templates (https://github.com/vuejs/language-tools/pull/3215)
*
* Here is an overview for how support for how @vue-expect-error is implemented within this file
* (@vue-expect-error is the most complicated directive to support due to its behavior of raising
* a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics).
*
* Given .vue code:
*
* ```vue
* <script setup lang="ts">
* defineProps<{
* knownProp1: string;
* knownProp2: string;
* knownProp3: string;
* knownProp4_will_trigger_unused_expect_error: string;
* }>();
* </script>
*
* <template>
* {{ knownProp1 }}
* {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] -->
* {{ knownProp2 }}
* <!-- @vue-expect-error This suppresses an Unknown Property Error -->
* {{ suppressed_error_unknownProp }}
* {{ knownProp3 }}
* <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) -->
* {{ knownProp4_will_trigger_unused_expect_error }}
* </template>
* ```
*
* The above code should raise two diagnostics:
*
* 1. Property 'error_unknownProp' does not exist on type [...]
* 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive
* that covers code that doesn't actually raise an error -- note that all `@vue-...` directives
* will ultimately translate into `@ts-...` diagnostics.
*
* The above code will produce the following type-checkable TS code (note: omitting asterisks
* to prevent VSCode syntax double-greying out double-commented code).
*
* ```ts
* ( __VLS_ctx.knownProp1 );
* ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...]
* ( __VLS_ctx.knownProp2 );
* // @vue-expect-error start
* ( __VLS_ctx.suppressed_error_unknownProp );
* // @ts-expect-error __VLS_TS_EXPECT_ERROR
* ;
* // @vue-expect-error end of INTERPOLATION
* ( __VLS_ctx.knownProp3 );
* // @vue-expect-error start
* ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error );
* // @ts-expect-error __VLS_TS_EXPECT_ERROR
* ;
* // @vue-expect-error end of INTERPOLATION
* ```
*
* In the generated code, there are actually 3 diagnostic errors that'll be raised in the first
* pass on this generated code (but through cleverness described below, not all of them will be
* propagated back to the original .vue file):
*
* 1. Property 'error_unknownProp' does not exist on type [...]
* 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR`
* 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR`
*
* Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`;
* Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`;
* any `@vue-` prefixed directives in the comments are only for debugging purposes.
*
* As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but
* only 2 should be propagated back to the original .vue file.
*
* (The reason we structure things this way is somewhat complicated, but in short it allows us
* to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors
* while covering a number of edge cases.)
*
* So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR`
* directives should be reported as an unused directive or not.
*
* To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the
* `verification` property of the `CodeInformation` object attached to the mapping between source .vue
* and generated .ts code. The `verification` property determines whether "verification" (which includes
* semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided,
* can be used to determine whether a given diagnostic should be reported back "upwards" to the original
* .vue file or not.
*
* See the comments in the code below for how and where we use this hook to keep track of whether
* an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive,
* and additionally how we use that to determine whether to propagate diagnostics back upward.
*/
export declare function createTemplateCodegenContext(): {
generatedTypes: Set<string>;
readonly currentInfo: {
ignoreError?: boolean;
expectError?: {
token: number;
node: CompilerDOM.CommentNode;
};
generic?: {
content: string;
offset: number;
};
};
resolveCodeFeatures: (features: VueCodeInformation) => VueCodeInformation;
inVFor: boolean;
slots: {
name: string;
offset?: number;
tagRange: [number, number];
nodeLoc: any;
propsVar: string;
}[];
dynamicSlots: {
expVar: string;
propsVar: string;
}[];
dollarVars: Set<string>;
componentAccessMap: Map<string, Map<string, Set<number>>>;
blockConditions: string[];
inlayHints: InlayHintInfo[];
inheritedAttrVars: Set<string>;
templateRefs: Map<string, {
typeExp: string;
offset: number;
}[]>;
singleRootElTypes: Set<string>;
singleRootNodes: Set<CompilerDOM.ElementNode | null>;
addTemplateRef(name: string, typeExp: string, offset: number): void;
recordComponentAccess(source: string, name: string, offset?: number): void;
scopes: Set<string>[];
components: (() => string)[];
declare(...varNames: string[]): void;
startScope(): () => Generator<Code, any, any>;
getInternalVariable(): string;
getHoistVariable(originalVar: string): string;
generateHoistVariables(): Generator<string, void, unknown>;
generateConditionGuards(): Generator<string, void, unknown>;
enter(node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode | CompilerDOM.SimpleExpressionNode): boolean;
exit(): Generator<Code>;
};
+346
View File
@@ -0,0 +1,346 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTemplateCodegenContext = createTemplateCodegenContext;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const codeFeatures_1 = require("../codeFeatures");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const commentDirectiveRegex = /^<!--\s*@vue-(?<name>[-\w]+)\b(?<content>[\s\S]*)-->$/;
/**
* Creates and returns a Context object used for generating type-checkable TS code
* from the template section of a .vue file.
*
* ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives.
*
* Vue language tooling supports a number of directives for suppressing diagnostics within
* Vue templates (https://github.com/vuejs/language-tools/pull/3215)
*
* Here is an overview for how support for how @vue-expect-error is implemented within this file
* (@vue-expect-error is the most complicated directive to support due to its behavior of raising
* a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics).
*
* Given .vue code:
*
* ```vue
* <script setup lang="ts">
* defineProps<{
* knownProp1: string;
* knownProp2: string;
* knownProp3: string;
* knownProp4_will_trigger_unused_expect_error: string;
* }>();
* </script>
*
* <template>
* {{ knownProp1 }}
* {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] -->
* {{ knownProp2 }}
* <!-- @vue-expect-error This suppresses an Unknown Property Error -->
* {{ suppressed_error_unknownProp }}
* {{ knownProp3 }}
* <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) -->
* {{ knownProp4_will_trigger_unused_expect_error }}
* </template>
* ```
*
* The above code should raise two diagnostics:
*
* 1. Property 'error_unknownProp' does not exist on type [...]
* 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive
* that covers code that doesn't actually raise an error -- note that all `@vue-...` directives
* will ultimately translate into `@ts-...` diagnostics.
*
* The above code will produce the following type-checkable TS code (note: omitting asterisks
* to prevent VSCode syntax double-greying out double-commented code).
*
* ```ts
* ( __VLS_ctx.knownProp1 );
* ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...]
* ( __VLS_ctx.knownProp2 );
* // @vue-expect-error start
* ( __VLS_ctx.suppressed_error_unknownProp );
* // @ts-expect-error __VLS_TS_EXPECT_ERROR
* ;
* // @vue-expect-error end of INTERPOLATION
* ( __VLS_ctx.knownProp3 );
* // @vue-expect-error start
* ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error );
* // @ts-expect-error __VLS_TS_EXPECT_ERROR
* ;
* // @vue-expect-error end of INTERPOLATION
* ```
*
* In the generated code, there are actually 3 diagnostic errors that'll be raised in the first
* pass on this generated code (but through cleverness described below, not all of them will be
* propagated back to the original .vue file):
*
* 1. Property 'error_unknownProp' does not exist on type [...]
* 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR`
* 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR`
*
* Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`;
* Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`;
* any `@vue-` prefixed directives in the comments are only for debugging purposes.
*
* As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but
* only 2 should be propagated back to the original .vue file.
*
* (The reason we structure things this way is somewhat complicated, but in short it allows us
* to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors
* while covering a number of edge cases.)
*
* So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR`
* directives should be reported as an unused directive or not.
*
* To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the
* `verification` property of the `CodeInformation` object attached to the mapping between source .vue
* and generated .ts code. The `verification` property determines whether "verification" (which includes
* semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided,
* can be used to determine whether a given diagnostic should be reported back "upwards" to the original
* .vue file or not.
*
* See the comments in the code below for how and where we use this hook to keep track of whether
* an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive,
* and additionally how we use that to determine whether to propagate diagnostics back upward.
*/
function createTemplateCodegenContext() {
let variableId = 0;
const scopes = [];
const components = [];
const hoistVars = new Map();
const dollarVars = new Set();
const componentAccessMap = new Map();
const slots = [];
const dynamicSlots = [];
const blockConditions = [];
const inlayHints = [];
const inheritedAttrVars = new Set();
const templateRefs = new Map();
const stack = [];
const commentBuffer = [];
return {
generatedTypes: new Set(),
get currentInfo() {
return stack[stack.length - 1];
},
resolveCodeFeatures,
inVFor: false,
slots,
dynamicSlots,
dollarVars,
componentAccessMap,
blockConditions,
inlayHints,
inheritedAttrVars,
templateRefs,
singleRootElTypes: new Set(),
singleRootNodes: new Set(),
addTemplateRef(name, typeExp, offset) {
let refs = templateRefs.get(name);
if (!refs) {
templateRefs.set(name, refs = []);
}
refs.push({ typeExp, offset });
},
recordComponentAccess(source, name, offset) {
let map = componentAccessMap.get(name);
if (!map) {
componentAccessMap.set(name, map = new Map());
}
let arr = map.get(source);
if (!arr) {
map.set(source, arr = new Set());
}
if (offset !== undefined) {
arr.add(offset);
}
},
scopes,
components,
declare(...varNames) {
const scope = scopes.at(-1);
for (const varName of varNames) {
scope.add(varName);
}
},
startScope() {
const scope = new Set();
scopes.push(scope);
return () => {
scopes.pop();
return generateAutoImport();
};
},
getInternalVariable() {
return `__VLS_${variableId++}`;
},
getHoistVariable(originalVar) {
let name = hoistVars.get(originalVar);
if (name === undefined) {
hoistVars.set(originalVar, name = `__VLS_${variableId++}`);
}
return name;
},
*generateHoistVariables() {
// trick to avoid TS 4081 (#5186)
if (hoistVars.size) {
yield `// @ts-ignore${utils_1.newLine}`;
yield `var `;
for (const [originalVar, hoistVar] of hoistVars) {
yield `${hoistVar} = ${originalVar}, `;
}
yield utils_1.endOfLine;
}
},
*generateConditionGuards() {
for (const condition of blockConditions) {
yield `if (!${condition}) return${utils_1.endOfLine}`;
}
},
enter(node) {
if (node.type === CompilerDOM.NodeTypes.COMMENT) {
commentBuffer.push(node);
return false;
}
const data = {};
const comments = [...commentBuffer];
commentBuffer.length = 0;
for (const comment of comments) {
const match = comment.loc.source.match(commentDirectiveRegex);
if (match) {
const { name, content } = match.groups;
switch (name) {
case 'skip': {
return false;
}
case 'ignore': {
data.ignoreError = true;
break;
}
case 'expect-error': {
data.expectError = {
token: 0,
node: comment,
};
break;
}
case 'generic': {
const text = content.trim();
if (text.startsWith('{') && text.endsWith('}')) {
data.generic = {
content: text.slice(1, -1),
offset: comment.loc.start.offset + comment.loc.source.indexOf('{') + 1,
};
}
break;
}
}
}
}
stack.push(data);
return true;
},
*exit() {
const data = stack.pop();
commentBuffer.length = 0;
if (data.expectError !== undefined) {
const token = yield* (0, boundary_1.startBoundary)('template', data.expectError.node.loc.start.offset, {
verification: {
// If no errors/warnings/diagnostics were reported within the region of code covered
// by the @vue-expect-error directive, then we should allow any `unused @ts-expect-error`
// diagnostics to be reported upward.
shouldReport: () => data.expectError.token === 0,
},
});
yield `// @ts-expect-error`;
yield (0, boundary_1.endBoundary)(token, data.expectError.node.loc.end.offset);
yield `${utils_1.newLine}${utils_1.endOfLine}`;
}
},
};
function* generateAutoImport() {
const all = [...componentAccessMap.entries()];
if (!all.some(([, offsets]) => offsets.size)) {
return;
}
yield `// @ts-ignore${utils_1.newLine}`; // #2304
yield `[`;
for (const [varName, map] of all) {
for (const [source, offsets] of map) {
for (const offset of offsets) {
yield [varName, source, offset, codeFeatures_1.codeFeatures.importCompletionOnly];
yield `,`;
}
offsets.clear();
}
}
yield `]${utils_1.endOfLine}`;
}
function resolveCodeFeatures(features) {
if (features.verification && stack.length) {
const data = stack[stack.length - 1];
if (data.ignoreError) {
// We are currently in a region of code covered by a @vue-ignore directive, so don't
// even bother performing any type-checking: set verification to false.
return {
...features,
verification: false,
};
}
if (data.expectError !== undefined) {
// We are currently in a region of code covered by a @vue-expect-error directive. We need to
// keep track of the number of errors encountered within this region so that we can know whether
// we will need to propagate an "unused ts-expect-error" diagnostic back to the original
// .vue file or not.
return {
...features,
verification: {
shouldReport: (source, code) => {
if (typeof features.verification !== 'object'
|| !features.verification.shouldReport
|| features.verification.shouldReport(source, code) === true) {
data.expectError.token++;
}
return false;
},
},
};
}
}
return features;
}
}
//# sourceMappingURL=context.js.map
@@ -0,0 +1,7 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateComponent(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>;
export declare function generateElement(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>;
export declare function generateFragment(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>;
+405
View File
@@ -0,0 +1,405 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateComponent = generateComponent;
exports.generateElement = generateElement;
exports.generateFragment = generateFragment;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("@vue/shared");
const muggle_string_1 = require("muggle-string");
const shared_2 = require("../../utils/shared");
const codeFeatures_1 = require("../codeFeatures");
const inlayHints_1 = require("../inlayHints");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const camelized_1 = require("../utils/camelized");
const stringLiteralKey_1 = require("../utils/stringLiteralKey");
const elementDirectives_1 = require("./elementDirectives");
const elementEvents_1 = require("./elementEvents");
const elementProps_1 = require("./elementProps");
const interpolation_1 = require("./interpolation");
const propertyAccess_1 = require("./propertyAccess");
const styleScopedClasses_1 = require("./styleScopedClasses");
const templateChild_1 = require("./templateChild");
const vSlot_1 = require("./vSlot");
function* generateComponent(options, ctx, node) {
let { tag, props } = node;
let [startTagOffset, endTagOffset] = (0, shared_2.getElementTagOffsets)(node, options.template);
let isExpression = false;
let isIsShorthand = false;
if (tag.includes('.')) {
isExpression = true;
}
else if (tag === 'component') {
for (const prop of node.props) {
if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& prop.name === 'bind'
&& prop.arg?.loc.source === 'is'
&& prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
isIsShorthand = prop.arg.loc.end.offset === prop.exp.loc.end.offset;
if (isIsShorthand) {
ctx.inlayHints.push((0, inlayHints_1.createVBindShorthandInlayHintInfo)(prop.exp.loc, 'is'));
}
isExpression = true;
tag = prop.exp.content;
startTagOffset = prop.exp.loc.start.offset;
endTagOffset = undefined;
props = props.filter(p => p !== prop);
break;
}
}
}
const componentVar = ctx.getInternalVariable();
if (isExpression) {
yield `const ${componentVar} = `;
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, isIsShorthand
? codeFeatures_1.codeFeatures.withoutHighlightAndCompletion
: codeFeatures_1.codeFeatures.all, tag, startTagOffset, `(`, `)`);
if (endTagOffset !== undefined) {
yield ` || `;
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.withoutCompletion, tag, endTagOffset, `(`, `)`);
}
yield `${utils_1.endOfLine}`;
}
else {
const originalNames = new Set([
(0, shared_1.capitalize)((0, shared_1.camelize)(tag)),
(0, shared_1.camelize)(tag),
tag,
]);
const matchedSetupConst = [...originalNames].find(name => options.setupConsts.has(name));
if (matchedSetupConst) {
// navigation & auto import support
yield `const ${componentVar} = `;
yield* (0, camelized_1.generateCamelized)(matchedSetupConst[0] + tag.slice(1), 'template', startTagOffset, {
...codeFeatures_1.codeFeatures.withoutHighlightAndCompletion,
...codeFeatures_1.codeFeatures.importCompletionOnly,
});
if (endTagOffset !== undefined) {
yield ` || `;
yield* (0, camelized_1.generateCamelized)(matchedSetupConst[0] + tag.slice(1), 'template', endTagOffset, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
}
yield utils_1.endOfLine;
}
else {
yield `let ${componentVar}!: ${names_1.names.WithComponent}<'${tag}', ${names_1.names.LocalComponents}, ${names_1.names.GlobalComponents}`;
yield originalNames.has(options.componentName)
? `, typeof ${names_1.names.export}`
: `, void`;
for (const name of originalNames) {
yield `, '${name}'`;
}
yield `>[`;
yield* (0, stringLiteralKey_1.generateStringLiteralKey)(tag, startTagOffset, {
...codeFeatures_1.codeFeatures.semanticWithoutHighlight,
...options.vueCompilerOptions.checkUnknownComponents
? codeFeatures_1.codeFeatures.verification
: codeFeatures_1.codeFeatures.doNotReportTs2339AndTs2551,
});
yield `]${utils_1.endOfLine}`;
if (utils_1.identifierRegex.test((0, shared_1.camelize)(tag))) {
// navigation support
yield `/** @ts-ignore @type {`;
for (const offset of [startTagOffset, endTagOffset]) {
if (offset === undefined) {
continue;
}
yield ` | typeof ${names_1.names.components}.`;
yield* (0, camelized_1.generateCamelized)(tag, 'template', offset, codeFeatures_1.codeFeatures.navigation);
if (tag[0] !== tag[0].toUpperCase()) {
yield ` | typeof ${names_1.names.components}.`;
yield* (0, camelized_1.generateCamelized)((0, shared_1.capitalize)(tag), 'template', offset, codeFeatures_1.codeFeatures.navigation);
}
if (tag.includes('-')) {
yield ` | typeof ${names_1.names.components}[`;
yield* (0, stringLiteralKey_1.generateStringLiteralKey)(tag, offset, codeFeatures_1.codeFeatures.navigation);
yield `]`;
}
}
yield `} */${utils_1.newLine}`;
// auto import support
yield* (0, camelized_1.generateCamelized)(tag, 'template', startTagOffset, codeFeatures_1.codeFeatures.importCompletionOnly);
yield utils_1.endOfLine;
}
}
}
let isCtxVarUsed = false;
let isPropsVarUsed = false;
const getCtxVar = () => (isCtxVarUsed = true, ctxVar);
const getPropsVar = () => (isPropsVarUsed = true, propsVar);
ctx.components.push(getCtxVar);
const functionalVar = ctx.getInternalVariable();
const vnodeVar = ctx.getInternalVariable();
const ctxVar = ctx.getInternalVariable();
const propsVar = ctx.getInternalVariable();
const failedPropExps = [];
const propCodes = [...(0, elementProps_1.generateElementProps)(options, ctx, node, props, options.vueCompilerOptions.checkUnknownProps, failedPropExps)];
const propsStr = (0, muggle_string_1.toString)(propCodes);
yield `// @ts-ignore${utils_1.newLine}`;
yield `const ${functionalVar} = ${options.vueCompilerOptions.checkUnknownProps ? names_1.names.asFunctionalComponent0 : names_1.names.asFunctionalComponent1}(${componentVar}, new ${componentVar}({${utils_1.newLine}`;
yield propsStr;
yield `}))${utils_1.endOfLine}`;
yield `const `;
const token = yield* (0, boundary_1.startBoundary)('template', node.loc.start.offset, codeFeatures_1.codeFeatures.doNotReportTs6133);
yield vnodeVar;
yield (0, boundary_1.endBoundary)(token, node.loc.end.offset);
yield ` = ${functionalVar}`;
if (ctx.currentInfo.generic) {
const { content, offset } = ctx.currentInfo.generic;
const token = yield* (0, boundary_1.startBoundary)('template', offset, codeFeatures_1.codeFeatures.verification);
yield `<`;
yield [content, 'template', offset, codeFeatures_1.codeFeatures.all];
yield `>`;
yield (0, boundary_1.endBoundary)(token, offset + content.length);
}
const shouldInheritAttrs = hasVBindAttrs(options, ctx, node);
yield `(`;
const token2 = yield* (0, boundary_1.startBoundary)('template', startTagOffset, shouldInheritAttrs && options.vueCompilerOptions.checkRequiredFallthroughAttributes
? {}
: codeFeatures_1.codeFeatures.verification);
yield `{`;
yield [``, 'template', node.loc.start.offset, { __propsCompletion: true }];
yield utils_1.newLine;
yield* propCodes;
yield `}`;
yield (0, boundary_1.endBoundary)(token2, startTagOffset + tag.length);
yield `, ...${names_1.names.functionalComponentArgsRest}(${functionalVar}))${utils_1.endOfLine}`;
yield* generateFailedExpressions(options, ctx, failedPropExps);
yield* (0, elementEvents_1.generateElementEvents)(options, ctx, node, componentVar, getCtxVar, getPropsVar);
yield* (0, elementDirectives_1.generateElementDirectives)(options, ctx, node);
const templateRef = getTemplateRef(node);
const isSingleRoot = ctx.singleRootNodes.has(node)
&& !options.vueCompilerOptions.fallthroughComponentNames.includes((0, shared_2.hyphenateTag)(tag));
if (templateRef || isSingleRoot) {
const componentInstanceVar = ctx.getInternalVariable();
yield `var ${componentInstanceVar}!: Parameters<NonNullable<typeof ${getCtxVar()}['expose']>>[0]`;
yield utils_1.endOfLine;
if (templateRef) {
let typeExp = `typeof ${ctx.getHoistVariable(componentInstanceVar)} | null`;
if (ctx.inVFor) {
typeExp = `(${typeExp})[]`;
}
ctx.addTemplateRef(templateRef[0], typeExp, templateRef[1]);
}
if (isSingleRoot) {
ctx.singleRootElTypes.add(`NonNullable<typeof ${componentInstanceVar}>['$el']`);
}
}
if (shouldInheritAttrs) {
if (options.vueCompilerOptions.checkRequiredFallthroughAttributes) {
const restsVar = ctx.getInternalVariable();
yield `var ${restsVar} = ${names_1.names.omit}(${getPropsVar()}, {\n${propsStr}})${utils_1.endOfLine}`;
ctx.inheritedAttrVars.add(restsVar);
}
else {
ctx.inheritedAttrVars.add(getPropsVar());
}
}
yield* generateStyleScopedClassReferences(options, node);
const slotDir = node.props.find(CompilerDOM.isVSlot);
if (slotDir || node.children.length) {
yield* (0, vSlot_1.generateVSlot)(options, ctx, node, slotDir, getCtxVar());
}
if (isCtxVarUsed) {
yield `var ${ctxVar}!: ${names_1.names.FunctionalComponentCtx}<typeof ${componentVar}, typeof ${vnodeVar}>${utils_1.endOfLine}`;
}
if (isPropsVarUsed) {
yield `var ${propsVar}!: ${names_1.names.FunctionalComponentProps}<typeof ${componentVar}, typeof ${vnodeVar}>${utils_1.endOfLine}`;
}
ctx.components.pop();
}
function* generateElement(options, ctx, node) {
const [startTagOffset, endTagOffset] = (0, shared_2.getElementTagOffsets)(node, options.template);
const failedPropExps = [];
yield `${options.vueCompilerOptions.checkUnknownProps ? names_1.names.asFunctionalElement0 : names_1.names.asFunctionalElement1}(${names_1.names.intrinsics}`;
yield* (0, propertyAccess_1.generatePropertyAccess)(options, ctx, node.tag, startTagOffset, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
if (endTagOffset !== undefined) {
yield `, `;
yield names_1.names.intrinsics;
yield* (0, propertyAccess_1.generatePropertyAccess)(options, ctx, node.tag, endTagOffset, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
}
yield `)(`;
const token = yield* (0, boundary_1.startBoundary)('template', startTagOffset, codeFeatures_1.codeFeatures.verification);
yield `{${utils_1.newLine}`;
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, node.props, options.vueCompilerOptions.checkUnknownProps, failedPropExps);
yield `}`;
yield (0, boundary_1.endBoundary)(token, startTagOffset + node.tag.length);
yield `)${utils_1.endOfLine}`;
yield* generateFailedExpressions(options, ctx, failedPropExps);
yield* (0, elementDirectives_1.generateElementDirectives)(options, ctx, node);
const templateRef = getTemplateRef(node);
if (templateRef) {
let typeExp = `${names_1.names.Elements}['${node.tag}']`;
if (ctx.inVFor) {
typeExp += `[]`;
}
ctx.addTemplateRef(templateRef[0], typeExp, templateRef[1]);
}
if (ctx.singleRootNodes.has(node)) {
ctx.singleRootElTypes.add(`${names_1.names.Elements}['${node.tag}']`);
}
if (hasVBindAttrs(options, ctx, node)) {
ctx.inheritedAttrVars.add(`${names_1.names.intrinsics}.${node.tag}`);
}
yield* generateStyleScopedClassReferences(options, node);
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child);
}
}
function* generateFragment(options, ctx, node) {
const [startTagOffset] = (0, shared_2.getElementTagOffsets)(node, options.template);
// special case for <template v-for="..." :key="..." />
if (node.props.length) {
yield `__VLS_asFunctionalElement(__VLS_intrinsics.template)(`;
const token = yield* (0, boundary_1.startBoundary)('template', startTagOffset, codeFeatures_1.codeFeatures.verification);
yield `{${utils_1.newLine}`;
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, node.props, options.vueCompilerOptions.checkUnknownProps);
yield `}`;
yield (0, boundary_1.endBoundary)(token, startTagOffset + node.tag.length);
yield `)${utils_1.endOfLine}`;
}
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child);
}
}
function* generateStyleScopedClassReferences({ template, typescript: ts }, node) {
for (const prop of node.props) {
if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE
&& prop.name === 'class'
&& prop.value) {
const [text, start] = (0, shared_2.normalizeAttributeValue)(prop.value);
for (const [className, offset] of forEachClassName(text)) {
yield* (0, styleScopedClasses_1.generateStyleScopedClassReference)(template, className, start + offset);
}
}
else if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
&& prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
&& prop.arg.content === 'class') {
const content = '(' + prop.exp.content + ')';
const startOffset = prop.exp.loc.start.offset - 1;
const ast = (0, utils_1.getTypeScriptAST)(ts, template, content);
const literals = [];
for (const node of (0, utils_1.forEachNode)(ts, ast)) {
if (!ts.isExpressionStatement(node)
|| !ts.isParenthesizedExpression(node.expression)) {
continue;
}
const { expression } = node.expression;
if (ts.isStringLiteralLike(expression)) {
literals.push(expression);
}
else if (ts.isArrayLiteralExpression(expression)) {
yield* walkArrayLiteral(expression);
}
else if (ts.isObjectLiteralExpression(expression)) {
yield* walkObjectLiteral(expression);
}
}
for (const literal of literals) {
const start = literal.end - literal.text.length - 1 + startOffset;
for (const [className, offset] of forEachClassName(literal.text)) {
yield* (0, styleScopedClasses_1.generateStyleScopedClassReference)(template, className, start + offset);
}
}
function* walkArrayLiteral(node) {
const { elements } = node;
for (const element of elements) {
if (ts.isStringLiteralLike(element)) {
literals.push(element);
}
else if (ts.isObjectLiteralExpression(element)) {
yield* walkObjectLiteral(element);
}
}
}
function* walkObjectLiteral(node) {
const { properties } = node;
for (const property of properties) {
if (ts.isPropertyAssignment(property)) {
const { name } = property;
if (ts.isIdentifier(name)) {
const text = (0, shared_2.getNodeText)(ts, name, ast);
yield* (0, styleScopedClasses_1.generateStyleScopedClassReference)(template, text, name.end - text.length + startOffset);
}
else if (ts.isStringLiteral(name)) {
literals.push(name);
}
else if (ts.isComputedPropertyName(name)) {
const { expression } = name;
if (ts.isStringLiteralLike(expression)) {
literals.push(expression);
}
}
}
else if (ts.isShorthandPropertyAssignment(property)) {
const text = (0, shared_2.getNodeText)(ts, property.name, ast);
yield* (0, styleScopedClasses_1.generateStyleScopedClassReference)(template, text, property.name.end - text.length + startOffset);
}
}
}
}
}
}
function* forEachClassName(content) {
let offset = 0;
for (const className of content.split(' ')) {
yield [className, offset];
offset += className.length + 1;
}
}
function* generateFailedExpressions(options, ctx, failedPropExps) {
for (const { node, prefix, suffix } of failedPropExps) {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, node.loc.source, node.loc.start.offset, prefix, suffix);
yield utils_1.endOfLine;
}
}
function getTemplateRef(node) {
for (const prop of node.props) {
if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE
&& prop.name === 'ref'
&& prop.value) {
return (0, shared_2.normalizeAttributeValue)(prop.value);
}
}
}
function hasVBindAttrs(options, ctx, node) {
return options.vueCompilerOptions.fallthroughAttributes && ((options.inheritAttrs && ctx.singleRootNodes.has(node))
|| node.props.some(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& prop.name === 'bind'
&& prop.exp?.loc.source === '$attrs'));
}
//# sourceMappingURL=element.js.map
@@ -0,0 +1,6 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateElementDirectives(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>;
export declare function generateModifiers(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode, propertyName?: string): Generator<Code>;
@@ -0,0 +1,131 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateElementDirectives = generateElementDirectives;
exports.generateModifiers = generateModifiers;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("@vue/shared");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const camelized_1 = require("../utils/camelized");
const stringLiteralKey_1 = require("../utils/stringLiteralKey");
const elementProps_1 = require("./elementProps");
const interpolation_1 = require("./interpolation");
const objectProperty_1 = require("./objectProperty");
function* generateElementDirectives(options, ctx, node) {
for (const prop of node.props) {
if (prop.type !== CompilerDOM.NodeTypes.DIRECTIVE
|| prop.name === 'slot'
|| prop.name === 'on'
|| prop.name === 'model'
|| prop.name === 'bind') {
continue;
}
const token = yield* (0, boundary_1.startBoundary)('template', prop.loc.start.offset, codeFeatures_1.codeFeatures.verification);
yield `${names_1.names.asFunctionalDirective}(`;
yield* generateIdentifier(options, ctx, prop);
yield `, {} as import('${options.vueCompilerOptions.lib}').ObjectDirective)(null!, { ...${names_1.names.directiveBindingRestFields}, `;
yield* generateArg(options, ctx, prop);
yield* generateModifiers(options, ctx, prop);
yield* generateValue(options, ctx, prop);
yield ` }, null!, null!)`;
yield (0, boundary_1.endBoundary)(token, prop.loc.end.offset);
yield utils_1.endOfLine;
}
}
function* generateIdentifier(options, ctx, prop) {
const rawName = 'v-' + prop.name;
const startOffset = prop.loc.start.offset;
const token = yield* (0, boundary_1.startBoundary)('template', startOffset, codeFeatures_1.codeFeatures.verification);
yield names_1.names.directives;
yield `.`;
yield* (0, camelized_1.generateCamelized)(rawName, 'template', prop.loc.start.offset, {
...codeFeatures_1.codeFeatures.withoutHighlightAndCompletion,
verification: options.vueCompilerOptions.checkUnknownDirectives && !(0, shared_1.isBuiltInDirective)(prop.name),
});
if (!(0, shared_1.isBuiltInDirective)(prop.name)) {
ctx.recordComponentAccess('template', (0, shared_1.camelize)(rawName), prop.loc.start.offset);
}
yield (0, boundary_1.endBoundary)(token, startOffset + rawName.length);
}
function* generateArg(options, ctx, prop) {
const { arg } = prop;
if (arg?.type !== CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
return;
}
const startOffset = arg.loc.start.offset + arg.loc.source.indexOf(arg.content);
const token = yield* (0, boundary_1.startBoundary)('template', startOffset, codeFeatures_1.codeFeatures.verification);
yield `arg`;
yield (0, boundary_1.endBoundary)(token, startOffset + arg.content.length);
yield `: `;
if (arg.isStatic) {
yield* (0, stringLiteralKey_1.generateStringLiteralKey)(arg.content, startOffset, codeFeatures_1.codeFeatures.all);
}
else {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, arg.content, startOffset, `(`, `)`);
}
yield `, `;
}
function* generateModifiers(options, ctx, prop, propertyName = 'modifiers') {
const { modifiers } = prop;
if (!modifiers.length) {
return;
}
const startOffset = modifiers[0].loc.start.offset - 1;
const endOffset = modifiers.at(-1).loc.end.offset;
const token = yield* (0, boundary_1.startBoundary)('template', startOffset, codeFeatures_1.codeFeatures.verification);
yield propertyName;
yield (0, boundary_1.endBoundary)(token, endOffset);
yield `: { `;
for (const mod of modifiers) {
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, mod.content, mod.loc.start.offset, codeFeatures_1.codeFeatures.withoutHighlight);
yield `: true, `;
}
yield `}, `;
}
function* generateValue(options, ctx, prop) {
const { exp } = prop;
if (exp?.type !== CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
return;
}
const token = yield* (0, boundary_1.startBoundary)('template', exp.loc.start.offset, codeFeatures_1.codeFeatures.verification);
yield `value`;
yield (0, boundary_1.endBoundary)(token, exp.loc.end.offset);
yield `: `;
yield* (0, elementProps_1.generatePropExp)(options, ctx, prop, exp);
}
//# sourceMappingURL=elementDirectives.js.map
@@ -0,0 +1,10 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type * as ts from 'typescript';
import type { Code, VueCodeInformation } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateElementEvents(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, componentOriginalVar: string, getCtxVar: () => string, getPropsVar: () => string): Generator<Code>;
export declare function generateEventArg(options: TemplateCodegenOptions, name: string, start: number, directive?: string, features?: VueCodeInformation): Generator<Code>;
export declare function generateEventExpression(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode): Generator<Code>;
export declare function generateModelEventExpression(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode): Generator<Code>;
export declare function isCompoundExpression(ts: typeof import('typescript'), ast: ts.SourceFile): boolean;
@@ -0,0 +1,225 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateElementEvents = generateElementEvents;
exports.generateEventArg = generateEventArg;
exports.generateEventExpression = generateEventExpression;
exports.generateModelEventExpression = generateModelEventExpression;
exports.isCompoundExpression = isCompoundExpression;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("@vue/shared");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const camelized_1 = require("../utils/camelized");
const interpolation_1 = require("./interpolation");
function* generateElementEvents(options, ctx, node, componentOriginalVar, getCtxVar, getPropsVar) {
const definitions = {};
for (const prop of node.props) {
if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& (prop.name === 'on'
&& (prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.isStatic)
|| options.vueCompilerOptions.strictVModel
&& prop.name === 'model'
&& (!prop.arg || prop.arg.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.isStatic))) {
let source = prop.arg?.loc.source ?? 'model-value';
let offset = prop.arg?.loc.start.offset;
let propPrefix = 'on-';
let emitPrefix = '';
if (prop.name === 'model') {
propPrefix = 'onUpdate:';
emitPrefix = 'update:';
}
else if (source.startsWith('vue:')) {
source = source.slice('vue:'.length);
offset = offset + 'vue:'.length;
propPrefix = 'onVnode-';
emitPrefix = 'vnode-';
}
const propName = (0, shared_1.camelize)(propPrefix + source);
const emitName = emitPrefix + source;
const key = [
prop.name,
propName,
...prop.modifiers.map(modifier => modifier.content),
].join('+');
definitions[key] ??= {
propPrefix,
emitPrefix,
propName,
emitName,
items: [],
};
definitions[key].items.push({
prop,
source,
offset,
});
}
}
if (!Object.keys(definitions).length) {
return;
}
const emitsVar = ctx.getInternalVariable();
yield `let ${emitsVar}!: ${names_1.names.ResolveEmits}<typeof ${componentOriginalVar}, typeof ${getCtxVar()}.emit>${utils_1.endOfLine}`;
for (const { propPrefix, emitPrefix, propName, emitName, items } of Object.values(definitions)) {
yield `const ${ctx.getInternalVariable()}: ${names_1.names.ResolveEvent}<typeof ${getPropsVar()}, typeof ${emitsVar}, '${propName}', '${emitName}', '${(0, shared_1.camelize)(emitName)}'> = {${utils_1.newLine}`;
for (const { prop, source, offset } of items) {
if (prop.name === 'on') {
yield `/** @type {typeof ${emitsVar}.`;
yield* generateEventArg(options, source, offset, emitPrefix.slice(0, -1), codeFeatures_1.codeFeatures.navigation);
yield `} */${utils_1.newLine}`;
}
if (prop.name === 'on') {
yield* generateEventArg(options, source, offset, propPrefix.slice(0, -1));
yield `: `;
yield* generateEventExpression(options, ctx, prop);
}
else {
yield `'${propName}': `;
yield* generateModelEventExpression(options, ctx, prop);
}
yield `,${utils_1.newLine}`;
}
yield `}${utils_1.endOfLine}`;
}
}
function* generateEventArg(options, name, start, directive = 'on', features) {
features ??= {
...codeFeatures_1.codeFeatures.semanticWithoutHighlight,
...codeFeatures_1.codeFeatures.navigationWithoutRename,
...options.vueCompilerOptions.checkUnknownEvents
? codeFeatures_1.codeFeatures.verification
: codeFeatures_1.codeFeatures.doNotReportTs2353AndTs2561,
};
if (directive.length) {
name = (0, shared_1.capitalize)(name);
}
if (utils_1.identifierRegex.test((0, shared_1.camelize)(name))) {
const token = yield* (0, boundary_1.startBoundary)('template', start, features);
yield directive;
yield* (0, camelized_1.generateCamelized)(name, 'template', start, { __combineToken: token });
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', start, features);
yield `'`;
yield directive;
yield* (0, camelized_1.generateCamelized)(name, 'template', start, { __combineToken: token });
yield `'`;
yield (0, boundary_1.endBoundary)(token, start + name.length);
}
}
function* generateEventExpression(options, ctx, prop) {
if (prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const ast = (0, utils_1.getTypeScriptAST)(options.typescript, options.template, prop.exp.content);
const isCompound = isCompoundExpression(options.typescript, ast);
const interpolation = (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, prop.exp.content, prop.exp.loc.start.offset, isCompound ? `` : `(`, isCompound ? `` : `)`);
if (isCompound) {
yield `(...[$event]) => {${utils_1.newLine}`;
const endScope = ctx.startScope();
ctx.declare('$event');
yield* ctx.generateConditionGuards();
yield* interpolation;
yield utils_1.endOfLine;
yield* endScope();
yield `}`;
ctx.inlayHints.push({
blockName: 'template',
offset: prop.exp.loc.start.offset,
setting: 'vue.inlayHints.inlineHandlerLeading',
label: '$event =>',
paddingRight: true,
tooltip: [
'`$event` is a hidden parameter, you can use it in this callback.',
'To hide this hint, set `vue.inlayHints.inlineHandlerLeading` to `false` in IDE settings.',
'[More info](https://github.com/vuejs/language-tools/issues/2445#issuecomment-1444771420)',
].join('\n\n'),
});
}
else {
yield* interpolation;
}
}
else {
yield `() => {}`;
}
}
function* generateModelEventExpression(options, ctx, prop) {
if (prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
yield `(...[$event]) => {${utils_1.newLine}`;
yield* ctx.generateConditionGuards();
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.verification, prop.exp.content, prop.exp.loc.start.offset);
yield ` = $event${utils_1.endOfLine}`;
yield `}`;
}
else {
yield `() => {}`;
}
}
function isCompoundExpression(ts, ast) {
let result = true;
if (ast.statements.length === 0) {
result = false;
}
else if (ast.statements.length === 1) {
ts.forEachChild(ast, child_1 => {
if (ts.isExpressionStatement(child_1)) {
ts.forEachChild(child_1, child_2 => {
if (ts.isArrowFunction(child_2)) {
result = false;
}
else if (isPropertyAccessOrId(ts, child_2)) {
result = false;
}
});
}
else if (ts.isFunctionDeclaration(child_1)) {
result = false;
}
});
}
return result;
}
function isPropertyAccessOrId(ts, node) {
if (ts.isIdentifier(node)) {
return true;
}
if (ts.isPropertyAccessExpression(node)) {
return isPropertyAccessOrId(ts, node.expression);
}
return false;
}
//# sourceMappingURL=elementEvents.js.map
@@ -0,0 +1,11 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export interface FailedPropExpressions {
node: CompilerDOM.SimpleExpressionNode;
prefix: string;
suffix: string;
}
export declare function generateElementProps(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, props: CompilerDOM.ElementNode['props'], checkUnknownProps: boolean, failedPropExps?: FailedPropExpressions[]): Generator<Code>;
export declare function generatePropExp(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode, exp: CompilerDOM.SimpleExpressionNode | undefined): Generator<Code>;
@@ -0,0 +1,293 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateElementProps = generateElementProps;
exports.generatePropExp = generatePropExp;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("@vue/shared");
const picomatch_1 = require("picomatch");
const shared_2 = require("../../utils/shared");
const codeFeatures_1 = require("../codeFeatures");
const inlayHints_1 = require("../inlayHints");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const camelized_1 = require("../utils/camelized");
const unicode_1 = require("../utils/unicode");
const elementDirectives_1 = require("./elementDirectives");
const elementEvents_1 = require("./elementEvents");
const interpolation_1 = require("./interpolation");
const objectProperty_1 = require("./objectProperty");
function* generateElementProps(options, ctx, node, props, checkUnknownProps, failedPropExps) {
const isComponent = node.tagType === CompilerDOM.ElementTypes.COMPONENT;
for (const prop of props) {
if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& prop.name === 'on') {
if (prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
&& !prop.arg.loc.source.startsWith('[')
&& !prop.arg.loc.source.endsWith(']')) {
if (!isComponent) {
yield `...{ `;
yield* (0, elementEvents_1.generateEventArg)(options, prop.arg.loc.source, prop.arg.loc.start.offset);
yield `: `;
yield* (0, elementEvents_1.generateEventExpression)(options, ctx, prop);
yield `},`;
}
else {
yield `...{ '${(0, shared_1.camelize)('on-' + prop.arg.loc.source)}': {} as any },`;
}
yield utils_1.newLine;
}
else if (prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
&& prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
&& prop.arg.loc.source.startsWith('[')
&& prop.arg.loc.source.endsWith(']')) {
failedPropExps?.push({ node: prop.arg, prefix: `(`, suffix: `)` });
failedPropExps?.push({ node: prop.exp, prefix: `() => {`, suffix: `}` });
}
else if (!prop.arg
&& prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
failedPropExps?.push({ node: prop.exp, prefix: `(`, suffix: `)` });
}
}
}
for (const prop of props) {
if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& ((prop.name === 'bind' && prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION)
|| prop.name === 'model')
&& (!prop.exp || prop.exp.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION)) {
let propName;
if (prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
propName = prop.arg.constType === CompilerDOM.ConstantTypes.CAN_STRINGIFY
? prop.arg.content
: prop.arg.loc.source;
}
else {
propName = getModelPropName(node, options.vueCompilerOptions);
}
if (propName === undefined
|| options.vueCompilerOptions.dataAttributes.some(pattern => (0, picomatch_1.isMatch)(propName, pattern))) {
if (prop.exp && prop.exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY) {
failedPropExps?.push({ node: prop.exp, prefix: `(`, suffix: `)` });
}
continue;
}
if (prop.name === 'bind'
&& prop.modifiers.some(m => m.content === 'prop' || m.content === 'attr')) {
propName = propName.slice(1);
}
const shouldSpread = propName === 'style' || propName === 'class';
const shouldCamelize = getShouldCamelize(options, node, prop, propName);
const features = getPropsCodeFeatures(checkUnknownProps);
if (shouldSpread) {
yield `...{ `;
}
const token = yield* (0, boundary_1.startBoundary)('template', prop.loc.start.offset, codeFeatures_1.codeFeatures.verification);
if (prop.arg) {
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, propName, prop.arg.loc.start.offset, features, shouldCamelize);
}
else {
const token2 = yield* (0, boundary_1.startBoundary)('template', prop.loc.start.offset, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
yield propName;
yield (0, boundary_1.endBoundary)(token2, prop.loc.start.offset + 'v-model'.length);
}
yield `: `;
const argLoc = prop.arg?.loc ?? prop.loc;
const token3 = yield* (0, boundary_1.startBoundary)('template', argLoc.start.offset, codeFeatures_1.codeFeatures.verification);
yield* generatePropExp(options, ctx, prop, prop.exp);
yield (0, boundary_1.endBoundary)(token3, argLoc.end.offset);
yield (0, boundary_1.endBoundary)(token, prop.loc.end.offset);
if (shouldSpread) {
yield ` }`;
}
yield `,${utils_1.newLine}`;
if (isComponent && prop.name === 'model' && prop.modifiers.length) {
const propertyName = prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
? !prop.arg.isStatic
? `[${names_1.names.tryAsConstant}(\`\${${prop.arg.content}}Modifiers\`)]`
: (0, shared_1.camelize)(propName) + `Modifiers`
: `modelModifiers`;
yield* (0, elementDirectives_1.generateModifiers)(options, ctx, prop, propertyName);
yield utils_1.newLine;
}
}
else if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE) {
if (options.vueCompilerOptions.dataAttributes.some(pattern => (0, picomatch_1.isMatch)(prop.name, pattern))) {
continue;
}
const shouldSpread = prop.name === 'style' || prop.name === 'class';
const shouldCamelize = getShouldCamelize(options, node, prop, prop.name);
const features = getPropsCodeFeatures(checkUnknownProps);
if (shouldSpread) {
yield `...{ `;
}
const token = yield* (0, boundary_1.startBoundary)('template', prop.loc.start.offset, codeFeatures_1.codeFeatures.verification);
const prefix = options.template.content.slice(prop.loc.start.offset, prop.loc.start.offset + 1);
if (prefix === '.' || prefix === '#') {
// Pug shorthand syntax
for (const char of prop.name) {
yield [char, 'template', prop.loc.start.offset, features];
}
}
else {
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, prop.name, prop.loc.start.offset, features, shouldCamelize);
}
yield `: `;
if (prop.name === 'style') {
yield `{}`;
}
else if (prop.value) {
yield* generateAttrValue(prop.value, codeFeatures_1.codeFeatures.withoutNavigation);
}
else {
yield `true`;
}
yield (0, boundary_1.endBoundary)(token, prop.loc.end.offset);
if (shouldSpread) {
yield ` }`;
}
yield `,${utils_1.newLine}`;
}
else if (prop.name === 'bind'
&& !prop.arg
&& prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
if (prop.exp.loc.source === '$attrs') {
failedPropExps?.push({ node: prop.exp, prefix: `(`, suffix: `)` });
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', prop.exp.loc.start.offset, codeFeatures_1.codeFeatures.verification);
yield `...`;
yield* generatePropExp(options, ctx, prop, prop.exp);
yield (0, boundary_1.endBoundary)(token, prop.exp.loc.end.offset);
yield `,${utils_1.newLine}`;
}
}
}
}
function* generatePropExp(options, ctx, prop, exp) {
if (!exp) {
yield `{}`;
}
else if (prop.arg?.loc.start.offset !== prop.exp?.loc.start.offset) {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, exp.loc.source, exp.loc.start.offset, `(`, `)`);
}
else {
const propVariableName = (0, shared_1.camelize)(exp.loc.source);
if (utils_1.identifierRegex.test(propVariableName)) {
const codes = (0, camelized_1.generateCamelized)(exp.loc.source, 'template', exp.loc.start.offset, {
...codeFeatures_1.codeFeatures.withoutHighlightAndCompletion,
__shorthandExpression: 'html',
});
if ((0, interpolation_1.shouldIdentifierSkipped)(ctx, propVariableName)) {
yield* codes;
}
else if (options.setupRefs.has(propVariableName)) {
yield* codes;
yield `.value`;
}
else {
ctx.recordComponentAccess('template', propVariableName, exp.loc.start.offset);
yield names_1.names.ctx;
yield `.`;
yield* codes;
}
ctx.inlayHints.push((0, inlayHints_1.createVBindShorthandInlayHintInfo)(prop.loc, propVariableName));
}
}
}
function* generateAttrValue(node, features) {
const quote = node.loc.source.startsWith("'") ? "'" : '"';
const [content, offset] = (0, shared_2.normalizeAttributeValue)(node);
yield quote;
yield* (0, unicode_1.generateUnicode)(content, offset, features);
yield quote;
}
function getShouldCamelize(options, node, prop, propName) {
return (node.tagType === CompilerDOM.ElementTypes.COMPONENT
|| node.tagType === CompilerDOM.ElementTypes.SLOT) && (prop.type !== CompilerDOM.NodeTypes.DIRECTIVE
|| prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.isStatic)
&& (0, shared_2.hyphenateAttr)(propName) === propName
&& (node.tagType === CompilerDOM.ElementTypes.SLOT
|| !options.vueCompilerOptions.htmlAttributes.some(pattern => (0, picomatch_1.isMatch)(propName, pattern)));
}
function getPropsCodeFeatures(checkUnknownProps) {
return {
...codeFeatures_1.codeFeatures.withoutHighlightAndCompletion,
...checkUnknownProps
? codeFeatures_1.codeFeatures.verification
: codeFeatures_1.codeFeatures.doNotReportTs2353AndTs2561,
__propsCompletion: true,
};
}
function getModelPropName(node, vueCompilerOptions) {
for (const modelName in vueCompilerOptions.experimentalModelPropName) {
const tags = vueCompilerOptions.experimentalModelPropName[modelName];
for (const tag in tags) {
if (node.tag === tag || node.tag === (0, shared_2.hyphenateTag)(tag)) {
const val = tags[tag];
if (typeof val === 'object') {
const arr = Array.isArray(val) ? val : [val];
for (const attrs of arr) {
let failed = false;
for (const attr in attrs) {
const attrNode = node.props.find(prop => prop.type === CompilerDOM.NodeTypes.ATTRIBUTE && prop.name === attr);
if (!attrNode || attrNode.value?.content !== attrs[attr]) {
failed = true;
break;
}
}
if (!failed) {
// all match
return modelName || undefined;
}
}
}
}
}
}
for (const modelName in vueCompilerOptions.experimentalModelPropName) {
const tags = vueCompilerOptions.experimentalModelPropName[modelName];
for (const tag in tags) {
if (node.tag === tag || node.tag === (0, shared_2.hyphenateTag)(tag)) {
const attrs = tags[tag];
if (attrs === true) {
return modelName || undefined;
}
}
}
}
return 'modelValue';
}
//# sourceMappingURL=elementProps.js.map
+66
View File
@@ -0,0 +1,66 @@
import type * as ts from 'typescript';
import type { Code, IRTemplate, VueCompilerOptions } from '../../types';
export interface TemplateCodegenOptions {
typescript: typeof ts;
vueCompilerOptions: VueCompilerOptions;
template: IRTemplate;
setupRefs: Set<string>;
setupConsts: Set<string>;
hasDefineSlots?: boolean;
propsAssignName?: string;
slotsAssignName?: string;
inheritAttrs: boolean;
componentName: string;
}
export { generate as generateTemplate };
declare function generate(options: TemplateCodegenOptions): {
generatedTypes: Set<string>;
currentInfo: {
ignoreError?: boolean;
expectError?: {
token: number;
node: import("@vue/compiler-dom").CommentNode;
};
generic?: {
content: string;
offset: number;
};
};
resolveCodeFeatures: (features: import("../../types").VueCodeInformation) => import("../../types").VueCodeInformation;
inVFor: boolean;
slots: {
name: string;
offset?: number;
tagRange: [number, number];
nodeLoc: any;
propsVar: string;
}[];
dynamicSlots: {
expVar: string;
propsVar: string;
}[];
dollarVars: Set<string>;
componentAccessMap: Map<string, Map<string, Set<number>>>;
blockConditions: string[];
inlayHints: import("../inlayHints").InlayHintInfo[];
inheritedAttrVars: Set<string>;
templateRefs: Map<string, {
typeExp: string;
offset: number;
}[]>;
singleRootElTypes: Set<string>;
singleRootNodes: Set<import("@vue/compiler-dom").ElementNode | null>;
addTemplateRef(name: string, typeExp: string, offset: number): void;
recordComponentAccess(source: string, name: string, offset?: number): void;
scopes: Set<string>[];
components: (() => string)[];
declare(...varNames: string[]): void;
startScope(): () => Generator<Code, any, any>;
getInternalVariable(): string;
getHoistVariable(originalVar: string): string;
generateHoistVariables(): Generator<string, void, unknown>;
generateConditionGuards(): Generator<string, void, unknown>;
enter(node: import("@vue/compiler-dom").RootNode | import("@vue/compiler-dom").TemplateChildNode | import("@vue/compiler-dom").SimpleExpressionNode): boolean;
exit(): Generator<Code>;
codes: Code[];
};
+153
View File
@@ -0,0 +1,153 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateTemplate = generate;
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const context_1 = require("./context");
const objectProperty_1 = require("./objectProperty");
const templateChild_1 = require("./templateChild");
function generate(options) {
const ctx = (0, context_1.createTemplateCodegenContext)();
const codeGenerator = generateWorker(options, ctx);
const codes = [];
for (const code of codeGenerator) {
if (typeof code === 'object') {
code[3] = ctx.resolveCodeFeatures(code[3]);
}
codes.push(code);
}
return { ...ctx, codes };
}
function* generateWorker(options, ctx) {
const endScope = ctx.startScope();
ctx.declare(...options.setupConsts);
const { slotsAssignName, propsAssignName, vueCompilerOptions, template, } = options;
if (slotsAssignName) {
ctx.declare(slotsAssignName);
}
if (propsAssignName) {
ctx.declare(propsAssignName);
}
if (vueCompilerOptions.inferTemplateDollarSlots) {
ctx.dollarVars.add('$slots');
}
if (vueCompilerOptions.inferTemplateDollarAttrs) {
ctx.dollarVars.add('$attrs');
}
if (vueCompilerOptions.inferTemplateDollarRefs) {
ctx.dollarVars.add('$refs');
}
if (vueCompilerOptions.inferTemplateDollarEl) {
ctx.dollarVars.add('$el');
}
if (template.ast) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, template.ast);
}
yield* ctx.generateHoistVariables();
yield* generateSlotsType(options, ctx);
yield* generateInheritedAttrsType(options, ctx);
yield* generateTemplateRefsType(options, ctx);
yield* generateRootElType(ctx);
if (ctx.dollarVars.size) {
yield `var ${names_1.names.dollars}!: {${utils_1.newLine}`;
if (ctx.dollarVars.has('$slots')) {
const type = ctx.generatedTypes.has(names_1.names.Slots) ? names_1.names.Slots : `{}`;
yield `$slots: ${type}${utils_1.endOfLine}`;
}
if (ctx.dollarVars.has('$attrs')) {
yield `$attrs: import('${vueCompilerOptions.lib}').ComponentPublicInstance['$attrs']`;
if (ctx.generatedTypes.has(names_1.names.InheritedAttrs)) {
yield ` & ${names_1.names.InheritedAttrs}`;
}
yield utils_1.endOfLine;
}
if (ctx.dollarVars.has('$refs')) {
const type = ctx.generatedTypes.has(names_1.names.TemplateRefs) ? names_1.names.TemplateRefs : `{}`;
yield `$refs: ${type}${utils_1.endOfLine}`;
}
if (ctx.dollarVars.has('$el')) {
const type = ctx.generatedTypes.has(names_1.names.RootEl) ? names_1.names.RootEl : `any`;
yield `$el: ${type}${utils_1.endOfLine}`;
}
yield `} & { [K in keyof import('${vueCompilerOptions.lib}').ComponentPublicInstance]: unknown }${utils_1.endOfLine}`;
}
yield* endScope();
}
function* generateSlotsType(options, ctx) {
if (options.hasDefineSlots) {
ctx.generatedTypes.add(names_1.names.Slots);
return;
}
if (!ctx.slots.length && !ctx.dynamicSlots.length) {
return;
}
ctx.generatedTypes.add(names_1.names.Slots);
yield `type ${names_1.names.Slots} = {}`;
for (const { expVar, propsVar } of ctx.dynamicSlots) {
yield `${utils_1.newLine}& { [K in NonNullable<typeof ${expVar}>]?: (props: typeof ${propsVar}) => any }`;
}
for (const slot of ctx.slots) {
yield `${utils_1.newLine}& { `;
if (slot.name && slot.offset !== undefined) {
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, slot.name, slot.offset, codeFeatures_1.codeFeatures.navigation);
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', slot.tagRange[0], codeFeatures_1.codeFeatures.navigation);
yield `default`;
yield (0, boundary_1.endBoundary)(token, slot.tagRange[1]);
}
yield `?: (props: typeof ${slot.propsVar}) => any }`;
}
yield utils_1.endOfLine;
}
function* generateInheritedAttrsType(options, ctx) {
if (!ctx.inheritedAttrVars.size) {
return;
}
ctx.generatedTypes.add(names_1.names.InheritedAttrs);
const type = [...ctx.inheritedAttrVars].map(name => `typeof ${name}`).join(` & `);
yield `type ${names_1.names.InheritedAttrs} = ${options.vueCompilerOptions.checkRequiredFallthroughAttributes
? type
: `Partial<${type}>`}`;
yield utils_1.endOfLine;
}
function* generateTemplateRefsType(options, ctx) {
if (!ctx.templateRefs.size) {
return;
}
ctx.generatedTypes.add(names_1.names.TemplateRefs);
yield `type ${names_1.names.TemplateRefs} = {}`;
for (const [name, refs] of ctx.templateRefs) {
yield `${utils_1.newLine}& `;
if (refs.length >= 2) {
yield `(`;
}
for (let i = 0; i < refs.length; i++) {
const { typeExp, offset } = refs[i];
if (i) {
yield ` | `;
}
yield `{ `;
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, name, offset, codeFeatures_1.codeFeatures.navigation);
yield `: ${typeExp} }`;
}
if (refs.length >= 2) {
yield `)`;
}
}
yield utils_1.endOfLine;
}
function* generateRootElType(ctx) {
if (!ctx.singleRootElTypes.size || ctx.singleRootNodes.has(null)) {
return;
}
ctx.generatedTypes.add(names_1.names.RootEl);
yield `type ${names_1.names.RootEl} = `;
for (const type of ctx.singleRootElTypes) {
yield `${utils_1.newLine}| ${type}`;
}
yield utils_1.endOfLine;
}
//# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
import type { Code, IRBlock, VueCodeInformation } from '../../types';
import type { TemplateCodegenContext } from './context';
export declare function generateInterpolation({ typescript, setupRefs }: {
typescript: typeof import('typescript');
setupRefs: Set<string>;
}, ctx: TemplateCodegenContext, block: IRBlock, data: VueCodeInformation, code: string, start: number, prefix?: string, suffix?: string): Generator<Code>;
export declare function shouldIdentifierSkipped(ctx: TemplateCodegenContext, text: string): boolean;
@@ -0,0 +1,206 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateInterpolation = generateInterpolation;
exports.shouldIdentifierSkipped = shouldIdentifierSkipped;
const shared_1 = require("@vue/shared");
const collectBindings_1 = require("../../utils/collectBindings");
const shared_2 = require("../../utils/shared");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
// https://github.com/vuejs/core/blob/fb0c3ca519f1fccf52049cd6b8db3a67a669afe9/packages/compiler-core/src/transforms/transformExpression.ts#L47
const isLiteralWhitelisted = /*@__PURE__*/ (0, shared_1.makeMap)('true,false,null,this');
function* generateInterpolation({ typescript, setupRefs }, ctx, block, data, code, start, prefix = '', suffix = '') {
if (prefix) {
yield prefix;
}
let prevEnd = 0;
for (const [name, offset, isShorthand] of forEachIdentifiers(typescript, ctx, block, code, prefix, suffix)) {
if (isShorthand) {
yield [
code.slice(prevEnd, offset + name.length),
block.name,
start + prevEnd,
data,
];
yield `: `;
}
else if (prevEnd < offset) {
yield [
code.slice(prevEnd, offset),
block.name,
start + prevEnd,
data,
];
}
if (setupRefs.has(name)) {
yield [
name,
block.name,
start + offset,
data,
];
yield `.value`;
}
else {
// #1205, #1264
const token = yield* (0, boundary_1.startBoundary)(block.name, start + offset, codeFeatures_1.codeFeatures.verification);
if (ctx.dollarVars.has(name)) {
yield names_1.names.dollars;
}
else {
ctx.recordComponentAccess(block.name, name, start + offset);
yield names_1.names.ctx;
}
yield `.`;
yield [
name,
block.name,
start + offset,
isShorthand
? { ...data, __shorthandExpression: 'js' }
: data,
];
yield (0, boundary_1.endBoundary)(token, start + offset + name.length);
}
prevEnd = offset + name.length;
}
if (prevEnd < code.length) {
yield [
code.slice(prevEnd),
block.name,
start + prevEnd,
data,
];
}
if (suffix) {
yield suffix;
}
}
function* forEachIdentifiers(ts, ctx, block, code, prefix, suffix) {
if (utils_1.identifierRegex.test(code) && !shouldIdentifierSkipped(ctx, code)) {
yield [code, 0, false];
return;
}
const endScope = ctx.startScope();
const ast = (0, utils_1.getTypeScriptAST)(ts, block, prefix + code + suffix);
for (const [id, isShorthand] of forEachDeclarations(ts, ast, ast, ctx)) {
const text = (0, shared_2.getNodeText)(ts, id, ast);
if (shouldIdentifierSkipped(ctx, text)) {
continue;
}
yield [text, (0, shared_2.getStartEnd)(ts, id, ast).start - prefix.length, isShorthand];
}
endScope();
}
function* forEachDeclarations(ts, node, ast, ctx) {
if (ts.isIdentifier(node)) {
yield [node, false];
}
else if (ts.isShorthandPropertyAssignment(node)) {
yield [node.name, true];
}
else if (ts.isPropertyAccessExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx);
}
else if (ts.isVariableDeclaration(node)) {
ctx.declare(...(0, collectBindings_1.collectBindingNames)(ts, node.name, ast));
yield* forEachDeclarationsInBinding(ts, node, ast, ctx);
}
else if (ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node)) {
for (const element of node.elements) {
if (ts.isBindingElement(element)) {
yield* forEachDeclarationsInBinding(ts, element, ast, ctx);
}
}
}
else if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
yield* forEachDeclarationsInFunction(ts, node, ast, ctx);
}
else if (ts.isObjectLiteralExpression(node)) {
for (const prop of node.properties) {
if (ts.isPropertyAssignment(prop)) {
// fix https://github.com/vuejs/language-tools/issues/1176
if (ts.isComputedPropertyName(prop.name)) {
yield* forEachDeclarations(ts, prop.name.expression, ast, ctx);
}
yield* forEachDeclarations(ts, prop.initializer, ast, ctx);
}
// fix https://github.com/vuejs/language-tools/issues/1156
else if (ts.isShorthandPropertyAssignment(prop)) {
yield* forEachDeclarations(ts, prop, ast, ctx);
}
// fix https://github.com/vuejs/language-tools/issues/1148#issuecomment-1094378126
else if (ts.isSpreadAssignment(prop)) {
// TODO: cannot report "Spread types may only be created from object types.ts(2698)"
yield* forEachDeclarations(ts, prop.expression, ast, ctx);
}
// fix https://github.com/vuejs/language-tools/issues/4604
else if (ts.isFunctionLike(prop) && prop.body) {
yield* forEachDeclarationsInFunction(ts, prop, ast, ctx);
}
}
}
// fix https://github.com/vuejs/language-tools/issues/1422
else if (ts.isTypeNode(node)) {
yield* forEachDeclarationsInTypeNode(ts, node);
}
else if (ts.isBlock(node)) {
const endScope = ctx.startScope();
for (const child of (0, utils_1.forEachNode)(ts, node)) {
yield* forEachDeclarations(ts, child, ast, ctx);
}
endScope();
}
else {
for (const child of (0, utils_1.forEachNode)(ts, node)) {
yield* forEachDeclarations(ts, child, ast, ctx);
}
}
}
function* forEachDeclarationsInBinding(ts, node, ast, ctx) {
if ('type' in node && node.type) {
yield* forEachDeclarationsInTypeNode(ts, node.type);
}
if (!ts.isIdentifier(node.name)) {
yield* forEachDeclarations(ts, node.name, ast, ctx);
}
if (node.initializer) {
yield* forEachDeclarations(ts, node.initializer, ast, ctx);
}
}
function* forEachDeclarationsInFunction(ts, node, ast, ctx) {
const endScope = ctx.startScope();
for (const param of node.parameters) {
ctx.declare(...(0, collectBindings_1.collectBindingNames)(ts, param.name, ast));
yield* forEachDeclarationsInBinding(ts, param, ast, ctx);
}
if (node.body) {
yield* forEachDeclarations(ts, node.body, ast, ctx);
}
endScope();
}
function* forEachDeclarationsInTypeNode(ts, node) {
if (ts.isTypeQueryNode(node)) {
let id = node.exprName;
while (!ts.isIdentifier(id)) {
id = id.left;
}
yield [id, false];
}
else {
for (const child of (0, utils_1.forEachNode)(ts, node)) {
yield* forEachDeclarationsInTypeNode(ts, child);
}
}
}
function shouldIdentifierSkipped(ctx, text) {
return ctx.scopes.some(scope => scope.has(text))
// https://github.com/vuejs/core/blob/245230e135152900189f13a4281302de45fdcfaa/packages/compiler-core/src/transforms/transformExpression.ts#L342-L352
|| (0, shared_1.isGloballyAllowed)(text)
|| isLiteralWhitelisted(text)
|| text === 'require'
|| text.startsWith('__VLS_');
}
//# sourceMappingURL=interpolation.js.map
@@ -0,0 +1,4 @@
import type { Code, VueCodeInformation } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateObjectProperty(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, code: string, offset: number, features: VueCodeInformation, shouldCamelize?: boolean, shouldBeConstant?: boolean): Generator<Code>;
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateObjectProperty = generateObjectProperty;
const shared_1 = require("@vue/shared");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const camelized_1 = require("../utils/camelized");
const stringLiteralKey_1 = require("../utils/stringLiteralKey");
const interpolation_1 = require("./interpolation");
function* generateObjectProperty(options, ctx, code, offset, features, shouldCamelize = false, shouldBeConstant = false) {
if (code.startsWith('[') && code.endsWith(']')) {
if (shouldBeConstant) {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, features, code.slice(1, -1), offset + 1, `[${names_1.names.tryAsConstant}(`, `)]`);
}
else {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, features, code, offset);
}
}
else if (shouldCamelize) {
if (utils_1.identifierRegex.test((0, shared_1.camelize)(code))) {
yield* (0, camelized_1.generateCamelized)(code, 'template', offset, features);
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', offset, features);
yield `'`;
yield* (0, camelized_1.generateCamelized)(code, 'template', offset, { __combineToken: token });
yield `'`;
yield (0, boundary_1.endBoundary)(token, offset + code.length);
}
}
else {
if (utils_1.identifierRegex.test(code)) {
yield [code, 'template', offset, features];
}
else {
yield* (0, stringLiteralKey_1.generateStringLiteralKey)(code, offset, features);
}
}
}
//# sourceMappingURL=objectProperty.js.map
@@ -0,0 +1,4 @@
import type { Code, VueCodeInformation } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generatePropertyAccess(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, code: string, offset: number, features: VueCodeInformation): Generator<Code>;
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePropertyAccess = generatePropertyAccess;
const utils_1 = require("../utils");
const stringLiteralKey_1 = require("../utils/stringLiteralKey");
const interpolation_1 = require("./interpolation");
function* generatePropertyAccess(options, ctx, code, offset, features) {
if (code.startsWith('[') && code.endsWith(']')) {
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, features, code, offset);
}
else if (utils_1.identifierRegex.test(code)) {
yield `.`;
yield [code, 'template', offset, features];
}
else {
yield `[`;
yield* (0, stringLiteralKey_1.generateStringLiteralKey)(code, offset, features);
yield `]`;
}
}
//# sourceMappingURL=propertyAccess.js.map
@@ -0,0 +1,5 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateSlotOutlet(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.SlotOutletNode): Generator<Code>;
+146
View File
@@ -0,0 +1,146 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateSlotOutlet = generateSlotOutlet;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("../../utils/shared");
const codeFeatures_1 = require("../codeFeatures");
const inlayHints_1 = require("../inlayHints");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const elementProps_1 = require("./elementProps");
const interpolation_1 = require("./interpolation");
const propertyAccess_1 = require("./propertyAccess");
const templateChild_1 = require("./templateChild");
function* generateSlotOutlet(options, ctx, node) {
const [startTagOffset] = (0, shared_1.getElementTagOffsets)(node, options.template);
const startTagEndOffset = startTagOffset + node.tag.length;
const propsVar = ctx.getInternalVariable();
const nameProp = node.props.find(prop => {
if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE) {
return prop.name === 'name';
}
if (prop.name === 'bind'
&& prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
return prop.arg.content === 'name';
}
});
if (options.hasDefineSlots) {
yield `${names_1.names.asFunctionalSlot}(`;
if (nameProp) {
let codes;
if (nameProp.type === CompilerDOM.NodeTypes.ATTRIBUTE && nameProp.value) {
const [content, offset] = (0, shared_1.normalizeAttributeValue)(nameProp.value);
codes = (0, propertyAccess_1.generatePropertyAccess)(options, ctx, content, offset, codeFeatures_1.codeFeatures.navigationAndVerification);
}
else if (nameProp.type === CompilerDOM.NodeTypes.DIRECTIVE
&& nameProp.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
codes = [
`[`,
...(0, elementProps_1.generatePropExp)(options, ctx, nameProp, nameProp.exp),
`]`,
];
}
else {
codes = [`['default']`];
}
const token = yield* (0, boundary_1.startBoundary)('template', nameProp.loc.start.offset, codeFeatures_1.codeFeatures.verification);
yield options.slotsAssignName ?? names_1.names.slots;
yield* codes;
yield (0, boundary_1.endBoundary)(token, nameProp.loc.end.offset);
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', startTagOffset, codeFeatures_1.codeFeatures.verification);
yield `${options.slotsAssignName ?? names_1.names.slots}[`;
const token2 = yield* (0, boundary_1.startBoundary)('template', startTagOffset, codeFeatures_1.codeFeatures.verification);
yield `'default'`;
yield (0, boundary_1.endBoundary)(token2, startTagEndOffset);
yield `]`;
yield (0, boundary_1.endBoundary)(token, startTagEndOffset);
}
yield `)(`;
const token = yield* (0, boundary_1.startBoundary)('template', startTagOffset, codeFeatures_1.codeFeatures.verification);
yield `{${utils_1.newLine}`;
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, node.props.filter(prop => prop !== nameProp), true);
yield `}`;
yield (0, boundary_1.endBoundary)(token, startTagEndOffset);
yield `)${utils_1.endOfLine}`;
}
else {
yield `var ${propsVar} = {${utils_1.newLine}`;
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, node.props.filter(prop => prop !== nameProp), options.vueCompilerOptions.checkUnknownProps);
yield `}${utils_1.endOfLine}`;
if (nameProp?.type === CompilerDOM.NodeTypes.ATTRIBUTE
&& nameProp.value) {
ctx.slots.push({
name: nameProp.value.content,
offset: nameProp.loc.start.offset + nameProp.loc.source.indexOf(nameProp.value.content, nameProp.name.length),
tagRange: [startTagOffset, startTagOffset + node.tag.length],
nodeLoc: node.loc,
propsVar: ctx.getHoistVariable(propsVar),
});
}
else if (nameProp?.type === CompilerDOM.NodeTypes.DIRECTIVE
&& nameProp.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const isShortHand = nameProp.arg?.loc.start.offset === nameProp.exp.loc.start.offset;
if (isShortHand) {
ctx.inlayHints.push((0, inlayHints_1.createVBindShorthandInlayHintInfo)(nameProp.exp.loc, 'name'));
}
const expVar = ctx.getInternalVariable();
yield `var ${expVar} = ${names_1.names.tryAsConstant}(`;
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, isShortHand
? codeFeatures_1.codeFeatures.withoutHighlightAndCompletion
: codeFeatures_1.codeFeatures.all, nameProp.exp.content, nameProp.exp.loc.start.offset);
yield `)${utils_1.endOfLine}`;
ctx.dynamicSlots.push({
expVar: ctx.getHoistVariable(expVar),
propsVar: ctx.getHoistVariable(propsVar),
});
}
else {
ctx.slots.push({
name: 'default',
tagRange: [startTagOffset, startTagEndOffset],
nodeLoc: node.loc,
propsVar: ctx.getHoistVariable(propsVar),
});
}
}
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child);
}
}
//# sourceMappingURL=slotOutlet.js.map
@@ -0,0 +1,3 @@
import type { Code, IRBlock } from '../../types';
export declare const references: WeakMap<IRBlock, [version: string, [className: string, offset: number][]]>;
export declare function generateStyleScopedClassReference(block: IRBlock, className: string, offset: number, fullStart?: number): Generator<Code>;
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.references = void 0;
exports.generateStyleScopedClassReference = generateStyleScopedClassReference;
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const escaped_1 = require("../utils/escaped");
const classNameEscapeRegex = /([\\'])/;
// For language-service/lib/plugins/vue-scoped-class-links.ts usage
exports.references = new WeakMap();
function* generateStyleScopedClassReference(block, className, offset, fullStart = offset) {
if (!className) {
yield `/** @type {${names_1.names.StyleScopedClasses}['`;
yield ['', 'template', offset, codeFeatures_1.codeFeatures.completion];
yield `']} */${utils_1.endOfLine}`;
return;
}
const cache = exports.references.get(block);
if (!cache || cache[0] !== block.content) {
const arr = [];
exports.references.set(block, [block.content, arr]);
arr.push([className, offset]);
}
else {
cache[1].push([className, offset]);
}
yield `/** @type {${names_1.names.StyleScopedClasses}[`;
const token = yield* (0, boundary_1.startBoundary)(block.name, fullStart, codeFeatures_1.codeFeatures.navigation);
yield `'`;
yield* (0, escaped_1.generateEscaped)(className, block.name, offset, codeFeatures_1.codeFeatures.navigationAndCompletion, classNameEscapeRegex);
yield `'`;
yield (0, boundary_1.endBoundary)(token, offset + className.length);
yield `]} */${utils_1.endOfLine}`;
}
//# sourceMappingURL=styleScopedClasses.js.map
@@ -0,0 +1,6 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateTemplateChild(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode | CompilerDOM.SimpleExpressionNode, enterNode?: boolean, treatTemplateAsFragment?: boolean): Generator<Code>;
export declare function parseInterpolationNode(node: CompilerDOM.InterpolationNode, template: string): readonly [string, number];
@@ -0,0 +1,148 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateTemplateChild = generateTemplateChild;
exports.parseInterpolationNode = parseInterpolationNode;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("../../utils/shared");
const codeFeatures_1 = require("../codeFeatures");
const utils_1 = require("../utils");
const element_1 = require("./element");
const interpolation_1 = require("./interpolation");
const slotOutlet_1 = require("./slotOutlet");
const vFor_1 = require("./vFor");
const vIf_1 = require("./vIf");
const vSlot_1 = require("./vSlot");
function* generateTemplateChild(options, ctx, node, enterNode = true, treatTemplateAsFragment = false) {
if (enterNode && !ctx.enter(node)) {
return;
}
if (node.type === CompilerDOM.NodeTypes.ROOT) {
for (const item of collectSingleRootNodes(options, node.children)) {
ctx.singleRootNodes.add(item);
}
for (const child of node.children) {
yield* generateTemplateChild(options, ctx, child);
}
}
else if (node.type === CompilerDOM.NodeTypes.ELEMENT) {
if (node.tagType === CompilerDOM.ElementTypes.SLOT) {
yield* (0, slotOutlet_1.generateSlotOutlet)(options, ctx, node);
}
else {
const slotDir = node.props.find(CompilerDOM.isVSlot);
if (node.tagType === CompilerDOM.ElementTypes.TEMPLATE && ctx.components.length && slotDir) {
yield* (0, vSlot_1.generateVSlot)(options, ctx, node, slotDir, ctx.components.at(-1)());
}
else if (node.tagType === CompilerDOM.ElementTypes.TEMPLATE && treatTemplateAsFragment) {
yield* (0, element_1.generateFragment)(options, ctx, node);
}
else if (node.tagType === CompilerDOM.ElementTypes.COMPONENT) {
yield* (0, element_1.generateComponent)(options, ctx, node);
}
else {
yield* (0, element_1.generateElement)(options, ctx, node);
}
}
}
else if (node.type === CompilerDOM.NodeTypes.COMPOUND_EXPRESSION) {
// {{ ... }} {{ ... }}
for (const child of node.children) {
if (typeof child !== 'object') {
continue;
}
yield* generateTemplateChild(options, ctx, child, false);
}
}
else if (node.type === CompilerDOM.NodeTypes.INTERPOLATION) {
// {{ ... }}
const [content, start] = parseInterpolationNode(node, options.template.content);
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, content, start, `(`, `)${utils_1.endOfLine}`);
}
else if (node.type === CompilerDOM.NodeTypes.IF) {
// v-if / v-else-if / v-else
yield* (0, vIf_1.generateVIf)(options, ctx, node);
}
else if (node.type === CompilerDOM.NodeTypes.FOR) {
// v-for
yield* (0, vFor_1.generateVFor)(options, ctx, node);
}
if (enterNode) {
yield* ctx.exit();
}
}
function* collectSingleRootNodes(options, children, treatTemplateAsFragment = false) {
// Exclude the effect of comments on the root node
children = children.filter(node => node.type !== CompilerDOM.NodeTypes.COMMENT);
if (children.length !== 1) {
// "null" is used to determine whether the component is not always has a single root
if (children.length > 1) {
yield null;
}
return;
}
const child = children[0];
if (child.type === CompilerDOM.NodeTypes.IF) {
for (const branch of child.branches) {
yield* collectSingleRootNodes(options, branch.children, true);
}
return;
}
else if (child.type !== CompilerDOM.NodeTypes.ELEMENT) {
return;
}
if (child.tagType === CompilerDOM.ElementTypes.TEMPLATE && treatTemplateAsFragment) {
yield* collectSingleRootNodes(options, child.children);
return;
}
yield child;
const tag = (0, shared_1.hyphenateTag)(child.tag);
if (options.vueCompilerOptions.fallthroughComponentNames.includes(tag)) {
yield* collectSingleRootNodes(options, child.children);
}
}
function parseInterpolationNode(node, template) {
let start = node.content.loc.start.offset;
let end = node.content.loc.end.offset;
// fix https://github.com/vuejs/language-tools/issues/1787
while (template[start - 1]?.trim() === '') {
start--;
}
while (template[end]?.trim() === '') {
end++;
}
return [template.slice(start, end), start];
}
//# sourceMappingURL=templateChild.js.map
+12
View File
@@ -0,0 +1,12 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateVFor(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ForNode): Generator<Code>;
export declare function parseVForNode(node: CompilerDOM.ForNode): {
leftExpressionRange: {
start: number;
end: number;
} | undefined;
leftExpressionText: string | undefined;
};
+95
View File
@@ -0,0 +1,95 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateVFor = generateVFor;
exports.parseVForNode = parseVForNode;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const collectBindings_1 = require("../../utils/collectBindings");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const interpolation_1 = require("./interpolation");
const templateChild_1 = require("./templateChild");
function* generateVFor(options, ctx, node) {
const { source } = node.parseResult;
const { leftExpressionRange, leftExpressionText } = parseVForNode(node);
const endScope = ctx.startScope();
yield `for (const [`;
if (leftExpressionRange && leftExpressionText) {
const collectAst = (0, utils_1.getTypeScriptAST)(options.typescript, options.template, `const [${leftExpressionText}]`);
ctx.declare(...(0, collectBindings_1.collectBindingNames)(options.typescript, collectAst, collectAst));
yield [
leftExpressionText,
'template',
leftExpressionRange.start,
codeFeatures_1.codeFeatures.all,
];
}
yield `] of `;
if (source.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
yield `${names_1.names.vFor}(`;
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, source.content, source.loc.start.offset, `(`, `)`);
yield `!)`; // #3102
}
else {
yield `{} as any`;
}
yield `) {${utils_1.newLine}`;
const { inVFor } = ctx;
ctx.inVFor = true;
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child, false, true);
}
ctx.inVFor = inVFor;
yield* endScope();
yield `}${utils_1.newLine}`;
}
function parseVForNode(node) {
const { value, key, index } = node.parseResult;
const leftExpressionRange = (value || key || index)
? {
start: (value ?? key ?? index).loc.start.offset,
end: (index ?? key ?? value).loc.end.offset,
}
: undefined;
const leftExpressionText = leftExpressionRange
? node.loc.source.slice(leftExpressionRange.start - node.loc.start.offset, leftExpressionRange.end - node.loc.start.offset)
: undefined;
return {
leftExpressionRange,
leftExpressionText,
};
}
//# sourceMappingURL=vFor.js.map
+5
View File
@@ -0,0 +1,5 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateVIf(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.IfNode): Generator<Code>;
+75
View File
@@ -0,0 +1,75 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateVIf = generateVIf;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const muggle_string_1 = require("muggle-string");
const codeFeatures_1 = require("../codeFeatures");
const utils_1 = require("../utils");
const interpolation_1 = require("./interpolation");
const templateChild_1 = require("./templateChild");
function* generateVIf(options, ctx, node) {
const originalBlockConditionsLength = ctx.blockConditions.length;
for (let i = 0; i < node.branches.length; i++) {
const branch = node.branches[i];
if (i === 0) {
yield `if `;
}
else if (branch.condition) {
yield `else if `;
}
else {
yield `else `;
}
let addedBlockCondition = false;
if (branch.condition?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const codes = [...(0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, branch.condition.content, branch.condition.loc.start.offset, `(`, `)`)];
yield* codes;
ctx.blockConditions.push((0, muggle_string_1.toString)(codes));
addedBlockCondition = true;
yield ` `;
}
yield `{${utils_1.newLine}`;
for (const child of branch.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child, i !== 0, true);
}
yield `}${utils_1.newLine}`;
if (addedBlockCondition) {
ctx.blockConditions[ctx.blockConditions.length - 1] = `!${ctx.blockConditions[ctx.blockConditions.length - 1]}`;
}
}
ctx.blockConditions.length = originalBlockConditionsLength;
}
//# sourceMappingURL=vIf.js.map
+5
View File
@@ -0,0 +1,5 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
export declare function generateVSlot(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, slotDir: CompilerDOM.DirectiveNode | undefined, ctxVar: string): Generator<Code>;
+140
View File
@@ -0,0 +1,140 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateVSlot = generateVSlot;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const muggle_string_1 = require("muggle-string");
const collectBindings_1 = require("../../utils/collectBindings");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const interpolation_1 = require("./interpolation");
const objectProperty_1 = require("./objectProperty");
const templateChild_1 = require("./templateChild");
function* generateVSlot(options, ctx, node, slotDir, ctxVar) {
const slotVar = ctx.getInternalVariable();
if (slotDir) {
yield `{${utils_1.newLine}`;
yield `const { `;
if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && slotDir.arg.content) {
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, slotDir.arg.loc.source, slotDir.arg.loc.start.offset, slotDir.arg.isStatic ? codeFeatures_1.codeFeatures.withoutHighlight : codeFeatures_1.codeFeatures.all, false, true);
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', slotDir.loc.start.offset, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
yield `default`;
yield (0, boundary_1.endBoundary)(token, slotDir.loc.start.offset + (slotDir.rawName?.length ?? 0));
}
}
else {
yield `const { `;
// #932: reference for implicit default slot
const token = yield* (0, boundary_1.startBoundary)('template', node.loc.start.offset, codeFeatures_1.codeFeatures.navigation);
yield `default`;
yield (0, boundary_1.endBoundary)(token, node.loc.end.offset);
}
yield `: ${slotVar} } = ${ctxVar}.slots!${utils_1.endOfLine}`;
const endScope = ctx.startScope();
if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const slotAst = (0, utils_1.getTypeScriptAST)(options.typescript, options.template, `(${slotDir.exp.content}) => {}`);
yield* generateSlotParameters(options, ctx, slotAst, slotDir.exp, slotVar);
ctx.declare(...(0, collectBindings_1.collectBindingNames)(options.typescript, slotAst, slotAst));
}
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child);
}
yield* endScope();
if (slotDir) {
let isStatic = true;
if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
isStatic = slotDir.arg.isStatic;
}
if (isStatic && !slotDir.arg) {
yield `${ctxVar}.slots!['`;
yield [
'',
'template',
slotDir.loc.start.offset + (slotDir.loc.source.startsWith('#')
? '#'.length
: slotDir.loc.source.startsWith('v-slot:')
? 'v-slot:'.length
: 0),
codeFeatures_1.codeFeatures.completion,
];
yield `'/* empty slot name completion */]${utils_1.endOfLine}`;
}
yield `}${utils_1.newLine}`;
}
}
function* generateSlotParameters(options, ctx, ast, exp, slotVar) {
const { typescript: ts } = options;
const statement = ast.statements[0];
if (!statement || !ts.isExpressionStatement(statement) || !ts.isArrowFunction(statement.expression)) {
return;
}
const { expression } = statement;
const startOffset = exp.loc.start.offset - 1;
const types = [];
const interpolation = [...(0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, ast.text, startOffset)];
(0, muggle_string_1.replaceSourceRange)(interpolation, 'template', startOffset, startOffset + `(`.length);
(0, muggle_string_1.replaceSourceRange)(interpolation, 'template', startOffset + ast.text.length - `) => {}`.length, startOffset + ast.text.length);
for (const { name, type } of expression.parameters) {
if (type) {
types.push([
ast.text.slice(name.end, type.end),
'template',
startOffset + name.end,
codeFeatures_1.codeFeatures.all,
]);
(0, muggle_string_1.replaceSourceRange)(interpolation, 'template', startOffset + name.end, startOffset + type.end);
}
else {
types.push(null);
}
}
yield `const [`;
yield* interpolation;
yield `] = ${names_1.names.vSlot}(${slotVar}!`;
if (types.some(t => t)) {
yield `, `;
const token = yield* (0, boundary_1.startBoundary)('template', exp.loc.start.offset, codeFeatures_1.codeFeatures.verification);
yield `(`;
yield* types.flatMap(type => type ? [`_`, type, `, `] : `_, `);
yield `) => [] as any`;
yield (0, boundary_1.endBoundary)(token, exp.loc.end.offset);
}
yield `)${utils_1.endOfLine}`;
}
//# sourceMappingURL=vSlot.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { Code, VueCodeInformation } from '../../types';
export declare function startBoundary(source: string, startOffset: number, features: VueCodeInformation): Generator<Code, symbol, unknown>;
export declare function endBoundary(token: symbol, endOffset: number): Code;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startBoundary = startBoundary;
exports.endBoundary = endBoundary;
function* startBoundary(source, startOffset, features) {
const token = Symbol(source);
yield ['', source, startOffset, { ...features, __combineToken: token }];
return token;
}
function endBoundary(token, endOffset) {
return ['', token.description, endOffset, { __combineToken: token }];
}
//# sourceMappingURL=boundary.js.map
+2
View File
@@ -0,0 +1,2 @@
import type { Code, VueCodeInformation } from '../../types';
export declare function generateCamelized(code: string, source: string, offset: number, features: VueCodeInformation): Generator<Code>;
+31
View File
@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCamelized = generateCamelized;
const shared_1 = require("@vue/shared");
function* generateCamelized(code, source, offset, features) {
const parts = code.split('-');
const combineToken = features.__combineToken ?? Symbol();
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (part !== '') {
if (i === 0) {
yield [
part,
source,
offset,
{ ...features, __combineToken: combineToken },
];
}
else {
yield [
(0, shared_1.capitalize)(part),
source,
offset,
{ __combineToken: combineToken },
];
}
}
offset += part.length + 1;
}
}
//# sourceMappingURL=camelized.js.map
+2
View File
@@ -0,0 +1,2 @@
import type { Code, VueCodeInformation } from '../../types';
export declare function generateEscaped(text: string, source: string, offset: number, features: VueCodeInformation, escapeTarget: RegExp): Generator<Code>;
+25
View File
@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateEscaped = generateEscaped;
function* generateEscaped(text, source, offset, features, escapeTarget) {
const parts = text.split(escapeTarget);
const combineToken = features.__combineToken ?? Symbol();
let isEscapeTarget = false;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (isEscapeTarget) {
yield `\\`;
}
yield [
part,
source,
offset,
i === 0
? { ...features, __combineToken: combineToken }
: { __combineToken: combineToken },
];
offset += part.length;
isEscapeTarget = !isEscapeTarget;
}
}
//# sourceMappingURL=escaped.js.map
+8
View File
@@ -0,0 +1,8 @@
import type * as ts from 'typescript';
import type { Code, IRBlock, IRScript, IRScriptSetup, VueCodeInformation } from '../../types';
export declare const newLine = "\n";
export declare const endOfLine = ";\n";
export declare const identifierRegex: RegExp;
export declare function getTypeScriptAST(ts: typeof import('typescript'), block: IRBlock, text: string): ts.SourceFile;
export declare function generateSfcBlockSection(block: IRScript | IRScriptSetup, start: number, end: number, features: VueCodeInformation): Generator<Code>;
export declare function forEachNode(ts: typeof import('typescript'), node: ts.Node): Generator<ts.Node>;
+64
View File
@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.identifierRegex = exports.endOfLine = exports.newLine = void 0;
exports.getTypeScriptAST = getTypeScriptAST;
exports.generateSfcBlockSection = generateSfcBlockSection;
exports.forEachNode = forEachNode;
const codeFeatures_1 = require("../codeFeatures");
exports.newLine = `\n`;
exports.endOfLine = `;${exports.newLine}`;
exports.identifierRegex = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
const cacheMaps = new Map();
function getTypeScriptAST(ts, block, text) {
if (!cacheMaps.has(block)) {
cacheMaps.set(block, [block.content, new Map()]);
}
const cacheMap = cacheMaps.get(block);
if (cacheMap[0] !== block.content) {
cacheMap[0] = block.content;
for (const [key, info] of cacheMap[1]) {
if (info[1]) {
info[1] = 0;
}
else {
cacheMap[1].delete(key);
}
}
}
const cache = cacheMap[1].get(text);
if (cache) {
cache[1]++;
return cache[0];
}
const ast = ts.createSourceFile('/dummy.ts', text, 99);
cacheMap[1].set(text, [ast, 1]);
return ast;
}
function* generateSfcBlockSection(block, start, end, features) {
const text = block.content.slice(start, end);
yield [text, block.name, start, features];
// #3632
if ('parseDiagnostics' in block.ast) {
const textEnd = text.trimEnd().length;
for (const diag of block.ast.parseDiagnostics) {
const diagStart = diag.start;
const diagEnd = diag.start + diag.length;
if (diagStart >= textEnd && diagEnd <= end) {
yield `;`;
yield ['', block.name, end, codeFeatures_1.codeFeatures.verification];
yield exports.newLine;
break;
}
}
}
}
function* forEachNode(ts, node) {
const children = [];
ts.forEachChild(node, child => {
children.push(child);
});
for (const child of children) {
yield child;
}
}
//# sourceMappingURL=index.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { Code } from '../../types';
export declare function generateIntersectMerge(...codes: Code[]): Generator<Code>;
export declare function generateSpreadMerge(...codes: Code[]): Generator<Code>;
+27
View File
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateIntersectMerge = generateIntersectMerge;
exports.generateSpreadMerge = generateSpreadMerge;
const index_1 = require("./index");
function* generateIntersectMerge(...codes) {
yield codes[0];
for (let i = 1; i < codes.length; i++) {
yield ` & `;
yield codes[i];
}
}
function* generateSpreadMerge(...codes) {
if (codes.length <= 1) {
yield* codes;
}
else {
yield `{${index_1.newLine}`;
for (const code of codes) {
yield `...`;
yield code;
yield `,${index_1.newLine}`;
}
yield `}`;
}
}
//# sourceMappingURL=merge.js.map
@@ -0,0 +1,2 @@
import type { Code, VueCodeInformation } from '../../types';
export declare function generateStringLiteralKey(code: string, offset?: number, info?: VueCodeInformation): Generator<Code>;
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateStringLiteralKey = generateStringLiteralKey;
const boundary_1 = require("./boundary");
function* generateStringLiteralKey(code, offset, info) {
if (offset === undefined || !info) {
yield `'${code}'`;
}
else {
const token = yield* (0, boundary_1.startBoundary)('template', offset, info);
yield `'`;
yield [code, 'template', offset, { __combineToken: token }];
yield `'`;
yield (0, boundary_1.endBoundary)(token, offset + code.length);
}
}
//# sourceMappingURL=stringLiteralKey.js.map
+8
View File
@@ -0,0 +1,8 @@
import type { Code } from '../../types';
export interface CodeTransform {
range: [start: number, end: number];
generate(): Iterable<Code>;
}
export declare function replace(start: number, end: number, replacement: () => Iterable<Code>): CodeTransform;
export declare function insert(position: number, insertion: () => Iterable<Code>): CodeTransform;
export declare function generateCodeWithTransforms(start: number, end: number, transforms: CodeTransform[], section: (start: number, end: number) => Iterable<Code>): Generator<Code>;
+27
View File
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.replace = replace;
exports.insert = insert;
exports.generateCodeWithTransforms = generateCodeWithTransforms;
function replace(start, end, replacement) {
return {
range: [start, end],
generate: replacement,
};
}
function insert(position, insertion) {
return {
range: [position, position],
generate: insertion,
};
}
function* generateCodeWithTransforms(start, end, transforms, section) {
const sortedTransforms = transforms.sort((a, b) => a.range[0] - b.range[0]);
for (const { range, generate } of sortedTransforms) {
yield* section(start, range[0]);
yield* generate();
start = range[1];
}
yield* section(start, end);
}
//# sourceMappingURL=transform.js.map
+2
View File
@@ -0,0 +1,2 @@
import type { Code, VueCodeInformation } from '../../types';
export declare function generateUnicode(code: string, offset: number, info: VueCodeInformation): Generator<Code>;
+27
View File
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateUnicode = generateUnicode;
const boundary_1 = require("./boundary");
function* generateUnicode(code, offset, info) {
if (needToUnicode(code)) {
const token = yield* (0, boundary_1.startBoundary)('template', offset, info);
yield toUnicode(code);
yield (0, boundary_1.endBoundary)(token, offset + code.length);
}
else {
yield [code, 'template', offset, info];
}
}
function needToUnicode(str) {
return str.includes('\\') || str.includes('\n');
}
function toUnicode(str) {
return str.split('').map(value => {
const temp = value.charCodeAt(0).toString(16).padStart(4, '0');
if (temp.length > 2) {
return '\\u' + temp;
}
return value;
}).join('');
}
//# sourceMappingURL=unicode.js.map
+23
View File
@@ -0,0 +1,23 @@
import type * as ts from 'typescript';
import type { RawVueCompilerOptions, VueCompilerOptions, VueLanguagePlugin } from './types';
interface ParseConfigHost extends Omit<ts.ParseConfigHost, 'readDirectory'> {
}
export interface ParsedCommandLine extends Omit<ts.ParsedCommandLine, 'fileNames'> {
vueOptions: VueCompilerOptions;
}
export declare function createParsedCommandLineByJson(ts: typeof import('typescript'), host: ParseConfigHost, rootDir: string, json: any, configFileName?: string): ParsedCommandLine;
export declare function createParsedCommandLine(ts: typeof import('typescript'), host: ParseConfigHost, configFileName: string): ParsedCommandLine;
export declare class CompilerOptionsResolver {
ts: typeof import('typescript');
readFile: (fileName: string) => string | undefined;
options: Omit<RawVueCompilerOptions, 'target' | 'strictTemplates' | 'typesRoot' | 'plugins'>;
target: number | undefined;
typesRoot: string | undefined;
plugins: VueLanguagePlugin[];
constructor(ts: typeof import('typescript'), readFile: (fileName: string) => string | undefined);
addConfig(options: RawVueCompilerOptions, rootDir: string): void;
build(defaults?: VueCompilerOptions): VueCompilerOptions;
resolveVueVersion(folder: string): number | undefined;
}
export declare function getDefaultCompilerOptions(target?: number, lib?: string, strictTemplates?: boolean, typesRoot?: string): VueCompilerOptions;
export {};
+254
View File
@@ -0,0 +1,254 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompilerOptionsResolver = void 0;
exports.createParsedCommandLineByJson = createParsedCommandLineByJson;
exports.createParsedCommandLine = createParsedCommandLine;
exports.getDefaultCompilerOptions = getDefaultCompilerOptions;
const shared_1 = require("@vue/shared");
const path_browserify_1 = require("path-browserify");
const shared_2 = require("./utils/shared");
function createParsedCommandLineByJson(ts, host, rootDir, json, configFileName) {
const extendedPaths = new Set();
const proxyHost = {
...host,
readFile(fileName) {
if (!fileName.endsWith('/package.json')) {
extendedPaths.add(fileName);
}
return host.readFile(fileName);
},
readDirectory() {
return [];
},
};
const config = ts.readJsonConfigFile(rootDir, () => JSON.stringify(json));
const parsed = ts.parseJsonSourceFileConfigFileContent(config, proxyHost, rootDir, {}, configFileName);
const resolver = new CompilerOptionsResolver(ts, host.readFile);
for (const extendPath of [...extendedPaths].reverse()) {
try {
const configFile = ts.readJsonConfigFile(extendPath, host.readFile);
const obj = ts.convertToObject(configFile, []);
const rawOptions = obj?.vueCompilerOptions ?? {};
resolver.addConfig(rawOptions, path_browserify_1.posix.dirname(configFile.fileName));
}
catch { }
}
resolver.addConfig(json?.vueCompilerOptions ?? {}, rootDir);
return {
...parsed,
vueOptions: resolver.build(),
};
}
function createParsedCommandLine(ts, host, configFileName) {
try {
const extendedPaths = new Set();
const proxyHost = {
...host,
readFile(fileName) {
if (!fileName.endsWith('/package.json')) {
extendedPaths.add(fileName);
}
return host.readFile(fileName);
},
readDirectory() {
return [];
},
};
const config = ts.readJsonConfigFile(configFileName, proxyHost.readFile);
const parsed = ts.parseJsonSourceFileConfigFileContent(config, proxyHost, path_browserify_1.posix.dirname(configFileName), {}, configFileName);
const resolver = new CompilerOptionsResolver(ts, host.readFile);
for (const extendPath of [...extendedPaths].reverse()) {
try {
const configFile = ts.readJsonConfigFile(extendPath, host.readFile);
const obj = ts.convertToObject(configFile, []);
const rawOptions = obj?.vueCompilerOptions ?? {};
resolver.addConfig(rawOptions, path_browserify_1.posix.dirname(configFile.fileName));
}
catch { }
}
return {
...parsed,
vueOptions: resolver.build(),
};
}
catch { }
return {
options: {},
errors: [],
vueOptions: getDefaultCompilerOptions(),
};
}
class CompilerOptionsResolver {
constructor(ts, readFile) {
this.ts = ts;
this.readFile = readFile;
this.options = {};
this.plugins = [];
}
addConfig(options, rootDir) {
for (const key in options) {
switch (key) {
case 'target':
if (options[key] === 'auto') {
this.target = this.resolveVueVersion(rootDir);
}
else {
this.target = options[key];
}
break;
case 'strictTemplates':
const strict = !!options.strictTemplates;
this.options.strictVModel ??= strict;
this.options.checkUnknownProps ??= strict;
this.options.checkUnknownEvents ??= strict;
this.options.checkUnknownDirectives ??= strict;
this.options.checkUnknownComponents ??= strict;
break;
case 'typesRoot':
if (options[key] !== undefined) {
if (path_browserify_1.posix.isAbsolute(options[key])) {
this.typesRoot = options[key];
}
else {
this.typesRoot = path_browserify_1.posix.join(rootDir, options[key]);
}
}
break;
case 'plugins':
for (let raw of options.plugins ?? []) {
raw = typeof raw === 'string' ? { name: raw } : raw;
try {
const resolve = require?.resolve;
const resolvedPath = resolve?.(raw.name, { paths: [rootDir] });
if (resolvedPath) {
const plugin = require(resolvedPath);
const plugins = Array.isArray(plugin) ? plugin : [plugin];
for (const plugin of plugins) {
plugin.__moduleConfig = raw;
this.plugins.push(plugin);
}
}
else {
console.warn('[Vue] Load plugin failed:', raw.name);
}
}
catch (error) {
console.warn('[Vue] Resolve plugin path failed:', raw.name, error);
}
}
break;
default:
// @ts-expect-error
this.options[key] = options[key];
break;
}
}
if (options.target === undefined) {
this.target ??= this.resolveVueVersion(rootDir);
}
}
build(defaults = getDefaultCompilerOptions(this.target, this.options.lib, undefined, this.typesRoot)) {
const resolvedOptions = {
...defaults,
...this.options,
plugins: this.plugins,
macros: {
...defaults.macros,
...this.options.macros,
},
composables: {
...defaults.composables,
...this.options.composables,
},
fallthroughComponentNames: [
...defaults.fallthroughComponentNames,
...this.options.fallthroughComponentNames ?? [],
].map(shared_2.hyphenateTag),
// https://github.com/vuejs/core/blob/master/packages/compiler-dom/src/transforms/vModel.ts#L49-L51
// https://vuejs.org/guide/essentials/forms.html#form-input-bindings
experimentalModelPropName: Object.fromEntries(Object.entries(this.options.experimentalModelPropName ?? defaults.experimentalModelPropName).map(([k, v]) => [(0, shared_1.camelize)(k), v])),
};
return resolvedOptions;
}
resolveVueVersion(folder) {
const packageJsonPath = this.ts.findConfigFile(folder, fileName => this.readFile(fileName) !== undefined, 'node_modules/vue/package.json');
if (!packageJsonPath) {
return;
}
const packageJsonContent = this.readFile(packageJsonPath);
if (!packageJsonContent) {
return;
}
const packageJson = JSON.parse(packageJsonContent);
const version = packageJson.version;
const [majorVersion, minorVersion] = version.split('.');
return Number(majorVersion + '.' + minorVersion);
}
}
exports.CompilerOptionsResolver = CompilerOptionsResolver;
function getDefaultCompilerOptions(target = 99, lib = 'vue', strictTemplates = false, typesRoot = typeof __dirname !== 'undefined'
? path_browserify_1.posix.join(__dirname.replace(/\\/g, '/'), '..', 'types')
: '@vue/language-core/types') {
return {
target,
lib,
typesRoot,
extensions: ['.vue'],
vitePressExtensions: [],
petiteVueExtensions: [],
jsxSlots: false,
strictCssModules: false,
strictVModel: strictTemplates,
checkUnknownProps: strictTemplates,
checkUnknownEvents: strictTemplates,
checkUnknownDirectives: strictTemplates,
checkUnknownComponents: strictTemplates,
inferComponentDollarEl: false,
inferComponentDollarRefs: false,
inferTemplateDollarAttrs: false,
inferTemplateDollarEl: false,
inferTemplateDollarRefs: false,
inferTemplateDollarSlots: false,
skipTemplateCodegen: false,
fallthroughAttributes: false,
checkRequiredFallthroughAttributes: false,
resolveStyleImports: false,
resolveStyleClassNames: 'scoped',
fallthroughComponentNames: [
'Transition',
'KeepAlive',
'Teleport',
'Suspense',
],
dataAttributes: [],
htmlAttributes: ['aria-*'],
optionsWrapper: [`(await import('${lib}')).defineComponent(`, `)`],
macros: {
defineProps: ['defineProps'],
defineSlots: ['defineSlots'],
defineEmits: ['defineEmits'],
defineExpose: ['defineExpose'],
defineModel: ['defineModel'],
defineOptions: ['defineOptions'],
withDefaults: ['withDefaults'],
},
composables: {
useAttrs: ['useAttrs'],
useCssModule: ['useCssModule'],
useSlots: ['useSlots'],
useTemplateRef: ['useTemplateRef', 'templateRef'],
},
plugins: [],
experimentalModelPropName: {
'': {
input: true,
},
value: {
input: { type: 'text' },
textarea: true,
select: true,
},
},
};
}
//# sourceMappingURL=compilerOptions.js.map
+6
View File
@@ -0,0 +1,6 @@
import { type LanguagePlugin } from '@volar/language-core';
import type * as ts from 'typescript';
import type { VueCompilerOptions } from './types';
import { VueVirtualCode } from './virtualCode';
export declare function createVueLanguagePlugin<T>(ts: typeof import('typescript'), compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions, asFileName: (scriptId: T) => string): LanguagePlugin<T, VueVirtualCode>;
export declare function getAllExtensions(options: VueCompilerOptions): string[];
+142
View File
@@ -0,0 +1,142 @@
"use strict";
/// <reference types="@volar/typescript" />
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVueLanguagePlugin = createVueLanguagePlugin;
exports.getAllExtensions = getAllExtensions;
const language_core_1 = require("@volar/language-core");
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const LanguageCore = __importStar(require("../index"));
const plugins_1 = require("./plugins");
const virtualCode_1 = require("./virtualCode");
const fileRegistries = {};
function getVueFileRegistry(compilerOptions, vueCompilerOptions, plugins) {
const key = JSON.stringify([
...plugins.map(plugin => plugin.name)
.filter(name => typeof name === 'string')
.sort(),
...Object.keys(vueCompilerOptions)
.filter(key => key !== 'plugins')
.sort()
.map(key => [key, vueCompilerOptions[key]]),
...[...new Set(plugins.flatMap(plugin => plugin.requiredCompilerOptions ?? []))]
.sort()
.map(key => [key, compilerOptions[key]]),
]);
return fileRegistries[key] ??= new Map();
}
function createVueLanguagePlugin(ts, compilerOptions, vueCompilerOptions, asFileName) {
const pluginContext = {
modules: {
'@vue/compiler-dom': CompilerDOM,
'@vue/language-core': LanguageCore,
typescript: ts,
},
compilerOptions,
vueCompilerOptions,
config: {},
};
const plugins = (0, plugins_1.createPlugins)(pluginContext);
const fileRegistry = getVueFileRegistry(compilerOptions, vueCompilerOptions, plugins);
return {
getLanguageId(scriptId) {
const fileName = asFileName(scriptId);
for (const plugin of plugins) {
const languageId = plugin.getLanguageId?.(fileName);
if (languageId) {
return languageId;
}
}
},
createVirtualCode(scriptId, languageId, snapshot) {
const fileName = asFileName(scriptId);
if (plugins.some(plugin => plugin.isValidFile?.(fileName, languageId))) {
const code = fileRegistry.get(String(scriptId));
if (code) {
code.update(snapshot);
return code;
}
else {
const code = new virtualCode_1.VueVirtualCode(fileName, languageId, snapshot, vueCompilerOptions, plugins, ts);
fileRegistry.set(String(scriptId), code);
return code;
}
}
},
updateVirtualCode(_scriptId, code, snapshot) {
code.update(snapshot);
return code;
},
disposeVirtualCode(scriptId) {
fileRegistry.delete(String(scriptId));
},
typescript: {
extraFileExtensions: getAllExtensions(vueCompilerOptions)
.map(ext => ({
extension: ext.slice(1),
isMixedContent: true,
scriptKind: 7,
})),
getServiceScript(root) {
for (const code of (0, language_core_1.forEachEmbeddedCode)(root)) {
if (/script_(js|jsx|ts|tsx)/.test(code.id)) {
const lang = code.id.slice('script_'.length);
return {
code,
extension: '.' + lang,
scriptKind: lang === 'js'
? ts.ScriptKind.JS
: lang === 'jsx'
? ts.ScriptKind.JSX
: lang === 'tsx'
? ts.ScriptKind.TSX
: ts.ScriptKind.TS,
};
}
}
},
},
};
}
function getAllExtensions(options) {
return [
...new Set([
'extensions',
'vitePressExtensions',
'petiteVueExtensions',
].flatMap(key => options[key])),
];
}
//# sourceMappingURL=languagePlugin.js.map
+33
View File
@@ -0,0 +1,33 @@
import type * as ts from 'typescript';
import type { TextRange, VueCompilerOptions } from '../types';
export interface ScriptRanges extends ReturnType<typeof parseScriptRanges> {
}
export declare function parseScriptRanges(ts: typeof import('typescript'), sourceFile: ts.SourceFile, vueCompilerOptions: VueCompilerOptions): {
exportDefault: (TextRange<ts.Node> & {
expression: TextRange<ts.Expression>;
isObjectLiteral: boolean;
options?: {
isObjectLiteral: boolean;
expression: TextRange;
args: TextRange<ts.ObjectLiteralExpression>;
components: TextRange<ts.ObjectLiteralExpression> | undefined;
directives: TextRange | undefined;
name: TextRange<ts.StringLiteral> | undefined;
inheritAttrs: string | undefined;
};
}) | undefined;
bindings: TextRange<ts.Node>[];
components: TextRange<ts.Node>[];
};
export declare function parseOptionsFromExtression(ts: typeof import('typescript'), exp: ts.Node, sourceFile: ts.SourceFile): {
isObjectLiteral: boolean;
expression: TextRange<ts.Node>;
args: TextRange<ts.ObjectLiteralExpression>;
argsNode: ts.ObjectLiteralExpression;
components: TextRange<ts.ObjectLiteralExpression> | undefined;
componentsNode: ts.ObjectLiteralExpression | undefined;
directives: TextRange<ts.ObjectLiteralExpression> | undefined;
name: TextRange<ts.StringLiteral> | undefined;
nameNode: ts.StringLiteral | undefined;
inheritAttrs: string | undefined;
} | undefined;
+90
View File
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseScriptRanges = parseScriptRanges;
exports.parseOptionsFromExtression = parseOptionsFromExtression;
const shared_1 = require("../utils/shared");
const utils_1 = require("./utils");
function parseScriptRanges(ts, sourceFile, vueCompilerOptions) {
let exportDefault;
const { bindings, components } = (0, utils_1.parseBindingRanges)(ts, sourceFile, vueCompilerOptions.extensions);
ts.forEachChild(sourceFile, child => {
if (ts.isExportAssignment(child)) {
exportDefault = {
...(0, shared_1.getStartEnd)(ts, child, sourceFile),
expression: (0, shared_1.getStartEnd)(ts, child.expression, sourceFile),
isObjectLiteral: ts.isObjectLiteralExpression(child.expression),
options: parseOptionsFromExtression(ts, child.expression, sourceFile),
};
const comment = (0, utils_1.getClosestMultiLineCommentRange)(ts, child, [], sourceFile);
if (comment) {
exportDefault.start = comment.start;
}
}
});
return {
exportDefault,
bindings,
components,
};
}
function parseOptionsFromExtression(ts, exp, sourceFile) {
let obj;
while (isAsExpression(ts, exp) || ts.isParenthesizedExpression(exp)) { // fix https://github.com/vuejs/language-tools/issues/1882
exp = exp.expression;
}
if (ts.isObjectLiteralExpression(exp)) {
obj = exp;
}
else if (ts.isCallExpression(exp) && exp.arguments.length) {
const arg0 = exp.arguments[0];
if (ts.isObjectLiteralExpression(arg0)) {
obj = arg0;
}
}
if (obj) {
let componentsOptionNode;
let directivesOptionNode;
let nameOptionNode;
let inheritAttrsOption;
ts.forEachChild(obj, node => {
if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name)) {
const name = _getNodeText(node.name);
if (name === 'components' && ts.isObjectLiteralExpression(node.initializer)) {
componentsOptionNode = node.initializer;
}
else if (name === 'directives' && ts.isObjectLiteralExpression(node.initializer)) {
directivesOptionNode = node.initializer;
}
else if (name === 'name' && ts.isStringLiteral(node.initializer)) {
nameOptionNode = node.initializer;
}
else if (name === 'inheritAttrs') {
inheritAttrsOption = _getNodeText(node.initializer);
}
}
});
return {
isObjectLiteral: ts.isObjectLiteralExpression(exp),
expression: _getStartEnd(exp),
args: _getStartEnd(obj),
argsNode: obj,
components: componentsOptionNode ? _getStartEnd(componentsOptionNode) : undefined,
componentsNode: componentsOptionNode,
directives: directivesOptionNode ? _getStartEnd(directivesOptionNode) : undefined,
name: nameOptionNode ? _getStartEnd(nameOptionNode) : undefined,
nameNode: nameOptionNode,
inheritAttrs: inheritAttrsOption,
};
}
function _getStartEnd(node) {
return (0, shared_1.getStartEnd)(ts, node, sourceFile);
}
function _getNodeText(node) {
return (0, shared_1.getNodeText)(ts, node, sourceFile);
}
}
// isAsExpression is missing in tsc
function isAsExpression(ts, node) {
return node.kind === ts.SyntaxKind.AsExpression;
}
//# sourceMappingURL=scriptRanges.js.map
+60
View File
@@ -0,0 +1,60 @@
import type * as ts from 'typescript';
import type { TextRange, VueCompilerOptions } from '../types';
export interface CallExpressionRange {
callExp: TextRange;
exp: TextRange;
arg?: TextRange;
typeArg?: TextRange;
}
export interface DefineModel {
arg?: TextRange;
localName?: TextRange;
name?: TextRange;
type?: TextRange;
modifierType?: TextRange;
runtimeType?: TextRange;
defaultValue?: TextRange;
required?: boolean;
comments?: TextRange;
}
export interface DefineProps extends CallExpressionRange {
name?: string;
destructured?: Map<string, ts.Expression | undefined>;
destructuredRest?: string;
statement: TextRange;
}
export interface DefineEmits extends CallExpressionRange {
name?: string;
hasUnionTypeArg?: boolean;
statement: TextRange;
}
export interface DefineSlots extends CallExpressionRange {
name?: string;
statement: TextRange;
}
export interface DefineOptions {
name?: string;
inheritAttrs?: string;
}
export interface UseTemplateRef extends CallExpressionRange {
name?: string;
}
export interface ScriptSetupRanges extends ReturnType<typeof parseScriptSetupRanges> {
}
export declare function parseScriptSetupRanges(ts: typeof import('typescript'), sourceFile: ts.SourceFile, vueCompilerOptions: VueCompilerOptions): {
leadingCommentEndOffset: number;
importSectionEndOffset: number;
bindings: TextRange<ts.Node>[];
components: TextRange<ts.Node>[];
defineModel: DefineModel[];
defineProps: DefineProps | undefined;
withDefaults: CallExpressionRange | undefined;
defineEmits: DefineEmits | undefined;
defineSlots: DefineSlots | undefined;
defineExpose: CallExpressionRange | undefined;
defineOptions: DefineOptions | undefined;
useAttrs: CallExpressionRange[];
useCssModule: CallExpressionRange[];
useSlots: CallExpressionRange[];
useTemplateRef: UseTemplateRef[];
};
+283
View File
@@ -0,0 +1,283 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseScriptSetupRanges = parseScriptSetupRanges;
const collectBindings_1 = require("../utils/collectBindings");
const shared_1 = require("../utils/shared");
const utils_1 = require("./utils");
const tsCheckReg = /^\/\/\s*@ts-(?:no)?check(?:$|\s)/;
function parseScriptSetupRanges(ts, sourceFile, vueCompilerOptions) {
const defineModel = [];
let defineProps;
let withDefaults;
let defineEmits;
let defineSlots;
let defineExpose;
let defineOptions;
const useAttrs = [];
const useCssModule = [];
const useSlots = [];
const useTemplateRef = [];
const text = sourceFile.text;
const leadingCommentRanges = ts.getLeadingCommentRanges(text, 0)?.reverse() ?? [];
const leadingCommentEndOffset = leadingCommentRanges.find(range => tsCheckReg.test(text.slice(range.pos, range.end)))?.end ?? 0;
let { bindings, components } = (0, utils_1.parseBindingRanges)(ts, sourceFile, vueCompilerOptions.extensions);
let foundNonImportExportNode = false;
let importSectionEndOffset = 0;
ts.forEachChild(sourceFile, node => {
if (foundNonImportExportNode
|| ts.isImportDeclaration(node)
|| ts.isExportDeclaration(node)
|| ts.isEmptyStatement(node)
// fix https://github.com/vuejs/language-tools/issues/1223
|| ts.isImportEqualsDeclaration(node)) {
return;
}
if ((ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node))
&& node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) {
return;
}
const commentRanges = ts.getLeadingCommentRanges(text, node.pos);
if (commentRanges?.length) {
const commentRange = commentRanges.sort((a, b) => a.pos - b.pos)[0];
importSectionEndOffset = commentRange.pos;
}
else {
importSectionEndOffset = (0, shared_1.getStartEnd)(ts, node, sourceFile).start;
}
foundNonImportExportNode = true;
});
ts.forEachChild(sourceFile, node => visitNode(node, [sourceFile]));
const templateRefNames = new Set(useTemplateRef.map(ref => ref.name));
bindings = bindings.filter(range => {
const name = text.slice(range.start, range.end);
return !templateRefNames.has(name);
});
return {
leadingCommentEndOffset,
importSectionEndOffset,
bindings,
components,
defineModel,
defineProps,
withDefaults,
defineEmits,
defineSlots,
defineExpose,
defineOptions,
useAttrs,
useCssModule,
useSlots,
useTemplateRef,
};
function visitNode(node, parents) {
const parent = parents[parents.length - 1];
if (ts.isCallExpression(node)
&& ts.isIdentifier(node.expression)) {
const callText = _getNodeText(node.expression);
if (vueCompilerOptions.macros.defineModel.includes(callText)) {
let localName;
let propName;
let options;
let type;
let modifierType;
let runtimeType;
let defaultValue;
let required = false;
if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
localName = _getStartEnd(parent.name);
}
if (node.typeArguments) {
if (node.typeArguments.length >= 1) {
type = _getStartEnd(node.typeArguments[0]);
}
if (node.typeArguments.length >= 2) {
modifierType = _getStartEnd(node.typeArguments[1]);
}
}
if (node.arguments.length >= 2) {
propName = node.arguments[0];
options = node.arguments[1];
}
else if (node.arguments.length >= 1) {
if (ts.isStringLiteralLike(node.arguments[0])) {
propName = node.arguments[0];
}
else {
options = node.arguments[0];
}
}
if (options && ts.isObjectLiteralExpression(options)) {
for (const property of options.properties) {
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
continue;
}
const text = _getNodeText(property.name);
if (text === 'type') {
runtimeType = _getStartEnd(property.initializer);
}
else if (text === 'default') {
defaultValue = _getStartEnd(property.initializer);
}
else if (text === 'required' && property.initializer.kind === ts.SyntaxKind.TrueKeyword) {
required = true;
}
}
}
let name;
if (propName && ts.isStringLiteralLike(propName)) {
name = _getStartEnd(propName);
}
defineModel.push({
localName,
name,
type,
modifierType,
runtimeType,
defaultValue,
required,
comments: (0, utils_1.getClosestMultiLineCommentRange)(ts, node, parents, sourceFile),
arg: _getStartEnd(node),
});
}
else if (vueCompilerOptions.macros.defineProps.includes(callText)) {
defineProps = {
...parseCallExpressionAssignment(node, parent),
statement: getStatementRange(ts, parents, node, sourceFile),
};
if (ts.isVariableDeclaration(parent) && ts.isObjectBindingPattern(parent.name)) {
defineProps.destructured = new Map();
const identifiers = (0, collectBindings_1.collectBindingIdentifiers)(ts, parent.name);
for (const { id, isRest, initializer } of identifiers) {
const name = _getNodeText(id);
if (isRest) {
defineProps.destructuredRest = name;
}
else {
defineProps.destructured.set(name, initializer);
}
}
}
else if (ts.isCallExpression(parent)
&& vueCompilerOptions.macros.withDefaults.includes(_getNodeText(parent.expression))) {
const grand = parents.at(-2);
if (grand && ts.isVariableDeclaration(grand)) {
defineProps.name = _getNodeText(grand.name);
}
}
}
else if (vueCompilerOptions.macros.withDefaults.includes(callText)) {
const [, arg] = node.arguments;
withDefaults = {
callExp: _getStartEnd(node),
exp: _getStartEnd(node.expression),
arg: arg ? _getStartEnd(arg) : undefined,
};
}
else if (vueCompilerOptions.macros.defineEmits.includes(callText)) {
defineEmits = {
...parseCallExpressionAssignment(node, parent),
statement: getStatementRange(ts, parents, node, sourceFile),
};
if (node.typeArguments?.length && ts.isTypeLiteralNode(node.typeArguments[0])) {
for (const member of node.typeArguments[0].members) {
if (ts.isCallSignatureDeclaration(member)) {
const type = member.parameters[0]?.type;
if (type && ts.isUnionTypeNode(type)) {
defineEmits.hasUnionTypeArg = true;
break;
}
}
}
}
}
else if (vueCompilerOptions.macros.defineSlots.includes(callText)) {
defineSlots = {
...parseCallExpressionAssignment(node, parent),
statement: getStatementRange(ts, parents, node, sourceFile),
};
}
else if (vueCompilerOptions.macros.defineExpose.includes(callText)) {
defineExpose = parseCallExpression(node);
}
else if (vueCompilerOptions.macros.defineOptions.includes(callText)
&& node.arguments.length
&& ts.isObjectLiteralExpression(node.arguments[0])) {
defineOptions = {};
const obj = node.arguments[0];
for (const prop of obj.properties) {
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
const name = _getNodeText(prop.name);
if (name === 'inheritAttrs') {
defineOptions.inheritAttrs = _getNodeText(prop.initializer);
}
else if (name === 'name' && ts.isStringLiteral(prop.initializer)) {
defineOptions.name = prop.initializer.text;
}
}
}
}
else if (vueCompilerOptions.composables.useAttrs.includes(callText)) {
useAttrs.push(parseCallExpression(node));
}
else if (vueCompilerOptions.composables.useCssModule.includes(callText)) {
useCssModule.push(parseCallExpression(node));
}
else if (vueCompilerOptions.composables.useSlots.includes(callText)) {
useSlots.push(parseCallExpression(node));
}
else if (vueCompilerOptions.composables.useTemplateRef.includes(callText)
&& !node.typeArguments?.length) {
useTemplateRef.push(parseCallExpressionAssignment(node, parent));
}
}
ts.forEachChild(node, child => {
if (ts.isFunctionLike(node)) {
return;
}
parents.push(node);
visitNode(child, parents);
parents.pop();
});
}
function parseCallExpression(node) {
return {
callExp: _getStartEnd(node),
exp: _getStartEnd(node.expression),
arg: node.arguments.length ? _getStartEnd(node.arguments[0]) : undefined,
typeArg: node.typeArguments?.length ? _getStartEnd(node.typeArguments[0]) : undefined,
};
}
function parseCallExpressionAssignment(node, parent) {
return {
name: ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)
? _getNodeText(parent.name)
: undefined,
...parseCallExpression(node),
};
}
function _getStartEnd(node) {
return (0, shared_1.getStartEnd)(ts, node, sourceFile);
}
function _getNodeText(node) {
return (0, shared_1.getNodeText)(ts, node, sourceFile);
}
}
function getStatementRange(ts, parents, node, ast) {
let statementRange;
for (let i = parents.length - 1; i >= 0; i--) {
const statement = parents[i];
if (ts.isStatement(statement)) {
ts.forEachChild(statement, child => {
const range = (0, shared_1.getStartEnd)(ts, child, ast);
statementRange ??= range;
statementRange.end = range.end;
});
break;
}
}
if (!statementRange) {
statementRange = (0, shared_1.getStartEnd)(ts, node, ast);
}
return statementRange;
}
//# sourceMappingURL=scriptSetupRanges.js.map
+7
View File
@@ -0,0 +1,7 @@
import type * as ts from 'typescript';
import type { TextRange } from '../types';
export declare function parseBindingRanges(ts: typeof import('typescript'), ast: ts.SourceFile, componentExtsensions: string[]): {
bindings: TextRange<ts.Node>[];
components: TextRange<ts.Node>[];
};
export declare function getClosestMultiLineCommentRange(ts: typeof import('typescript'), node: ts.Node, parents: ts.Node[], ast: ts.SourceFile): TextRange | undefined;
+94
View File
@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBindingRanges = parseBindingRanges;
exports.getClosestMultiLineCommentRange = getClosestMultiLineCommentRange;
const collectBindings_1 = require("../utils/collectBindings");
const shared_1 = require("../utils/shared");
function parseBindingRanges(ts, ast, componentExtsensions) {
const bindings = [];
const components = [];
ts.forEachChild(ast, node => {
if (ts.isVariableStatement(node)) {
for (const decl of node.declarationList.declarations) {
const ranges = (0, collectBindings_1.collectBindingRanges)(ts, decl.name, ast);
bindings.push(...ranges);
}
}
else if (ts.isFunctionDeclaration(node)) {
if (node.name && ts.isIdentifier(node.name)) {
bindings.push(_getStartEnd(node.name));
}
}
else if (ts.isClassDeclaration(node)) {
if (node.name) {
bindings.push(_getStartEnd(node.name));
}
}
else if (ts.isEnumDeclaration(node)) {
bindings.push(_getStartEnd(node.name));
}
if (ts.isImportDeclaration(node)) {
const moduleName = _getNodeText(node.moduleSpecifier).slice(1, -1);
if (node.importClause && !node.importClause.isTypeOnly) {
const { name, namedBindings } = node.importClause;
if (name) {
if (componentExtsensions.some(ext => moduleName.endsWith(ext))) {
components.push(_getStartEnd(name));
}
else {
bindings.push(_getStartEnd(name));
}
}
if (namedBindings) {
if (ts.isNamedImports(namedBindings)) {
for (const element of namedBindings.elements) {
if (element.isTypeOnly) {
continue;
}
if (element.propertyName
&& _getNodeText(element.propertyName) === 'default'
&& componentExtsensions.some(ext => moduleName.endsWith(ext))) {
components.push(_getStartEnd(element.name));
}
else {
bindings.push(_getStartEnd(element.name));
}
}
}
else {
bindings.push(_getStartEnd(namedBindings.name));
}
}
}
}
});
return {
bindings,
components,
};
function _getStartEnd(node) {
return (0, shared_1.getStartEnd)(ts, node, ast);
}
function _getNodeText(node) {
return (0, shared_1.getNodeText)(ts, node, ast);
}
}
function getClosestMultiLineCommentRange(ts, node, parents, ast) {
for (let i = parents.length - 1; i >= 0; i--) {
if (ts.isStatement(node)) {
break;
}
node = parents[i];
}
const comment = ts.getLeadingCommentRanges(ast.text, node.pos)
?.reverse()
.find(range => range.kind === 3);
if (comment) {
return {
node,
start: comment.pos,
end: comment.end,
};
}
}
//# sourceMappingURL=utils.js.map
@@ -0,0 +1,2 @@
import type { RawVueCompilerOptions } from '../types';
export declare function parseVueCompilerOptions(comments: string[]): RawVueCompilerOptions | undefined;
+22
View File
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseVueCompilerOptions = parseVueCompilerOptions;
const syntaxReg = /^\s*@(?<key>.+?)\s+(?<value>.+?)\s*$/m;
function parseVueCompilerOptions(comments) {
const entries = comments
.map(text => {
try {
const match = text.match(syntaxReg);
if (match) {
const { key, value } = match.groups ?? {};
return [key, JSON.parse(value)];
}
}
catch { }
})
.filter(item => !!item);
if (entries.length) {
return Object.fromEntries(entries);
}
}
//# sourceMappingURL=vueCompilerOptions.js.map
+3
View File
@@ -0,0 +1,3 @@
import { type VueLanguagePlugin } from './types';
export * from './plugins/shared';
export declare function createPlugins(pluginContext: Parameters<VueLanguagePlugin>[0]): import("./types").VueLanguagePluginReturn[];
+88
View File
@@ -0,0 +1,88 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPlugins = createPlugins;
const file_html_1 = __importDefault(require("./plugins/file-html"));
const file_md_1 = __importDefault(require("./plugins/file-md"));
const file_vue_1 = __importDefault(require("./plugins/file-vue"));
const vue_root_tags_1 = __importDefault(require("./plugins/vue-root-tags"));
const vue_script_js_1 = __importDefault(require("./plugins/vue-script-js"));
const vue_sfc_customblocks_1 = __importDefault(require("./plugins/vue-sfc-customblocks"));
const vue_sfc_scripts_1 = __importDefault(require("./plugins/vue-sfc-scripts"));
const vue_sfc_styles_1 = __importDefault(require("./plugins/vue-sfc-styles"));
const vue_sfc_template_1 = __importDefault(require("./plugins/vue-sfc-template"));
const vue_style_css_1 = __importDefault(require("./plugins/vue-style-css"));
const vue_template_html_1 = __importDefault(require("./plugins/vue-template-html"));
const vue_template_inline_css_1 = __importDefault(require("./plugins/vue-template-inline-css"));
const vue_template_inline_ts_1 = __importDefault(require("./plugins/vue-template-inline-ts"));
const vue_tsx_1 = __importDefault(require("./plugins/vue-tsx"));
const types_1 = require("./types");
__exportStar(require("./plugins/shared"), exports);
function createPlugins(pluginContext) {
const plugins = [
file_vue_1.default,
file_md_1.default,
file_html_1.default,
vue_root_tags_1.default,
vue_tsx_1.default,
vue_script_js_1.default,
vue_style_css_1.default,
vue_template_html_1.default,
vue_template_inline_css_1.default,
vue_template_inline_ts_1.default,
vue_sfc_styles_1.default,
vue_sfc_customblocks_1.default,
vue_sfc_scripts_1.default,
vue_sfc_template_1.default,
...pluginContext.vueCompilerOptions.plugins,
];
const pluginInstances = plugins
.flatMap(plugin => {
try {
const moduleConfig = plugin.__moduleConfig ?? {};
const instance = plugin({ ...pluginContext, config: moduleConfig });
if (Array.isArray(instance)) {
for (let i = 0; i < instance.length; i++) {
instance[i].name ??= `${moduleConfig.name} (${i})`;
}
}
else {
instance.name ??= moduleConfig.name;
}
return instance;
}
catch (err) {
console.warn('[Vue] Failed to create plugin', err);
}
})
.filter(plugin => !!plugin)
.sort((a, b) => {
const aOrder = a.order ?? 0;
const bOrder = b.order ?? 0;
return aOrder - bOrder;
});
return pluginInstances.filter(plugin => {
if (!types_1.validVersions.includes(plugin.version)) {
console.warn(`[Vue] Plugin ${plugin.name} is not compatible with the current Vue language tools version. (version: ${plugin.version}, supported versions: ${JSON.stringify(types_1.validVersions)})`);
return false;
}
return true;
});
}
//# sourceMappingURL=plugins.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { VueLanguagePlugin } from '../types';
declare const plugin: VueLanguagePlugin;
export default plugin;
+91
View File
@@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const sfcBlockReg = /<(script|style)\b([\s\S]*?)>([\s\S]*?)<\/\1>/g;
const langReg = /\blang\s*=\s*(['"]?)(\S*)\b\1/;
const plugin = ({ vueCompilerOptions }) => {
return {
version: 2.2,
getLanguageId(fileName) {
if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) {
return 'html';
}
},
isValidFile(_fileName, languageId) {
return languageId === 'html';
},
parseSFC2(fileName, languageId, content) {
if (languageId !== 'html') {
return;
}
let sfc = {
descriptor: {
filename: fileName,
source: content,
comments: [],
template: null,
script: null,
scriptSetup: null,
styles: [],
customBlocks: [],
cssVars: [],
shouldForceReload: () => false,
slotted: false,
},
errors: [],
};
let templateContent = content;
for (const match of content.matchAll(sfcBlockReg)) {
const matchText = match[0];
const tag = match[1];
const attrs = match[2];
const lang = attrs.match(langReg)?.[2];
const content = match[3];
const contentStart = match.index + matchText.indexOf(content);
if (tag === 'style') {
sfc.descriptor.styles.push({
attrs: {},
content,
loc: {
start: { column: -1, line: -1, offset: contentStart },
end: { column: -1, line: -1, offset: contentStart + content.length },
source: content,
},
type: 'style',
lang,
});
}
// ignore `<script src="...">`
else if (tag === 'script' && !attrs.includes('src=')) {
let type = attrs.includes('type=') ? 'scriptSetup' : 'script';
sfc.descriptor[type] = {
attrs: {},
content,
loc: {
start: { column: -1, line: -1, offset: contentStart },
end: { column: -1, line: -1, offset: contentStart + content.length },
source: content,
},
type: 'script',
lang,
};
}
templateContent = templateContent.slice(0, match.index) + ' '.repeat(matchText.length)
+ templateContent.slice(match.index + matchText.length);
}
sfc.descriptor.template = {
attrs: {},
content: templateContent,
loc: {
start: { column: -1, line: -1, offset: 0 },
end: { column: -1, line: -1, offset: templateContent.length },
source: templateContent,
},
type: 'template',
ast: {},
};
return sfc;
},
};
};
exports.default = plugin;
//# sourceMappingURL=file-html.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { VueLanguagePlugin } from '../types';
declare const plugin: VueLanguagePlugin;
export default plugin;
+90
View File
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const language_core_1 = require("@volar/language-core");
const muggle_string_1 = require("muggle-string");
const buildMappings_1 = require("../utils/buildMappings");
const parseSfc_1 = require("../utils/parseSfc");
const frontmatterReg = /^---[\s\S]*?\n---(?:\r?\n|$)/;
const codeblockReg = /(`{3}|\${2})[\s\S]+?\1/g;
const codeSnippetImportReg = /^\s*<<<\s*.+/gm;
const sfcBlockReg = /<(script|style)\b[^>]*>([\s\S]*?)<\/\1>/g;
const htmlTagReg = /(?<=<\/?)([a-z][a-z0-9-]*)\b[^>]*(?=>)/gi;
const interpolationReg = /(?<=\{\{)[\s\S]*?(?=\}\})/g;
const inlineCodeReg = /(`{1,2})[^`]+\1/g;
const angleBracketReg = /<[^\s:]*:\S*>/g;
const plugin = ({ vueCompilerOptions }) => {
return {
version: 2.2,
getLanguageId(fileName) {
if (vueCompilerOptions.vitePressExtensions.some(ext => fileName.endsWith(ext))) {
return 'markdown';
}
},
isValidFile(_fileName, languageId) {
return languageId === 'markdown';
},
parseSFC2(_fileName, languageId, content) {
if (languageId !== 'markdown') {
return;
}
for (const reg of [frontmatterReg, codeblockReg, codeSnippetImportReg]) {
content = content.replace(reg, match => ' '.repeat(match.length));
}
const codes = [];
for (const { 0: text, index } of content.matchAll(sfcBlockReg)) {
codes.push([text, undefined, index]);
codes.push('\n\n');
content = content.slice(0, index) + ' '.repeat(text.length) + content.slice(index + text.length);
}
const ranges = [];
for (const reg of [htmlTagReg, interpolationReg]) {
for (const { 0: text, index } of content.matchAll(reg)) {
ranges.push([index, index + text.length]);
}
}
for (const reg of [inlineCodeReg, angleBracketReg]) {
for (const { 0: text, index } of content.matchAll(reg)) {
if (ranges.some(([start, end]) => index >= start && index < end)) {
continue;
}
content = content.slice(0, index) + ' '.repeat(text.length) + content.slice(index + text.length);
}
}
codes.push('<template>\n');
codes.push([content, undefined, 0]);
codes.push('\n</template>');
const mappings = (0, buildMappings_1.buildMappings)(codes);
const mapper = new language_core_1.SourceMap(mappings);
const sfc = (0, parseSfc_1.parse)((0, muggle_string_1.toString)(codes));
for (const block of [
sfc.descriptor.template,
sfc.descriptor.script,
sfc.descriptor.scriptSetup,
...sfc.descriptor.styles,
...sfc.descriptor.customBlocks,
]) {
if (block) {
transformRange(block);
}
}
return sfc;
function transformRange(block) {
const { start, end } = block.loc;
const startOffset = start.offset;
const endOffset = end.offset;
start.offset = -1;
end.offset = -1;
for (const [offset] of mapper.toSourceLocation(startOffset)) {
start.offset = offset;
break;
}
for (const [offset] of mapper.toSourceLocation(endOffset)) {
end.offset = offset;
break;
}
}
},
};
};
exports.default = plugin;
//# sourceMappingURL=file-md.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { VueLanguagePlugin } from '../types';
declare const plugin: VueLanguagePlugin;
export default plugin;
+72
View File
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const parseSfc_1 = require("../utils/parseSfc");
const plugin = ({ vueCompilerOptions }) => {
return {
version: 2.2,
getLanguageId(fileName) {
if (vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext))) {
return 'vue';
}
},
isValidFile(_fileName, languageId) {
return languageId === 'vue';
},
parseSFC2(_fileName, languageId, content) {
if (languageId !== 'vue') {
return;
}
const sfc = (0, parseSfc_1.parse)(content);
for (const error of sfc.errors) {
// Handle 'Element is missing end tag.' error, see #4893
if ('code' in error && error.code === 24 && sfc.descriptor.template
&& error.loc?.start.line === sfc.descriptor.template.loc.start.line) {
const template = sfc.descriptor.template;
const templateText = template.content;
const endTagOffset = templateText.lastIndexOf('<');
const endTagText = templateText.slice(endTagOffset).trimEnd();
if ('</template>'.startsWith(endTagText)) {
sfc.descriptor.template.loc.end.offset = template.loc.start.offset + endTagOffset;
template.content = templateText.slice(0, endTagOffset);
}
}
}
return sfc;
},
updateSFC(sfc, change) {
const blocks = [
sfc.descriptor.template,
sfc.descriptor.script,
sfc.descriptor.scriptSetup,
...sfc.descriptor.styles,
...sfc.descriptor.customBlocks,
].filter(block => !!block);
const hitBlock = blocks.find(block => change.start >= block.loc.start.offset && change.end <= block.loc.end.offset);
if (!hitBlock) {
return;
}
const oldContent = hitBlock.content;
const newContent = hitBlock.content = hitBlock.content.slice(0, change.start - hitBlock.loc.start.offset)
+ change.newText
+ hitBlock.content.slice(change.end - hitBlock.loc.start.offset);
// #3449
const endTagRegex = new RegExp(`</\\s*${hitBlock.type}\\s*>`);
const insertedEndTag = endTagRegex.test(oldContent) !== endTagRegex.test(newContent);
if (insertedEndTag) {
return;
}
const lengthDiff = change.newText.length - (change.end - change.start);
for (const block of blocks) {
if (block.loc.start.offset > change.end) {
block.loc.start.offset += lengthDiff;
}
if (block.loc.end.offset >= change.end) {
block.loc.end.offset += lengthDiff;
}
}
return sfc;
},
};
};
exports.default = plugin;
//# sourceMappingURL=file-vue.js.map
+2
View File
@@ -0,0 +1,2 @@
import type { CodeInformation } from '@volar/language-core';
export declare const allCodeFeatures: CodeInformation;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.allCodeFeatures = void 0;
exports.allCodeFeatures = {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: true,
};
//# sourceMappingURL=shared.js.map
+3
View File
@@ -0,0 +1,3 @@
import type { VueLanguagePlugin } from '../types';
declare const plugin: VueLanguagePlugin;
export default plugin;
+44
View File
@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const muggle_string_1 = require("muggle-string");
const shared_1 = require("./shared");
const plugin = () => {
return {
version: 2.2,
getEmbeddedCodes() {
return [{
id: 'root_tags',
lang: 'vue-root-tags',
}];
},
resolveEmbeddedCode(_fileName, ir, embeddedFile) {
if (embeddedFile.id === 'root_tags') {
embeddedFile.content.push([ir.content, undefined, 0, shared_1.allCodeFeatures]);
for (const block of [
ir.template,
ir.script,
ir.scriptSetup,
...ir.styles,
...ir.customBlocks,
]) {
if (!block) {
continue;
}
const offset = block.content.lastIndexOf('\n', block.content.lastIndexOf('\n') - 1) + 1;
// fix folding range end position failed to mapping
(0, muggle_string_1.replaceSourceRange)(embeddedFile.content, undefined, block.startTagEnd, block.endTagStart, ir.content.slice(block.startTagEnd, block.startTagEnd + offset), [
'',
undefined,
block.startTagEnd + offset,
{ structure: true },
], ir.content.slice(block.startTagEnd + offset, block.endTagStart));
}
}
else {
embeddedFile.parentCodeId ??= 'root_tags';
}
},
};
};
exports.default = plugin;
//# sourceMappingURL=vue-root-tags.js.map

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