first commit

This commit is contained in:
Artem Anufrij
2026-10-07 18:56:27 +02:00
commit 2a8a60b725
7768 changed files with 1550851 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.
+162
View File
@@ -0,0 +1,162 @@
# @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. |
| `vapor` | `boolean` | `false` | Enable Vapor mode for all Vue SFCs. |
| `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
+17
View File
@@ -0,0 +1,17 @@
export * from './lib/codegen/codeFeatures';
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';
+37
View File
@@ -0,0 +1,37 @@
"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/codeFeatures"), exports);
__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
+26
View File
@@ -0,0 +1,26 @@
import type { VueCodeInformation } from '../types';
export declare const codeFeatures: {
full: VueCodeInformation;
all: VueCodeInformation;
importCompletionOnly: VueCodeInformation;
verification: VueCodeInformation;
completion: VueCodeInformation;
withoutCompletion: VueCodeInformation;
navigation: VueCodeInformation;
navigationWithoutRename: VueCodeInformation;
navigationAndCompletion: VueCodeInformation;
navigationAndVerification: VueCodeInformation;
withoutNavigation: VueCodeInformation;
semanticWithoutHighlight: VueCodeInformation;
withoutHighlight: VueCodeInformation;
withoutHighlightAndCompletion: VueCodeInformation;
withoutSemantic: VueCodeInformation;
structure: VueCodeInformation;
structureAndFormat: VueCodeInformation;
format: VueCodeInformation;
doNotReportTs2339AndTs2551: VueCodeInformation;
doNotReportTs2353AndTs2561: VueCodeInformation;
doNotReportTs6133: VueCodeInformation;
};
/** @deprecated use `codeFeatures.full` instead */
export declare const allCodeFeatures: VueCodeInformation;
+127
View File
@@ -0,0 +1,127 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.allCodeFeatures = exports.codeFeatures = void 0;
exports.codeFeatures = defineCodeFeatures({
full: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: true,
},
/** @internal */
all: {
verification: true,
completion: true,
semantic: true,
navigation: true,
},
/** @internal */
importCompletionOnly: {
__importCompletion: true,
},
/** @internal */
verification: {
verification: true,
},
/** @internal */
completion: {
completion: true,
},
/** @internal */
withoutCompletion: {
verification: true,
semantic: true,
navigation: true,
},
/** @internal */
navigation: {
navigation: true,
},
/** @internal */
navigationWithoutRename: {
navigation: { shouldRename: () => false },
},
/** @internal */
navigationAndCompletion: {
navigation: true,
completion: true,
},
/** @internal */
navigationAndVerification: {
navigation: true,
verification: true,
},
/** @internal */
withoutNavigation: {
verification: true,
completion: true,
semantic: true,
},
/** @internal */
semanticWithoutHighlight: {
semantic: { shouldHighlight: () => false },
},
/** @internal */
withoutHighlight: {
semantic: { shouldHighlight: () => false },
verification: true,
navigation: true,
completion: true,
},
/** @internal */
withoutHighlightAndCompletion: {
semantic: { shouldHighlight: () => false },
verification: true,
navigation: true,
},
/** @internal */
withoutSemantic: {
verification: true,
navigation: true,
completion: true,
},
/** @internal */
structure: {
structure: true,
},
/** @internal */
structureAndFormat: {
structure: true,
format: true,
},
/** @internal */
format: {
format: true,
},
/** @internal */
doNotReportTs2339AndTs2551: {
verification: {
// https://typescript.tv/errors/#ts2339
// https://typescript.tv/errors/#ts2551
shouldReport: (_source, code) => String(code) !== '2339' && String(code) !== '2551',
},
},
/** @internal */
doNotReportTs2353AndTs2561: {
verification: {
// https://typescript.tv/errors/#ts2353
// https://typescript.tv/errors/#ts2561
shouldReport: (_source, code) => String(code) !== '2353' && String(code) !== '2561',
},
},
/** @internal */
doNotReportTs6133: {
verification: {
// https://typescript.tv/errors/#ts6133
shouldReport: (_source, code) => String(code) !== '6133',
},
},
});
/** @deprecated use `codeFeatures.full` instead */
exports.allCodeFeatures = exports.codeFeatures.full;
function defineCodeFeatures(features) {
return features;
}
//# 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, lang: string): {
generate: () => Generator<string, void, unknown>;
readonly PrettifyLocal: string;
readonly WithDefaults: string;
readonly WithSlots: string;
readonly PropsChildren: string;
readonly TypePropsToOption: string;
readonly OmitIndexSignature: string;
};
+109
View File
@@ -0,0 +1,109 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalTypesGenerator = getLocalTypesGenerator;
const utils_1 = require("./utils");
function getLocalTypesGenerator(vueCompilerOptions, lang) {
const used = new Set();
const isTs = (0, utils_1.isTsLang)(lang);
const WithDefaults = defineHelper(`__VLS_WithDefaults`, () => isTs
? `
type __VLS_WithDefaults<P, D> = {
[K in keyof P & string]: K extends keyof D
? ${PrettifyLocal.name}<P[K] & { default: D[K] }>
: P[K]
};
`.trimStart()
: jsTypedef(`P, D`, `__VLS_WithDefaults`, `{ [K in keyof Pick<P, keyof P>]: K extends keyof D ? ${PrettifyLocal.name}<P[K] & { default: D[K] }> : P[K] }`));
const PrettifyLocal = defineHelper(`__VLS_PrettifyLocal`, () => isTs
? `type __VLS_PrettifyLocal<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {}${utils_1.endOfLine}`
: jsTypedef(`T`, `__VLS_PrettifyLocal`, `(T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {}`));
const WithSlots = defineHelper(`__VLS_WithSlots`, () => isTs
? `
type __VLS_WithSlots<T, S> = T & {
new(): {
$slots: S;
}
};
`.trimStart()
: jsTypedef(`T, S`, `__VLS_WithSlots`, `T & { new(): { $slots: S; } }`));
const PropsChildren = defineHelper(`__VLS_PropsChildren`, () => isTs
? `
type __VLS_PropsChildren<S> = {
[K in keyof (
boolean extends (
// @ts-ignore
JSX.ElementChildrenAttribute extends never
? true
: false
)
? never
// @ts-ignore
: JSX.ElementChildrenAttribute
)]?: S;
};
`.trimStart()
// The single-line form lets the preceding @ts-ignore cover the whole typedef,
// mirroring the inline @ts-ignore guards of the TS form.
: `// @ts-ignore${utils_1.newLine}/** @template S @typedef {{ [K in keyof (boolean extends (JSX.ElementChildrenAttribute extends never ? true : false) ? never : JSX.ElementChildrenAttribute)]?: S; }} __VLS_PropsChildren */${utils_1.newLine}`);
const TypePropsToOption = defineHelper(`__VLS_TypePropsToOption`, () => isTs
? `
type __VLS_TypePropsToOption<T> = {
[K in keyof T & string]-?: {} extends Pick<T, K>
? { type: import('${vueCompilerOptions.lib}').PropType<Required<T>[K]> }
: { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true }
};
`.trimStart()
: jsTypedef(`T`, `__VLS_TypePropsToOption`, `{ [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 } }`));
const OmitIndexSignature = defineHelper(`__VLS_OmitIndexSignature`, () => isTs
? `type __VLS_OmitIndexSignature<T> = { [K in keyof T as {} extends Record<K, unknown> ? never : K]: T[K]; }${utils_1.endOfLine}`
: jsTypedef(`T`, `__VLS_OmitIndexSignature`, `{ [K in keyof T as {} extends Record<K, unknown> ? never : K]: T[K] }`));
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 jsTypedef(params, name, body) {
return `/**${utils_1.newLine} * @template ${params}${utils_1.newLine} * @typedef {${body}} ${name}${utils_1.newLine} */${utils_1.newLine}`;
}
function defineHelper(name, generate) {
return {
get name() {
used.add(name);
return name;
},
generate,
};
}
}
//# sourceMappingURL=localTypes.js.map
+75
View File
@@ -0,0 +1,75 @@
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;
Slots: string;
StyleModules: string;
StyleScopedClasses: string;
TemplateRefs: string;
asFunctionalComponent0: string;
asFunctionalComponent1: string;
asFunctionalDirective: string;
asFunctionalElement0: string;
asFunctionalElement1: string;
asFunctionalSlot: string;
directiveBindingRestFields: string;
functionalComponentArgsRest: string;
nonNull: string;
omit: string;
tryAsConstant: string;
unwrap: string;
vFor: string;
vSlot: string;
withDotValue: string;
ConstructorOverloads: string;
Elements: string;
EmitsToProps: string;
ExtractComponentContext: string;
ExtractComponentProps: string;
FunctionalComponent: 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 {};
+80
View File
@@ -0,0 +1,80 @@
"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: '',
Slots: '',
StyleModules: '',
StyleScopedClasses: '',
TemplateRefs: '',
// #region template helpers
asFunctionalComponent0: '',
asFunctionalComponent1: '',
asFunctionalDirective: '',
asFunctionalElement0: '',
asFunctionalElement1: '',
asFunctionalSlot: '',
directiveBindingRestFields: '',
functionalComponentArgsRest: '',
nonNull: '',
omit: '',
tryAsConstant: '',
unwrap: '',
vFor: '',
vSlot: '',
withDotValue: '',
ConstructorOverloads: '',
Elements: '',
EmitsToProps: '',
ExtractComponentContext: '',
ExtractComponentProps: '',
FunctionalComponent: '',
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
+5
View File
@@ -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>;
+112
View File
@@ -0,0 +1,112 @@
"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: ${(0, utils_1.asType)(names_1.names.TemplateRefs, options.scriptLang)},${utils_1.newLine}`;
}
if (options.vueCompilerOptions.target >= 3.5
&& options.vueCompilerOptions.inferComponentDollarEl
&& options.templateAndStyleTypes.has(names_1.names.RootEl)) {
yield `__typeEl: ${(0, utils_1.asType)(names_1.names.RootEl, options.scriptLang)},${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(options, scriptSetupRanges)]
: [];
if (typeCodes.length) {
yield `__typeEmits: ${(0, utils_1.asType)(typeCodes.join(` & `), options.scriptLang)},${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(options, scriptSetupRanges) {
if (scriptSetupRanges.defineModel.length) {
yield (0, utils_1.asType)(`${names_1.names.NormalizeEmits}<typeof ${names_1.names.modelEmit}>`, options.scriptLang);
}
if (scriptSetupRanges.defineEmits) {
yield (0, utils_1.asType)(`${names_1.names.NormalizeEmits}<typeof ${scriptSetupRanges.defineEmits.name ?? names_1.names.emit}>`, options.scriptLang);
}
}
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 (0, utils_1.asType)(attrsType, options.scriptLang);
}
if (ctx.generatedTypes.has(names_1.names.PublicProps)) {
yield (0, utils_1.asType)(names_1.names.PublicProps, options.scriptLang);
}
}
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 (0, utils_1.asType)(propsType, options.scriptLang);
}
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 (0, utils_1.asType)(propsType, options.scriptLang);
}
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, options.scriptLang);
const inlayHints = [];
return {
generatedTypes: new Set(),
localTypes,
inlayHints,
};
}
//# sourceMappingURL=context.js.map
+33
View File
@@ -0,0 +1,33 @@
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;
scriptLang: string;
scriptRanges: ScriptRanges | undefined;
scriptSetupRanges: ScriptSetupRanges | undefined;
templateAndStyleTypes: Set<string>;
templateAndStyleCodes: Code[];
setupBindings: Set<string>;
localComponents: Set<string>;
localDirectives: Set<string>;
dotValueBindings: 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[];
};
+207
View File
@@ -0,0 +1,207 @@
"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");
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;
const exportExpression = (0, utils_1.asType)(`typeof ${names_1.names.export}`, options.scriptLang);
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 boundary = yield* boundary_1.Boundary.start('main', script.src.offset, script.src.offset + script.src.text.length, {
...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, boundary.features];
yield src.slice(script.src.text.length);
yield `'`;
yield boundary.end();
yield utils_1.endOfLine;
yield `export default ${names_1.names.src}${utils_1.endOfLine}`;
yield* (0, template_1.generateTemplate)(options, 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, exportExpression);
}
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, selfType)));
}
else {
yield `await (async () => {${utils_1.newLine}`;
yield* (0, scriptSetup_1.generateSetupFunction)(options, ctx, scriptSetup, scriptSetupRanges, (0, template_1.generateTemplate)(options, 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)));
}
else {
// no script block, generate script setup code at root
yield* (0, scriptSetup_1.generateSetupFunction)(options, ctx, scriptSetup, scriptSetupRanges, (0, template_1.generateTemplate)(options), 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, exportExpression, (0, template_1.generateTemplate)(options, 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, names_1.names.export);
yield `export default ${exportExpression}${utils_1.endOfLine}`;
}
}
yield* ctx.localTypes.generate();
// The <script src> branch never embeds the script setup content, so no
// macro references can appear and the import would be unused.
if (scriptSetup && scriptSetupRanges && typeof script?.src !== 'object') {
yield* (0, scriptSetup_1.generateMacros)(options);
}
}
function* generateScriptWithExportDefault(ctx, script, scriptRanges, exportDefault, vueCompilerOptions, varName, exportExpression, 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 boundary = yield* boundary_1.Boundary.start(block.name, 0, block.content.length, codeFeatures_1.codeFeatures.doNotReportTs6133);
yield name;
yield boundary.end();
yield ` = `;
}
//# sourceMappingURL=index.js.map
+8
View File
@@ -0,0 +1,8 @@
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>;
export declare function generateMacros(options: ScriptCodegenOptions): Generator<Code>;
+498
View File
@@ -0,0 +1,498 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateScriptSetupImports = generateScriptSetupImports;
exports.generateGeneric = generateGeneric;
exports.generateSetupFunction = generateSetupFunction;
exports.generateMacros = generateMacros;
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') {
const boundary = yield* boundary_1.Boundary.start('main', generic.offset, generic.offset + generic.text.length, codeFeatures_1.codeFeatures.verification);
yield `<`;
yield [generic.text, 'main', generic.offset, codeFeatures_1.codeFeatures.all];
if (!generic.text.trimEnd().endsWith(`,`)) {
yield `,`;
}
yield `>`;
yield boundary.end();
}
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?: NonNullable<Awaited<typeof ${names_1.names.setup}>> }))${utils_1.endOfLine}`;
}
function* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, body, output) {
const transforms = [];
for (const { defaultPropsArg } of scriptSetupRanges.defineModel) {
if (defaultPropsArg) {
transforms.push({
range: [defaultPropsArg.end, defaultPropsArg.end],
*generate() {
yield `: `;
if (scriptSetupRanges.defineProps?.typeArg) {
yield names_1.names.Props;
}
else {
// FIXME: (props: typeof props) => ... would cause TS2502
yield `typeof `;
yield scriptSetupRanges.defineProps?.name ?? names_1.names.props;
}
},
});
}
}
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 (!name) {
transforms.push((0, transform_1.insert)(statement.end, function* () {
yield `${utils_1.newLine}void ${names_1.names.slots}${utils_1.endOfLine}`;
}));
}
}
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) {
const type = `typeof ${names_1.names.dollars}.$attrs`;
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield (0, utils_1.isTsLang)(options.scriptLang) ? `(` : `/** @type {${type}} */ (`;
}), (0, transform_1.insert)(callExp.end, function* () {
yield (0, utils_1.isTsLang)(options.scriptLang) ? ` as ${type})` : `)`;
}));
}
}
for (const { callExp, exp, arg } of scriptSetupRanges.useCssModule) {
const type = options.templateAndStyleTypes.has(names_1.names.StyleModules)
? names_1.names.StyleModules
: `{}`;
if (arg) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
if ((0, utils_1.isTsLang)(options.scriptLang)) {
yield `(`;
}
else {
yield `/** @type {Omit<${type}, '$style'>[`;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, arg.start, arg.end, codeFeatures_1.codeFeatures.withoutSemantic);
yield `]} */ (`;
}
}), (0, transform_1.insert)(callExp.end, function* () {
if ((0, utils_1.isTsLang)(options.scriptLang)) {
yield ` as Omit<${type}, '$style'>[`;
yield* (0, utils_1.generateSfcBlockSection)(scriptSetup, arg.start, arg.end, codeFeatures_1.codeFeatures.withoutSemantic);
yield `])`;
}
else {
yield `)`;
}
}), (0, transform_1.replace)(arg.start, arg.end, function* () {
yield (0, utils_1.asType)('any', options.scriptLang);
}));
}
else {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield (0, utils_1.isTsLang)(options.scriptLang) ? `(` : `/** @type {${type}['$style']} */ (`;
}), (0, transform_1.insert)(callExp.end, function* () {
if ((0, utils_1.isTsLang)(options.scriptLang)) {
yield ` as ${type}[`;
const boundary = yield* boundary_1.Boundary.start(scriptSetup.name, exp.start, exp.end, codeFeatures_1.codeFeatures.verification);
yield `'$style'`;
yield boundary.end();
yield `])`;
}
else {
yield `)`;
}
}));
}
}
if (options.vueCompilerOptions.inferTemplateDollarSlots) {
for (const { callExp } of scriptSetupRanges.useSlots) {
const type = `typeof ${names_1.names.dollars}.$slots`;
transforms.push((0, transform_1.insert)(callExp.start, function* () {
yield (0, utils_1.isTsLang)(options.scriptLang) ? `(` : `/** @type {${type}} */ (`;
}), (0, transform_1.insert)(callExp.end, function* () {
yield (0, utils_1.isTsLang)(options.scriptLang) ? ` as ${type})` : `)`;
}));
}
}
for (const { callExp, arg } of scriptSetupRanges.useTemplateRef) {
transforms.push((0, transform_1.insert)(callExp.start, function* () {
if ((0, utils_1.isTsLang)(options.scriptLang)) {
yield `(`;
return;
}
yield `/** @type {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>>} */ (`;
}), (0, transform_1.insert)(callExp.end, function* () {
if ((0, utils_1.isTsLang)(options.scriptLang)) {
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>>)`;
}
else {
yield `)`;
}
}));
if (arg) {
transforms.push((0, transform_1.replace)(arg.start, arg.end, function* () {
yield (0, utils_1.asType)('any', options.scriptLang);
}));
}
}
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* generateModels(options, 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 (0, utils_1.asType)(`${ctx.localTypes.WithSlots}<typeof ${names_1.names.base}, ${names_1.names.Slots}>`, options.scriptLang);
yield utils_1.endOfLine;
}
else {
yield* output;
yield* (0, component_1.generateComponent)(options, ctx, scriptSetup, scriptSetupRanges);
yield utils_1.endOfLine;
}
}
}
// An `import` (rather than `declare const`) keeps the macros resolvable in JS
// virtual files, where type-only declarations are syntax errors. Imports hoist,
// so this can be emitted after all user content: leading directives stay ahead
// of any statement, and the import-section/content junction stays intact.
function* generateMacros(options) {
if (options.vueCompilerOptions.target >= 3.3) {
const scriptSetup = options.scriptSetup;
const scriptSetupRanges = options.scriptSetupRanges;
if (!scriptSetup || !scriptSetupRanges) {
return;
}
const usedMacros = [];
const add = (canonical, exp) => {
if (exp) {
usedMacros.push({ canonical, alias: getRangeText(scriptSetup, exp) });
}
};
add('defineProps', scriptSetupRanges.defineProps?.exp);
add('defineEmits', scriptSetupRanges.defineEmits?.exp);
add('defineSlots', scriptSetupRanges.defineSlots?.exp);
add('defineExpose', scriptSetupRanges.defineExpose?.exp);
add('withDefaults', scriptSetupRanges.withDefaults?.exp);
if (scriptSetupRanges.defineModel.length) {
usedMacros.push({ canonical: 'defineModel', alias: 'defineModel' });
}
if (scriptSetupRanges.defineOptions) {
usedMacros.push({ canonical: 'defineOptions', alias: 'defineOptions' });
}
const toImport = usedMacros.filter(({ alias }) => !options.setupBindings.has(alias));
if (toImport.length) {
yield `import { `;
for (const { canonical, alias } of toImport) {
yield alias === canonical ? `${canonical}, ` : `${canonical} as ${alias}, `;
}
yield `} from '${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.identifierRE.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;
yield `void ${names_1.names.defaults}${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);
}
const target = options.vueCompilerOptions.target;
const used = !!scriptSetup.generic
|| target < 3.6
|| (target >= 3.5 && !scriptSetupRanges.defineProps?.arg);
if (propTypes.length && used) {
yield* (0, utils_1.generateTypeAlias)(names_1.names.PublicProps, options.scriptLang, function* () {
yield propTypes.join(` & `);
});
ctx.generatedTypes.add(names_1.names.PublicProps);
}
}
function hasSlotsType(options) {
return !!(options.scriptSetupRanges?.defineSlots
|| options.templateAndStyleTypes.has(names_1.names.Slots));
}
function* generateModels(options, 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(options, 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 `void ${names_1.names.defaultModels}${utils_1.endOfLine}`;
}
yield* (0, utils_1.generateTypeAlias)(names_1.names.ModelProps, options.scriptLang, function* () {
yield `{${utils_1.newLine}`;
for (const codes of propCodes) {
yield* codes;
}
yield `}`;
});
yield* (0, utils_1.generateTypeAlias)(names_1.names.ModelEmit, options.scriptLang, function* () {
yield `{${utils_1.newLine}`;
for (const codes of emitCodes) {
yield* codes;
}
yield `}`;
});
// avoid `defineModel<...>()` to prevent JS AST issues
yield* (0, utils_1.generateTypedVar)('let', names_1.names.modelEmit, options.scriptLang, function* () {
yield `${names_1.names.ShortEmits}<${names_1.names.ModelEmit}>`;
});
}
function* generateModelProp(options, scriptSetup, defineModel, propName, modelType) {
// In JS the alias body lives inside a JSDoc comment; user comments could
// contain `*/` and terminate it early, so they are dropped.
if (defineModel.comments && (0, utils_1.isTsLang)(options.scriptLang)) {
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
+3
View File
@@ -0,0 +1,3 @@
import type { Code } from '../../types';
import type { ScriptCodegenOptions } from './index';
export declare function generateTemplate(options: ScriptCodegenOptions, selfType?: string): Generator<Code>;
+117
View File
@@ -0,0 +1,117 @@
"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, selfType) {
yield* generateTemplateCtx(options, selfType);
yield* generateTemplateComponents(options);
yield* generateTemplateDirectives(options);
yield `void ${names_1.names.ctx}, ${names_1.names.components}, ${names_1.names.intrinsics}, ${names_1.names.directives}${utils_1.endOfLine}`;
for (const name of options.dotValueBindings) {
yield `// @ts-ignore${utils_1.newLine}`;
yield `${names_1.names.withDotValue}(${name}, ${(0, utils_1.getRefBrandArgument)(options.vueCompilerOptions, options.scriptLang)})${utils_1.endOfLine}`;
}
if (options.templateAndStyleCodes.length) {
yield* options.templateAndStyleCodes;
}
}
function* generateTemplateCtx({ vueCompilerOptions, templateAndStyleTypes, scriptSetupRanges, fileName, scriptLang }, selfType) {
const exps = [];
const emitTypes = [];
const propTypes = [];
if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) {
exps.push(`globalThis`);
}
if (selfType) {
exps.push((0, utils_1.asType)(`InstanceType<${names_1.names.PickNotAny}<typeof ${selfType}, new () => {}>>`, scriptLang));
}
else {
exps.push((0, utils_1.asType)(`import('${vueCompilerOptions.lib}').ComponentPublicInstance`, scriptLang));
}
if (templateAndStyleTypes.has(names_1.names.StyleModules)) {
exps.push((0, utils_1.asType)(names_1.names.StyleModules, scriptLang));
}
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* (0, utils_1.generateTypeAlias)(names_1.names.EmitProps, scriptLang, function* () {
yield `${names_1.names.EmitsToProps}<${names_1.names.NormalizeEmits}<${emitTypes.join(` & `)}>>`;
});
exps.push((0, utils_1.asType)(`{ $emit: ${emitTypes.join(` & `)} }`, scriptLang));
}
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((0, utils_1.asType)(`{ $props: ${propTypes.join(` & `)} }`, scriptLang));
exps.push((0, utils_1.asType)(propTypes.join(` & `), scriptLang));
}
yield `const ${names_1.names.ctx} = `;
yield* (0, merge_1.generateSpreadMerge)(...exps);
yield utils_1.endOfLine;
}
function* generateTemplateComponents({ vueCompilerOptions, script, scriptRanges, localComponents, scriptLang }) {
const types = [];
if (localComponents.size) {
types.push(generateExposedType(vueCompilerOptions.lib, localComponents));
}
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* (0, utils_1.generateTypeAlias)(names_1.names.LocalComponents, scriptLang, function* () {
yield types.length ? types.join(` & `) : `{}`;
});
yield* (0, utils_1.generateTypeAlias)(names_1.names.GlobalComponents, scriptLang, function* () {
yield vueCompilerOptions.target >= 3.5
? `import('${vueCompilerOptions.lib}').GlobalComponents`
: `import('${vueCompilerOptions.lib}').GlobalComponents & Pick<typeof import('${vueCompilerOptions.lib}'), 'Transition' | 'TransitionGroup' | 'KeepAlive' | 'Suspense' | 'Teleport'>`;
});
yield* (0, utils_1.generateTypedVar)('let', names_1.names.components, scriptLang, function* () {
yield `${names_1.names.LocalComponents} & ${names_1.names.GlobalComponents}`;
});
yield* (0, utils_1.generateTypedVar)('let', names_1.names.intrinsics, scriptLang, function* () {
yield vueCompilerOptions.target >= 3.3
? `import('${vueCompilerOptions.lib}/jsx-runtime').JSX.IntrinsicElements`
: `globalThis.JSX.IntrinsicElements`;
});
}
function* generateTemplateDirectives({ vueCompilerOptions, script, scriptRanges, localDirectives, scriptLang }) {
const types = [];
if (localDirectives.size) {
types.push(generateExposedType(vueCompilerOptions.lib, localDirectives));
}
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* (0, utils_1.generateTypeAlias)(names_1.names.LocalDirectives, scriptLang, function* () {
yield types.length ? types.join(` & `) : `{}`;
});
yield* (0, utils_1.generateTypedVar)('let', names_1.names.directives, scriptLang, function* () {
yield `${names_1.names.LocalDirectives} & import('${vueCompilerOptions.lib}').GlobalDirectives`;
});
}
function generateExposedType(lib, bindings) {
return `import('${lib}').ShallowUnwrapRef<{\n${[...bindings].map(name => `${name}: typeof ${name};`).join(`\n`)}\n}>`;
}
//# 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>;
+39
View File
@@ -0,0 +1,39 @@
"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 boundary = yield* boundary_1.Boundary.start(source, offset, offset + classNameWithDot.length, codeFeatures_1.codeFeatures.navigation);
yield `'`;
yield [classNameWithDot.slice(1), source, offset + 1, boundary.features];
yield `'`;
yield boundary.end();
yield `: ${propertyType}`;
yield ` }`;
}
function* generateStyleImports(style) {
if (typeof style.src === 'object') {
yield `${utils_1.newLine} & typeof import(`;
const boundary = yield* boundary_1.Boundary.start('main', style.src.offset, style.src.offset + style.src.text.length, codeFeatures_1.codeFeatures.navigationAndVerification);
yield `'`;
yield [style.src.text, 'main', style.src.offset, boundary.features];
yield `'`;
yield boundary.end();
yield `).default`;
}
for (const { text, offset } of style.imports) {
yield `${utils_1.newLine} & typeof import('`;
yield [
text,
style.name,
offset,
codeFeatures_1.codeFeatures.navigationAndVerification,
];
yield `').default`;
}
}
//# sourceMappingURL=common.js.map
+96
View File
@@ -0,0 +1,96 @@
import type { Code, IRStyle, VueCompilerOptions } from '../../types';
export interface StyleCodegenOptions {
typescript: typeof import('typescript');
vueCompilerOptions: VueCompilerOptions;
styles: readonly IRStyle[];
scriptLang: string;
setupRefs: Set<string>;
setupConsts: Set<string>;
setupBindings: Set<string>;
dotValueBindings: Set<string>;
}
export { generate as generateStyle };
declare function generate(options: StyleCodegenOptions): {
getCommentInfo: () => {
ignoreError?: boolean;
expectError?: {
token: number;
node: import("@vue/compiler-dom").CommentNode;
};
generic?: {
content: string;
offset: number;
};
};
enter: (node: import("@vue/compiler-dom").RootNode | import("@vue/compiler-dom").TemplateChildNode | import("@vue/compiler-dom").SimpleExpressionNode) => boolean;
exit: () => Generator<Code>;
resolveCodeFeatures: (features: import("../../types").VueCodeInformation) => import("../../types").VueCodeInformation;
getInternalVariable: () => string;
scopes: {
has(value: string): boolean;
readonly size: number;
declare(...variables: string[]): void;
end(): Generator<Code, any, any>;
add(value: string): /*elided*/ any;
clear(): void;
delete(value: string): boolean;
forEach(callbackfn: (value: string, value2: string, set: Set<string>) => void, thisArg?: any): void;
[Symbol.iterator](): SetIterator<string>;
entries(): SetIterator<[string, string]>;
keys(): SetIterator<string>;
values(): SetIterator<string>;
readonly [Symbol.toStringTag]: string;
}[];
scope: () => {
has(value: string): boolean;
readonly size: number;
declare(...variables: string[]): void;
end(): Generator<Code, any, any>;
add(value: string): any;
clear(): void;
delete(value: string): boolean;
forEach(callbackfn: (value: string, value2: string, set: Set<string>) => void, thisArg?: any): void;
[Symbol.iterator](): SetIterator<string>;
entries(): SetIterator<[string, string]>;
keys(): SetIterator<string>;
values(): SetIterator<string>;
readonly [Symbol.toStringTag]: string;
};
contextAccesses: Map<string, Map<string, Set<number>>>;
dotValueAccesses: Set<string>;
accessLog: string[];
accessVariable: (source: string, name: string, offset?: number, dotValue?: boolean) => void;
generateAutoImport: () => Generator<Code>;
conditions: {
text: string;
accesses: string[];
}[];
generateConditionGuards: () => Generator<string, void, unknown>;
hoistVars: Map<string, string>;
getHoistVariable: (originalVar: string) => string;
generateHoistVariables: () => Generator<string, void, unknown>;
templateRefs: Map<string, {
typeExp: string;
offset: number;
}[]>;
addTemplateRef: (name: string, typeExp: string, offset: number) => void;
components: (() => string)[];
dollarVars: Set<string>;
inlayHints: import("../inlayHints").InlayHintInfo[];
generatedTypes: Set<string>;
inheritedAttrVars: Set<string>;
singleRootElTypes: Set<string>;
singleRootNodes: Set<import("@vue/compiler-dom").ElementNode | null>;
slots: {
name: string;
offset?: number;
tagRange: [number, number];
propsVar: string;
}[];
dynamicSlots: {
expVar: string;
propsVar: string;
}[];
inVFor: boolean;
codes: Code[];
};
+42
View File
@@ -0,0 +1,42 @@
"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 styleScopedClasses_1 = require("../template/styleScopedClasses");
const utils_1 = require("../utils");
function generate(options) {
// The references registry accumulates across codegen passes; start clean.
for (const style of options.styles) {
styleScopedClasses_1.references.delete(style);
}
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 scope = ctx.scope();
yield* (0, scopedClasses_1.generateStyleScopedClasses)(options, ctx);
yield* (0, modules_1.generateStyleModules)(options, ctx);
yield* generateCssVars(options, ctx);
yield* scope.end();
}
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({ vueCompilerOptions, styles, scriptLang }: StyleCodegenOptions, ctx: TemplateCodegenContext): Generator<Code>;
+63
View File
@@ -0,0 +1,63 @@
"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 boundary_1 = require("../utils/boundary");
const common_1 = require("./common");
function* generateStyleModules({ vueCompilerOptions, styles, scriptLang }, ctx) {
const styleModules = styles.filter(style => style.module);
if (!styleModules.length) {
return;
}
ctx.generatedTypes.add(names_1.names.StyleModules);
yield* (0, utils_1.generateTypeAlias)(names_1.names.StyleModules, scriptLang, function* () {
yield `{${utils_1.newLine}`;
for (const style of styleModules) {
if (style.module === true) {
yield `$style`;
}
else {
const { text, offset } = style.module;
if (!text) {
yield [
`$style`,
'main',
offset,
codeFeatures_1.codeFeatures.verification,
];
}
else if (utils_1.identifierRE.test(text)) {
yield [
text,
'main',
offset,
codeFeatures_1.codeFeatures.navigationAndVerification,
];
}
else {
const boundary = yield* boundary_1.Boundary.start('main', offset, offset + text.length, codeFeatures_1.codeFeatures.navigationAndVerification);
yield `'`;
yield [text, 'main', offset, boundary.features];
yield `'`;
yield boundary.end();
}
}
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 `}`;
});
}
//# sourceMappingURL=modules.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 generateStyleScopedClasses({ vueCompilerOptions, styles, scriptLang }: StyleCodegenOptions, ctx: TemplateCodegenContext): Generator<Code>;
+45
View File
@@ -0,0 +1,45 @@
"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, scriptLang }, ctx) {
const { resolveStyleClassNames, resolveStyleImports } = vueCompilerOptions;
if (!resolveStyleClassNames) {
return;
}
const scopedStyles = styles.filter(style => resolveStyleClassNames === true || style.scoped);
if (!scopedStyles.length) {
return;
}
ctx.generatedTypes.add(names_1.names.StyleScopedClasses);
const visited = new Set();
const deferredGenerates = [];
yield* (0, utils_1.generateTypeAlias)(names_1.names.StyleScopedClasses, scriptLang, function* () {
yield `{}`;
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 {
deferredGenerates.push((0, styleScopedClasses_1.generateStyleScopedClassReference)(style, className.text.slice(1), className.offset + 1));
}
}
}
});
if ((0, utils_1.isTsLang)(scriptLang)) {
// avoid TS6196: JSDoc refs don't count as usage; JS @typedefs skip the check
yield `void ({} as ${names_1.names.StyleScopedClasses})${utils_1.endOfLine}`;
}
for (const generate of deferredGenerates) {
yield* generate;
}
}
//# sourceMappingURL=scopedClasses.js.map
@@ -0,0 +1,12 @@
import type * as ts from 'typescript';
import type { TemplateCodegenContext } from './context';
export interface DeclarationItem {
id: ts.Identifier;
isShorthand: boolean;
isNarrowing: boolean;
skipped: boolean;
inTypeQuery: boolean;
isNewOperand: boolean;
}
export declare function forEachDeclarations(ts: typeof import('typescript'), node: ts.Node, ast: ts.SourceFile, ctx: TemplateCodegenContext, scope: ReturnType<TemplateCodegenContext['scope']>, inNarrowing: boolean): Generator<DeclarationItem>;
export declare function shouldIdentifierSkipped(ctx: TemplateCodegenContext, text: string): boolean;
@@ -0,0 +1,564 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.forEachDeclarations = forEachDeclarations;
exports.shouldIdentifierSkipped = shouldIdentifierSkipped;
const shared_1 = require("@vue/shared");
const collectBindings_1 = require("../../utils/collectBindings");
const shared_2 = require("../../utils/shared");
const utils_1 = require("../utils");
// 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* forEachDeclarations(ts, node, ast, ctx, scope, inNarrowing) {
if (ts.isIdentifier(node)) {
yield {
id: node,
isShorthand: false,
isNarrowing: inNarrowing,
skipped: shouldIdentifierSkipped(ctx, (0, shared_2.getNodeText)(ts, node, ast)),
inTypeQuery: false,
isNewOperand: false,
};
}
else if (ts.isShorthandPropertyAssignment(node)) {
yield {
id: node.name,
isShorthand: true,
isNarrowing: inNarrowing,
skipped: shouldIdentifierSkipped(ctx, (0, shared_2.getNodeText)(ts, node.name, ast)),
inTypeQuery: false,
isNewOperand: false,
};
}
else if (ts.isPropertyAccessExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, true);
}
else if (ts.isElementAccessExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, true);
yield* forEachDeclarations(ts, node.argumentExpression, ast, ctx, scope, false);
}
else if (ts.isCallExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, false);
if (node.typeArguments) {
for (const typeArg of node.typeArguments) {
yield* forEachDeclarationsInTypeNode(ts, typeArg, ast, ctx, scope);
}
}
for (const arg of node.arguments) {
yield* forEachDeclarations(ts, arg, ast, ctx, scope, inNarrowing);
}
}
else if (ts.isNewExpression(node)) {
if (ts.isIdentifier(node.expression)) {
yield {
id: node.expression,
isShorthand: false,
isNarrowing: false,
skipped: shouldIdentifierSkipped(ctx, (0, shared_2.getNodeText)(ts, node.expression, ast)),
inTypeQuery: false,
isNewOperand: true,
};
}
else {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, false);
}
if (node.typeArguments) {
for (const typeArg of node.typeArguments) {
yield* forEachDeclarationsInTypeNode(ts, typeArg, ast, ctx, scope);
}
}
for (const arg of node.arguments ?? []) {
yield* forEachDeclarations(ts, arg, ast, ctx, scope, inNarrowing);
}
}
else if (ts.isTaggedTemplateExpression(node)) {
yield* forEachDeclarations(ts, node.tag, ast, ctx, scope, false);
yield* forEachDeclarations(ts, node.template, ast, ctx, scope, inNarrowing);
}
else if (ts.isParenthesizedExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, inNarrowing);
}
else if (ts.isNonNullExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, inNarrowing);
}
else if (ts.isTypeAssertionExpression(node)) {
yield* forEachDeclarationsInTypeNode(ts, node.type, ast, ctx, scope);
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, inNarrowing);
}
else if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, inNarrowing);
yield* forEachDeclarationsInTypeNode(ts, node.type, ast, ctx, scope);
}
else if (ts.isBinaryExpression(node)) {
const isLogical = node.operatorToken.kind === ts.SyntaxKind.BarBarToken
|| node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
|| node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken;
const isAssignment = node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment
&& node.operatorToken.kind <= ts.SyntaxKind.LastAssignment;
const isEquality = node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken
|| node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken
|| node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken
|| node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken;
const isInstanceof = node.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword;
const isIn = node.operatorToken.kind === ts.SyntaxKind.InKeyword;
if (node.operatorToken.kind === ts.SyntaxKind.CommaToken) {
yield* forEachDeclarations(ts, node.left, ast, ctx, scope, false);
yield* forEachDeclarations(ts, node.right, ast, ctx, scope, inNarrowing);
}
else if (isLogical) {
yield* forEachNarrowedBy(ts, node.left, ast, ctx, scope, function* () {
yield* forEachDeclarations(ts, node.right, ast, ctx, scope, inNarrowing);
});
}
else if (isAssignment) {
yield* forEachDeclarationsInAssignmentTarget(ts, node.left, ast, ctx, scope);
yield* forEachDeclarations(ts, node.right, ast, ctx, scope, false);
}
else {
yield* forEachDeclarations(ts, node.left, ast, ctx, scope, isEquality || isInstanceof);
yield* forEachDeclarations(ts, node.right, ast, ctx, scope, isEquality || isIn);
}
}
else if (ts.isConditionalExpression(node)) {
yield* forEachNarrowedBy(ts, node.condition, ast, ctx, scope, function* () {
yield* forEachDeclarations(ts, node.whenTrue, ast, ctx, scope, false);
yield* forEachDeclarations(ts, node.whenFalse, ast, ctx, scope, false);
});
}
else if (ts.isPrefixUnaryExpression(node)) {
yield* forEachDeclarations(ts, node.operand, ast, ctx, scope, node.operator === ts.SyntaxKind.ExclamationToken
|| node.operator === ts.SyntaxKind.PlusPlusToken
|| node.operator === ts.SyntaxKind.MinusMinusToken);
}
else if (ts.isPostfixUnaryExpression(node)) {
yield* forEachDeclarations(ts, node.operand, ast, ctx, scope, true);
}
else if (isDeleteExpression(ts, node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, true);
}
else if (ts.isTypeOfExpression(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, true);
}
else if (ts.isVariableDeclaration(node)) {
scope.declare(...(0, collectBindings_1.collectBindingNames)(ts, node.name, ast));
yield* forEachDeclarationsInBinding(ts, node, ast, ctx, scope);
}
else if (ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node)) {
for (const element of node.elements) {
if (ts.isBindingElement(element)) {
yield* forEachDeclarationsInBinding(ts, element, ast, ctx, scope);
}
}
}
else if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
yield* forEachDeclarationsInFunction(ts, node, ast, ctx);
}
else if (ts.isFunctionDeclaration(node)) {
if (node.name) {
scope.declare((0, shared_2.getNodeText)(ts, node.name, ast));
}
yield* forEachDeclarationsInFunction(ts, node, ast, ctx);
}
else if (ts.isClassDeclaration(node)) {
if (node.name) {
scope.declare((0, shared_2.getNodeText)(ts, node.name, ast));
}
yield* forEachDeclarationsInClass(ts, node, ast, ctx, scope);
}
else if (ts.isClassExpression(node)) {
const classScope = ctx.scope();
if (node.name) {
classScope.declare((0, shared_2.getNodeText)(ts, node.name, ast));
}
yield* forEachDeclarationsInClass(ts, node, ast, ctx, classScope);
classScope.end();
}
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, scope, false);
}
yield* forEachDeclarations(ts, prop.initializer, ast, ctx, scope, false);
}
// fix https://github.com/vuejs/language-tools/issues/1156
else if (ts.isShorthandPropertyAssignment(prop)) {
yield* forEachDeclarations(ts, prop, ast, ctx, scope, false);
}
// 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, scope, false);
}
// fix https://github.com/vuejs/language-tools/issues/4604
else if (ts.isFunctionLike(prop) && prop.body) {
if (prop.name && ts.isComputedPropertyName(prop.name)) {
yield* forEachDeclarations(ts, prop.name.expression, ast, ctx, scope, false);
}
yield* forEachDeclarationsInFunction(ts, prop, ast, ctx);
}
}
}
// fix https://github.com/vuejs/language-tools/issues/1422
else if (ts.isTypeNode(node)) {
yield* forEachDeclarationsInTypeNode(ts, node, ast, ctx, scope);
}
else if (ts.isBlock(node)) {
const scope = ctx.scope();
predeclareFunctionDeclarations(ts, node.statements, ast, scope);
for (const child of (0, utils_1.forEachNode)(ts, node)) {
yield* forEachDeclarations(ts, child, ast, ctx, scope, false);
}
scope.end();
}
else if (ts.isForOfStatement(node) || ts.isForInStatement(node)) {
const scope = ctx.scope();
const declarations = ts.isVariableDeclarationList(node.initializer) ? node.initializer.declarations : undefined;
if (declarations) {
for (const decl of declarations) {
if (decl.initializer) {
yield* forEachDeclarations(ts, decl.initializer, ast, ctx, scope, false);
}
}
}
else {
yield* forEachDeclarationsInAssignmentTarget(ts, node.initializer, ast, ctx, scope);
}
// The source resolves before the loop bindings are in scope (`for (const x of x)` reads the outer `x`).
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, false);
if (declarations) {
for (const decl of declarations) {
scope.declare(...(0, collectBindings_1.collectBindingNames)(ts, decl.name, ast));
}
}
yield* forEachDeclarations(ts, node.statement, ast, ctx, scope, false);
scope.end();
}
else if (ts.isIfStatement(node)) {
yield* forEachNarrowedBy(ts, node.expression, ast, ctx, scope, function* () {
yield* forEachDeclarations(ts, node.thenStatement, ast, ctx, scope, false);
if (node.elseStatement) {
yield* forEachDeclarations(ts, node.elseStatement, ast, ctx, scope, false);
}
});
}
else if (isWhileStatement(ts, node)) {
yield* forEachNarrowedBy(ts, node.expression, ast, ctx, scope, function* () {
yield* forEachDeclarations(ts, node.statement, ast, ctx, scope, false);
});
}
else if (isDoStatement(ts, node)) {
yield* forEachDeclarations(ts, node.statement, ast, ctx, scope, false);
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, true);
}
else if (ts.isForStatement(node)) {
const scope = ctx.scope();
if (node.initializer) {
if (ts.isVariableDeclarationList(node.initializer)) {
for (const decl of node.initializer.declarations) {
scope.declare(...(0, collectBindings_1.collectBindingNames)(ts, decl.name, ast));
if (decl.initializer) {
yield* forEachDeclarations(ts, decl.initializer, ast, ctx, scope, false);
}
}
}
else {
yield* forEachDeclarations(ts, node.initializer, ast, ctx, scope, false);
}
}
yield* forEachNarrowedBy(ts, node.condition, ast, ctx, scope, function* () {
if (node.incrementor) {
yield* forEachDeclarations(ts, node.incrementor, ast, ctx, scope, false);
}
yield* forEachDeclarations(ts, node.statement, ast, ctx, scope, false);
});
scope.end();
}
else if (ts.isSwitchStatement(node)) {
predeclareFunctionDeclarations(ts, node.caseBlock.clauses.flatMap(clause => [...clause.statements]), ast, scope);
yield* forEachNarrowedBy(ts, node.expression, ast, ctx, scope, function* () {
for (const clause of node.caseBlock.clauses) {
if (ts.isCaseClause(clause)) {
yield* forEachDeclarations(ts, clause.expression, ast, ctx, scope, false);
}
for (const statement of clause.statements) {
yield* forEachDeclarations(ts, statement, ast, ctx, scope, false);
}
}
});
}
else if (ts.isLabeledStatement(node)) {
yield* forEachDeclarations(ts, node.statement, ast, ctx, scope, false);
}
else if (isBreakOrContinueStatement(ts, node)) {
// break/continue labels are not bindings.
}
else if (ts.isMetaProperty(node)) {
// `new.target` / `import.meta` are not bindings.
}
else if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
yield* forEachDeclarationsInTypeNode(ts, node, ast, ctx, scope);
}
else if (ts.isEnumDeclaration(node)) {
scope.declare((0, shared_2.getNodeText)(ts, node.name, ast));
for (const member of node.members) {
if (member.initializer) {
yield* forEachDeclarations(ts, member.initializer, ast, ctx, scope, false);
}
}
}
else if (ts.isModuleDeclaration(node)) {
if (node.body && ts.isModuleBlock(node.body)) {
const scope = ctx.scope();
predeclareFunctionDeclarations(ts, node.body.statements, ast, scope);
for (const statement of node.body.statements) {
yield* forEachDeclarations(ts, statement, ast, ctx, scope, false);
}
scope.end();
}
else if (node.body && ts.isModuleDeclaration(node.body)) {
yield* forEachDeclarations(ts, node.body, ast, ctx, scope, false);
}
}
else if (ts.isCatchClause(node)) {
const scope = ctx.scope();
if (node.variableDeclaration) {
yield* forEachDeclarations(ts, node.variableDeclaration, ast, ctx, scope, false);
}
if (node.block) {
yield* forEachDeclarations(ts, node.block, ast, ctx, scope, false);
}
scope.end();
}
else if (ts.isSourceFile(node)) {
predeclareFunctionDeclarations(ts, node.statements, ast, scope);
for (const statement of node.statements) {
yield* forEachDeclarations(ts, statement, ast, ctx, scope, inNarrowing);
}
}
else if (ts.isExpressionStatement(node)) {
yield* forEachDeclarations(ts, node.expression, ast, ctx, scope, inNarrowing);
}
else {
for (const child of (0, utils_1.forEachNode)(ts, node)) {
yield* forEachDeclarations(ts, child, ast, ctx, scope, false);
}
}
}
function* forEachNarrowedBy(ts, condition, ast, ctx, scope, body) {
// The condition's declarations come first (narrowing positions), then the body.
if (condition) {
yield* forEachDeclarations(ts, condition, ast, ctx, scope, true);
}
yield* body();
}
function predeclareFunctionDeclarations(ts, statements, ast, scope) {
for (const statement of statements) {
if (ts.isFunctionDeclaration(statement) && statement.name) {
scope.declare((0, shared_2.getNodeText)(ts, statement.name, ast));
}
}
}
function* forEachDeclarationsInAssignmentTarget(ts, node, ast, ctx, scope) {
if (ts.isIdentifier(node)) {
yield {
id: node,
isShorthand: false,
isNarrowing: true,
skipped: shouldIdentifierSkipped(ctx, (0, shared_2.getNodeText)(ts, node, ast)),
inTypeQuery: false,
isNewOperand: false,
};
}
else if (ts.isObjectLiteralExpression(node)) {
for (const prop of node.properties) {
if (ts.isPropertyAssignment(prop)) {
if (ts.isComputedPropertyName(prop.name)) {
yield* forEachDeclarations(ts, prop.name.expression, ast, ctx, scope, false);
}
yield* forEachDeclarationsInAssignmentTarget(ts, prop.initializer, ast, ctx, scope);
}
else if (ts.isShorthandPropertyAssignment(prop)) {
yield {
id: prop.name,
isShorthand: true,
isNarrowing: true,
skipped: shouldIdentifierSkipped(ctx, (0, shared_2.getNodeText)(ts, prop.name, ast)),
inTypeQuery: false,
isNewOperand: false,
};
if (prop.objectAssignmentInitializer) {
yield* forEachDeclarations(ts, prop.objectAssignmentInitializer, ast, ctx, scope, false);
}
}
else if (ts.isSpreadAssignment(prop)) {
yield* forEachDeclarationsInAssignmentTarget(ts, prop.expression, ast, ctx, scope);
}
}
}
else if (ts.isArrayLiteralExpression(node)) {
for (const element of node.elements) {
if (ts.isOmittedExpression(element)) {
continue;
}
else if (ts.isSpreadElement(element)) {
yield* forEachDeclarationsInAssignmentTarget(ts, element.expression, ast, ctx, scope);
}
else if (ts.isBinaryExpression(element)) {
yield* forEachDeclarationsInAssignmentTarget(ts, element.left, ast, ctx, scope);
yield* forEachDeclarations(ts, element.right, ast, ctx, scope, false);
}
else {
yield* forEachDeclarationsInAssignmentTarget(ts, element, ast, ctx, scope);
}
}
}
else if (ts.isParenthesizedExpression(node)) {
yield* forEachDeclarationsInAssignmentTarget(ts, node.expression, ast, ctx, scope);
}
else {
yield* forEachDeclarations(ts, node, ast, ctx, scope, true);
}
}
function* forEachDeclarationsInBinding(ts, node, ast, ctx, scope) {
if ('propertyName' in node && node.propertyName && ts.isComputedPropertyName(node.propertyName)) {
yield* forEachDeclarations(ts, node.propertyName.expression, ast, ctx, scope, true);
}
if (!ts.isIdentifier(node.name)) {
yield* forEachDeclarations(ts, node.name, ast, ctx, scope, false);
}
if ('type' in node && node.type) {
yield* forEachDeclarationsInTypeNode(ts, node.type, ast, ctx, scope);
}
if (node.initializer) {
yield* forEachDeclarations(ts, node.initializer, ast, ctx, scope, false);
}
}
function* forEachDeclarationsInFunction(ts, node, ast, ctx) {
const scope = ctx.scope();
if (ts.isFunctionExpression(node) && node.name) {
scope.declare((0, shared_2.getNodeText)(ts, node.name, ast));
}
for (const param of node.parameters) {
scope.declare(...(0, collectBindings_1.collectBindingNames)(ts, param.name, ast));
}
if (node.typeParameters) {
for (const typeParam of node.typeParameters) {
yield* forEachDeclarationsInTypeNode(ts, typeParam, ast, ctx, scope);
}
}
for (const param of node.parameters) {
yield* forEachDeclarationsInBinding(ts, param, ast, ctx, scope);
}
if (node.type) {
yield* forEachDeclarationsInTypeNode(ts, node.type, ast, ctx, scope);
}
if (node.body) {
yield* forEachDeclarations(ts, node.body, ast, ctx, scope, false);
}
scope.end();
}
function* forEachDeclarationsInClass(ts, node, ast, ctx, scope) {
for (const typeParam of node.typeParameters ?? []) {
yield* forEachDeclarationsInTypeNode(ts, typeParam, ast, ctx, scope);
}
for (const clause of node.heritageClauses ?? []) {
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
for (const type of clause.types) {
yield* forEachDeclarations(ts, type.expression, ast, ctx, scope, false);
if (type.typeArguments) {
for (const typeArg of type.typeArguments) {
yield* forEachDeclarationsInTypeNode(ts, typeArg, ast, ctx, scope);
}
}
}
}
else {
yield* forEachDeclarationsInTypeNode(ts, clause, ast, ctx, scope);
}
}
for (const member of node.members) {
if (ts.isPropertyDeclaration(member)
|| ts.isMethodDeclaration(member)
|| ts.isGetAccessorDeclaration(member)
|| ts.isSetAccessorDeclaration(member)) {
if (member.name && ts.isComputedPropertyName(member.name)) {
// A computed name in a class property must be an entity name (grammar rule): no `__VLS_unwrap` call allowed.
yield* forEachDeclarations(ts, member.name.expression, ast, ctx, scope, true);
}
}
if (ts.isConstructorDeclaration(member)
|| ts.isMethodDeclaration(member)
|| ts.isGetAccessorDeclaration(member)
|| ts.isSetAccessorDeclaration(member)) {
yield* forEachDeclarationsInFunction(ts, member, ast, ctx);
}
else if (ts.isPropertyDeclaration(member)) {
if (member.type) {
yield* forEachDeclarationsInTypeNode(ts, member.type, ast, ctx, scope);
}
if (member.initializer) {
yield* forEachDeclarations(ts, member.initializer, ast, ctx, scope, false);
}
}
else if (ts.isClassStaticBlockDeclaration(member)) {
const blockScope = ctx.scope();
predeclareFunctionDeclarations(ts, member.body.statements, ast, blockScope);
for (const statement of member.body.statements) {
yield* forEachDeclarations(ts, statement, ast, ctx, blockScope, false);
}
blockScope.end();
}
}
}
function* forEachDeclarationsInTypeNode(ts, node, ast, ctx, scope) {
if (ts.isTypeQueryNode(node)) {
let id = node.exprName;
while (!ts.isIdentifier(id)) {
id = id.left;
}
yield {
id,
isShorthand: false,
isNarrowing: false,
skipped: shouldIdentifierSkipped(ctx, (0, shared_2.getNodeText)(ts, id, ast)),
inTypeQuery: true,
isNewOperand: false,
};
}
else if (ts.isComputedPropertyName(node)) {
// TS1170: a computed name in a type literal must be an entity-name expression (no calls).
for (const item of forEachDeclarations(ts, node.expression, ast, ctx, scope, false)) {
item.inTypeQuery = true;
yield item;
}
}
else {
for (const child of (0, utils_1.forEachNode)(ts, node)) {
yield* forEachDeclarationsInTypeNode(ts, child, ast, ctx, scope);
}
}
}
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_');
}
// vue-tsc runs against TypeScript's tsc bundle, which does not include
// type guards that the compiler itself never uses, so check `kind` directly.
function isDeleteExpression(ts, node) {
return node.kind === ts.SyntaxKind.DeleteExpression;
}
function isWhileStatement(ts, node) {
return node.kind === ts.SyntaxKind.WhileStatement;
}
function isDoStatement(ts, node) {
return node.kind === ts.SyntaxKind.DoStatement;
}
function isBreakOrContinueStatement(ts, node) {
return node.kind === ts.SyntaxKind.BreakStatement || node.kind === ts.SyntaxKind.ContinueStatement;
}
//# sourceMappingURL=bindingReferences.js.map
+87
View File
@@ -0,0 +1,87 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code, VueCodeInformation } from '../../types';
import type { InlayHintInfo } from '../inlayHints';
export type TemplateCodegenContext = ReturnType<typeof createTemplateCodegenContext>;
export declare function createTemplateCodegenContext(): {
getCommentInfo: () => {
ignoreError?: boolean;
expectError?: {
token: number;
node: CompilerDOM.CommentNode;
};
generic?: {
content: string;
offset: number;
};
};
enter: (node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode | CompilerDOM.SimpleExpressionNode) => boolean;
exit: () => Generator<Code>;
resolveCodeFeatures: (features: VueCodeInformation) => VueCodeInformation;
getInternalVariable: () => string;
scopes: {
has(value: string): boolean;
readonly size: number;
declare(...variables: string[]): void;
end(): Generator<Code, any, any>;
add(value: string): /*elided*/ any;
clear(): void;
delete(value: string): boolean;
forEach(callbackfn: (value: string, value2: string, set: Set<string>) => void, thisArg?: any): void;
[Symbol.iterator](): SetIterator<string>;
entries(): SetIterator<[string, string]>;
keys(): SetIterator<string>;
values(): SetIterator<string>;
readonly [Symbol.toStringTag]: string;
}[];
scope: () => {
has(value: string): boolean;
readonly size: number;
declare(...variables: string[]): void;
end(): Generator<Code, any, any>;
add(value: string): any;
clear(): void;
delete(value: string): boolean;
forEach(callbackfn: (value: string, value2: string, set: Set<string>) => void, thisArg?: any): void;
[Symbol.iterator](): SetIterator<string>;
entries(): SetIterator<[string, string]>;
keys(): SetIterator<string>;
values(): SetIterator<string>;
readonly [Symbol.toStringTag]: string;
};
contextAccesses: Map<string, Map<string, Set<number>>>;
dotValueAccesses: Set<string>;
accessLog: string[];
accessVariable: (source: string, name: string, offset?: number, dotValue?: boolean) => void;
generateAutoImport: () => Generator<Code>;
conditions: {
text: string;
accesses: string[];
}[];
generateConditionGuards: () => Generator<string, void, unknown>;
hoistVars: Map<string, string>;
getHoistVariable: (originalVar: string) => string;
generateHoistVariables: () => Generator<string, void, unknown>;
templateRefs: Map<string, {
typeExp: string;
offset: number;
}[]>;
addTemplateRef: (name: string, typeExp: string, offset: number) => void;
components: (() => string)[];
dollarVars: Set<string>;
inlayHints: InlayHintInfo[];
generatedTypes: Set<string>;
inheritedAttrVars: Set<string>;
singleRootElTypes: Set<string>;
singleRootNodes: Set<CompilerDOM.ElementNode | null>;
slots: {
name: string;
offset?: number;
tagRange: [number, number];
propsVar: string;
}[];
dynamicSlots: {
expVar: string;
propsVar: string;
}[];
inVFor: boolean;
};
+337
View File
@@ -0,0 +1,337 @@
"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 language_core_1 = require("@volar/language-core");
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const codeFeatures_1 = require("../codeFeatures");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const directiveCommentRE = /^<!--\s*@vue-(?<name>[-\w]+)\b(?<content>[\s\S]*)-->$/;
// Reserved words can never be auto-imported bindings, and emitting them as
// bare array elements is a syntax error (#5267: `[class,]`).
const reservedWords = new Set([
'arguments',
'await',
'break',
'case',
'catch',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'else',
'enum',
'eval',
'export',
'extends',
'false',
'finally',
'for',
'function',
'if',
'implements',
'import',
'in',
'instanceof',
'interface',
'let',
'new',
'null',
'package',
'private',
'protected',
'public',
'return',
'static',
'super',
'switch',
'this',
'throw',
'true',
'try',
'typeof',
'var',
'void',
'while',
'with',
'yield',
]);
function createTemplateCodegenContext() {
// directive comments ---------------------------------------------------------
const stack = [];
const commentBuffer = [];
function getCommentInfo() {
return stack[stack.length - 1];
}
function enter(node) {
if (node.type === CompilerDOM.NodeTypes.COMMENT) {
commentBuffer.push(node);
return false;
}
const info = {};
const comments = [...commentBuffer];
commentBuffer.length = 0;
for (const comment of comments) {
const match = comment.loc.source.match(directiveCommentRE);
if (match) {
const { name, content } = match.groups;
switch (name) {
case 'skip': {
return false;
}
case 'ignore': {
info.ignoreError = true;
break;
}
case 'expect-error': {
info.expectError = {
token: 0,
node: comment,
};
break;
}
case 'generic': {
const text = content.trim();
if (text.startsWith('{') && text.endsWith('}')) {
info.generic = {
content: text.slice(1, -1),
offset: comment.loc.start.offset + comment.loc.source.indexOf('{') + 1,
};
}
break;
}
}
}
}
stack.push(info);
return true;
}
function* exit() {
const info = stack.pop();
commentBuffer.length = 0;
if (info.expectError !== undefined) {
const boundary = yield* boundary_1.Boundary.start('template', info.expectError.node.loc.start.offset, info.expectError.node.loc.end.offset, {
verification: {
shouldReport: () => info.expectError.token === 0,
},
});
yield `// @ts-expect-error`;
yield boundary.end();
yield `${utils_1.newLine}${utils_1.endOfLine}`;
}
}
function resolveCodeFeatures(features) {
if (features.verification && stack.length) {
const data = stack[stack.length - 1];
if (data.ignoreError) {
return {
...features,
verification: false,
};
}
if (data.expectError !== undefined) {
return {
...features,
verification: {
shouldReport: (source, code) => {
if ((0, language_core_1.shouldReportDiagnostics)(features, source, code)) {
data.expectError.token++;
}
return false;
},
},
};
}
}
return features;
}
// internal variables ---------------------------------------------------------
let variableId = 0;
function getInternalVariable() {
return `__VLS_${variableId++}`;
}
// scopes ---------------------------------------------------------------------
class Scope extends Set {
declare(...variables) {
for (const name of variables) {
this.add(name);
}
}
end() {
scopes.pop();
return generateAutoImport();
}
}
const scopes = [];
function scope() {
const scope = new Scope();
scopes.push(scope);
return scope;
}
// context accesses -----------------------------------------------------------
const contextAccesses = new Map();
const dotValueAccesses = new Set();
// Ordered log of accessed names; event-handler closures slice from a mark
// to find the names accessed within their body.
const accessLog = [];
function accessVariable(source, name, offset, dotValue = false) {
accessLog.push(name);
let map = contextAccesses.get(name);
if (!map) {
contextAccesses.set(name, map = new Map());
}
let arr = map.get(source);
if (!arr) {
map.set(source, arr = new Set());
}
if (offset !== undefined) {
arr.add(offset);
}
if (dotValue) {
dotValueAccesses.add(name);
}
}
function* generateAutoImport() {
const all = [...contextAccesses.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) {
if (!reservedWords.has(varName)) {
for (const offset of offsets) {
yield [varName, source, offset, codeFeatures_1.codeFeatures.importCompletionOnly];
yield `,`;
}
}
offsets.clear();
}
}
yield `]${utils_1.endOfLine}`;
}
// conditions -----------------------------------------------------------------
// Active branch conditions with the names each accessed; the guards are
// replayed inside inline-handler closures.
const conditions = [];
function* generateConditionGuards() {
for (const condition of conditions) {
if (condition.accesses.length && condition.accesses.every(name => scopes.some(scope => scope.has(name)))) {
continue;
}
yield `if (!${condition.text}) throw 0${utils_1.endOfLine}`;
}
}
// hoist vars -----------------------------------------------------------------
const hoistVars = new Map();
function getHoistVariable(originalVar) {
let name = hoistVars.get(originalVar);
if (name === undefined) {
hoistVars.set(originalVar, name = `__VLS_${variableId++}`);
}
return name;
}
function* generateHoistVariables() {
// trick to avoid TS 4081 (#5186)
if (hoistVars.size) {
yield `var `;
let first = true;
for (const [originalVar, hoistVar] of hoistVars) {
if (!first) {
yield `, `;
}
first = false;
yield `${hoistVar} = ${originalVar}!`;
}
yield utils_1.endOfLine;
}
}
// template refs --------------------------------------------------------------
const templateRefs = new Map();
function addTemplateRef(name, typeExp, offset) {
let refs = templateRefs.get(name);
if (!refs) {
templateRefs.set(name, refs = []);
}
refs.push({ typeExp, offset });
}
// others ---------------------------------------------------------------------
const components = [];
const dollarVars = new Set();
const inlayHints = [];
const generatedTypes = new Set();
const inheritedAttrVars = new Set();
const singleRootElTypes = new Set();
const singleRootNodes = new Set();
const slots = [];
const dynamicSlots = [];
return {
getCommentInfo,
enter,
exit,
resolveCodeFeatures,
getInternalVariable,
scopes,
scope,
contextAccesses,
dotValueAccesses,
accessLog,
accessVariable,
generateAutoImport,
conditions,
generateConditionGuards,
hoistVars,
getHoistVariable,
generateHoistVariables,
templateRefs,
addTemplateRef,
components,
dollarVars,
inlayHints,
generatedTypes,
inheritedAttrVars,
singleRootElTypes,
singleRootNodes,
slots,
dynamicSlots,
inVFor: false,
};
}
//# sourceMappingURL=context.js.map
+7
View File
@@ -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>;
+336
View File
@@ -0,0 +1,336 @@
"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 matchedImportedComponent = [...originalNames].find(name => options.importedComponents.has(name));
if (matchedImportedComponent) {
// navigation & auto import support
yield `const ${componentVar} = `;
yield* (0, camelized_1.generateCamelized)(matchedImportedComponent[0] + tag.slice(1), 'template', startTagOffset, {
...codeFeatures_1.codeFeatures.withoutHighlightAndCompletion,
...codeFeatures_1.codeFeatures.importCompletionOnly,
});
if (endTagOffset !== undefined) {
yield ` || `;
yield* (0, camelized_1.generateCamelized)(matchedImportedComponent[0] + tag.slice(1), 'template', endTagOffset, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
}
yield utils_1.endOfLine;
}
else {
yield* (0, utils_1.generateTypedVar)('let', componentVar, options.scriptLang, function* () {
yield `${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 `]`;
});
if (utils_1.identifierRE.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 `// @ts-ignore${utils_1.newLine}`;
yield propsStr
.replace(/\/\/(.*)$/gm, (_, body) => `/*${body.replaceAll('*/', '*\\/')} */`)
.replace(/\n/g, ' ');
yield `}))${utils_1.endOfLine}`;
yield `const `;
const boundary = yield* boundary_1.Boundary.start('template', node.loc.start.offset, node.loc.end.offset, codeFeatures_1.codeFeatures.doNotReportTs6133);
yield vnodeVar;
yield boundary.end();
yield ` = ${functionalVar}`;
const commentInfo = ctx.getCommentInfo();
if (commentInfo.generic) {
const { content, offset } = commentInfo.generic;
const boundary = yield* boundary_1.Boundary.start('template', offset, offset + content.length, codeFeatures_1.codeFeatures.verification);
yield `<`;
yield [content, 'template', offset, codeFeatures_1.codeFeatures.all];
yield `>`;
yield boundary.end();
}
const shouldInheritAttrs = hasVBindAttrs(options, ctx, node);
yield `(`;
const boundary2 = yield* boundary_1.Boundary.start('template', startTagOffset, startTagOffset + tag.length, 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 boundary2.end();
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));
const inferRootEl = ctx.dollarVars.has('$el') || options.vueCompilerOptions.inferComponentDollarEl;
const inferTemplateRefs = options.vueCompilerOptions.inferTemplateDollarRefs
|| options.vueCompilerOptions.inferComponentDollarRefs
|| options.setupRefs.size > 0;
if ((templateRef && inferTemplateRefs) || (isSingleRoot && inferRootEl)) {
const componentInstanceVar = ctx.getInternalVariable();
yield* (0, utils_1.generateTypedVar)('var', componentInstanceVar, options.scriptLang, function* () {
yield `Parameters<NonNullable<typeof ${getCtxVar()}['expose']>>[0]`;
});
if (templateRef && inferTemplateRefs) {
let typeExp = `typeof ${ctx.getHoistVariable(componentInstanceVar)} | null`;
if (ctx.inVFor) {
typeExp = `(${typeExp})[]`;
}
ctx.addTemplateRef(templateRef[0], typeExp, templateRef[1]);
}
if (isSingleRoot && inferRootEl) {
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* (0, styleScopedClasses_1.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* (0, utils_1.generateTypedVar)('var', ctxVar, options.scriptLang, function* () {
yield `${names_1.names.ExtractComponentContext}<typeof ${componentVar}, typeof ${vnodeVar}>`;
});
}
if (isPropsVarUsed) {
yield* (0, utils_1.generateTypedVar)('var', propsVar, options.scriptLang, function* () {
yield `${names_1.names.ExtractComponentProps}<typeof ${componentVar}, typeof ${vnodeVar}>`;
});
}
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 boundary = yield* boundary_1.Boundary.start('template', startTagOffset, startTagOffset + node.tag.length, codeFeatures_1.codeFeatures.verification);
yield `{${utils_1.newLine}`;
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, node.props, options.vueCompilerOptions.checkUnknownProps, failedPropExps);
yield `}`;
yield boundary.end();
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.dollarVars.has('$el') || options.vueCompilerOptions.inferComponentDollarEl)) {
ctx.singleRootElTypes.add(`${names_1.names.Elements}['${node.tag}']`);
}
if (hasVBindAttrs(options, ctx, node)) {
ctx.inheritedAttrVars.add(`${names_1.names.intrinsics}.${node.tag}`);
}
yield* (0, styleScopedClasses_1.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);
const failedPropExps = [];
// special case for <template v-for="..." :key="..." />
if (node.props.length) {
yield `${options.vueCompilerOptions.checkUnknownProps ? names_1.names.asFunctionalElement0 : names_1.names.asFunctionalElement1}(${names_1.names.intrinsics}.template)(`;
const boundary = yield* boundary_1.Boundary.start('template', startTagOffset, startTagOffset + node.tag.length, codeFeatures_1.codeFeatures.verification);
yield `{${utils_1.newLine}`;
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, node.props, options.vueCompilerOptions.checkUnknownProps, failedPropExps);
yield `}`;
yield boundary.end();
yield `)${utils_1.endOfLine}`;
yield* generateFailedExpressions(options, ctx, failedPropExps);
}
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child);
}
}
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, asBindingProperty?: boolean): Generator<Code>;
@@ -0,0 +1,162 @@
"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 boundary = yield* boundary_1.Boundary.start('template', prop.loc.start.offset, prop.loc.end.offset, codeFeatures_1.codeFeatures.verification);
if (options.isVapor && !(0, shared_1.isBuiltInDirective)(prop.name)) {
// vapor custom directives receive a value getter instead of a vdom binding object
yield* generateIdentifier(options, ctx, prop);
yield `(${names_1.names.nonNull}(null), `;
yield* generateValue(options, ctx, prop, false);
yield* generateArg(options, ctx, prop, false);
yield* generateModifiers(options, ctx, prop, 'modifiers', false);
yield `)`;
}
else {
yield `${names_1.names.asFunctionalDirective}(`;
yield* generateIdentifier(options, ctx, prop);
yield `, ${(0, utils_1.asType)(`import('${options.vueCompilerOptions.lib}').ObjectDirective`, options.scriptLang)})(${names_1.names.nonNull}(null), { ...${names_1.names.directiveBindingRestFields}, `;
yield* generateArg(options, ctx, prop);
yield* generateModifiers(options, ctx, prop);
yield* generateValue(options, ctx, prop);
// Vue invokes hooks with all four arguments regardless of the declared
// arity; the padded hook keeps the declared params checked, so the
// synthetic vnode args are `never` to stay assignable to whatever they declare.
yield `},${utils_1.newLine}${names_1.names.nonNull}(null), ${names_1.names.nonNull}(null))`;
}
yield boundary.end();
yield utils_1.endOfLine;
}
}
function* generateIdentifier(options, ctx, prop) {
const rawName = 'v-' + prop.name;
const startOffset = prop.loc.start.offset;
const boundary = yield* boundary_1.Boundary.start('template', startOffset, startOffset + rawName.length, 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.accessVariable('template', (0, shared_1.camelize)(rawName), prop.loc.start.offset);
}
yield boundary.end();
}
function* generateArg(options, ctx, prop, asBindingProperty = true) {
const { arg } = prop;
if (arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const startOffset = arg.loc.start.offset + arg.loc.source.indexOf(arg.content);
if (asBindingProperty) {
const boundary = yield* boundary_1.Boundary.start('template', startOffset, startOffset + arg.content.length, codeFeatures_1.codeFeatures.verification);
yield `arg`;
yield boundary.end();
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 `, `;
}
else if (!asBindingProperty) {
yield `undefined, `;
}
}
function* generateModifiers(options, ctx, prop, propertyName = 'modifiers', asBindingProperty = true) {
const { modifiers } = prop;
if (modifiers.length) {
if (asBindingProperty) {
const boundary = yield* boundary_1.Boundary.start('template', modifiers[0].loc.start.offset - 1, modifiers.at(-1).loc.end.offset, codeFeatures_1.codeFeatures.verification);
yield propertyName;
yield boundary.end();
yield `: `;
}
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 `}, `;
}
else if (!asBindingProperty) {
yield `undefined, `;
}
}
function* generateValue(options, ctx, prop, asBindingProperty = true) {
const { exp } = prop;
if (exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const boundary = yield* boundary_1.Boundary.start('template', exp.loc.start.offset, exp.loc.end.offset, codeFeatures_1.codeFeatures.verification);
if (asBindingProperty) {
yield `value`;
yield boundary.end();
yield `: `;
yield* (0, elementProps_1.generatePropExp)(options, ctx, prop, exp);
}
else {
yield `() => `;
yield* (0, elementProps_1.generatePropExp)(options, ctx, prop, exp);
yield boundary.end();
}
yield `, `;
}
else if (!asBindingProperty) {
yield `undefined, `;
}
}
//# 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;
+273
View File
@@ -0,0 +1,273 @@
"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 utils_1 = require("../../parsers/utils");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_2 = 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* (0, utils_2.generateTypedVar)('let', emitsVar, options.scriptLang, function* () {
yield `${names_1.names.ResolveEmits}<typeof ${componentOriginalVar}, typeof ${getCtxVar()}.emit>`;
});
for (const { propPrefix, emitPrefix, propName, emitName, items } of Object.values(definitions)) {
const eventVar = ctx.getInternalVariable();
const eventType = `${options.vueCompilerOptions.checkUnknownEvents ? '' : 'Record<string, unknown> & '}Partial<${names_1.names.ResolveEvent}<typeof ${getPropsVar()}, typeof ${emitsVar}, '${propName}', '${emitName}', '${(0, shared_1.camelize)(emitName)}'>>`;
if ((0, utils_2.isTsLang)(options.scriptLang)) {
yield `const ${eventVar}: ${eventType} = {${utils_2.newLine}`;
}
else {
yield `/** @type {${eventType}} */${utils_2.newLine}const ${eventVar} = {${utils_2.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_2.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_2.newLine}`;
}
yield `}${utils_2.endOfLine}`;
yield `void ${eventVar}${utils_2.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);
}
const boundary = yield* boundary_1.Boundary.start('template', start, start + name.length, features);
if (utils_2.identifierRE.test((0, shared_1.camelize)(name))) {
yield directive;
yield* (0, camelized_1.generateCamelized)(name, 'template', start, boundary.features);
}
else {
yield `'`;
yield directive;
yield* (0, camelized_1.generateCamelized)(name, 'template', start, boundary.features);
yield `'`;
yield boundary.end();
}
}
function* generateEventExpression(options, ctx, prop) {
if (prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const ast = (0, utils_2.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) {
const scope = ctx.scope();
scope.declare('$event');
const accessMark = ctx.accessLog.length;
const codes = [];
for (const code of interpolation) {
codes.push(code);
}
yield `// @ts-ignore${utils_2.newLine}`;
yield `(...[$event]) => {${utils_2.newLine}`;
// consume $event to avoid TS6133 when the expression doesn't use it
yield `void $event${utils_2.endOfLine}`;
yield* generateReasserts(options, ctx, accessMark);
yield* ctx.generateConditionGuards();
if (isSingleExpression(options.typescript, ast)) {
yield `return (`;
yield* codes;
yield `)`;
}
else {
yield* codes;
}
yield utils_2.endOfLine;
yield* scope.end();
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) {
const accessMark = ctx.accessLog.length;
const codes = [...(0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.verification, prop.exp.content, prop.exp.loc.start.offset, undefined, undefined, true)];
yield `// @ts-ignore${utils_2.newLine}`;
yield `(...[$event]) => {${utils_2.newLine}`;
yield* generateReasserts(options, ctx, accessMark);
yield* ctx.generateConditionGuards();
yield* codes;
yield ` = $event${utils_2.endOfLine}`;
yield `}`;
}
else {
yield `() => {}`;
}
}
// Assertion narrowing does not flow into nested closures for imports and
// `let`/`var` bindings (TS limitation), so re-assert those bindings at closure tops.
function* generateReasserts(options, ctx, accessMark) {
const reasserts = new Set();
const collect = (name) => {
if (options.reassertBindings.has(name) && !ctx.scopes.some(scope => scope.has(name))) {
reasserts.add(name);
}
};
for (const name of ctx.accessLog.slice(accessMark)) {
collect(name);
}
for (const condition of ctx.conditions) {
for (const name of condition.accesses) {
collect(name);
}
}
for (const name of reasserts) {
yield `${names_1.names.withDotValue}(${name}, ${(0, utils_2.getRefBrandArgument)(options.vueCompilerOptions, options.scriptLang)})${utils_2.endOfLine}`;
}
}
function isCompoundExpression(ts, ast) {
if (ast.statements.length === 0) {
return false;
}
if (ast.statements.length === 1 && ast.text[ast.endOfFileToken.pos - 1] !== ';') {
const statement = ast.statements[0];
if (ts.isExpressionStatement(statement)) {
const node = (0, utils_1.getUnwrappedExpression)(ts, statement.expression);
if (ts.isArrowFunction(node)
|| ts.isIdentifier(node)
|| ts.isElementAccessExpression(node)
|| ts.isPropertyAccessExpression(node)) {
return false;
}
}
else if (ts.isFunctionDeclaration(statement)) {
return false;
}
}
return true;
}
function isSingleExpression(ts, ast) {
if (ast.statements.length === 1 && ast.text[ast.endOfFileToken.pos - 1] !== ';') {
const statement = ast.statements[0];
if (ts.isExpressionStatement(statement)) {
return true;
}
}
return false;
}
//# sourceMappingURL=elementEvents.js.map
+11
View File
@@ -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>;
+280
View File
@@ -0,0 +1,280 @@
"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 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)}': ${(0, utils_1.asType)('any', options.scriptLang)} },`;
}
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.isDataAttribute(propName)) {
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 boundary = yield* boundary_1.Boundary.start('template', prop.loc.start.offset, prop.loc.end.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 boundary2 = yield* boundary_1.Boundary.start('template', prop.loc.start.offset, prop.loc.start.offset + 'v-model'.length, codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
yield propName;
yield boundary2.end();
}
yield `: `;
const argLoc = prop.arg?.loc ?? prop.loc;
const boundary3 = yield* boundary_1.Boundary.start('template', argLoc.start.offset, argLoc.end.offset, codeFeatures_1.codeFeatures.verification);
yield* generatePropExp(options, ctx, prop, prop.exp);
yield boundary3.end();
yield boundary.end();
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.isDataAttribute(prop.name)) {
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 boundary = yield* boundary_1.Boundary.start('template', prop.loc.start.offset, prop.loc.end.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 boundary.end();
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 boundary = yield* boundary_1.Boundary.start('template', prop.exp.loc.start.offset, prop.exp.loc.end.offset, codeFeatures_1.codeFeatures.verification);
yield `...`;
yield* generatePropExp(options, ctx, prop, prop.exp);
yield boundary.end();
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.identifierRE.test(propVariableName)) {
const codes = (0, camelized_1.generateCamelized)(exp.loc.source, 'template', exp.loc.start.offset, {
...codeFeatures_1.codeFeatures.withoutHighlightAndCompletion,
__shorthandExpression: 'html',
});
yield* (0, interpolation_1.generateIdentifier)(options, ctx, codes, propVariableName, 'template', exp.loc.start.offset, exp.loc.end.offset);
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.isHtmlAttribute(propName));
}
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
+105
View File
@@ -0,0 +1,105 @@
import type * as ts from 'typescript';
import type { Code, IRTemplate, VueCompilerOptions } from '../../types';
export interface TemplateCodegenOptions {
typescript: typeof ts;
vueCompilerOptions: VueCompilerOptions;
template: IRTemplate;
isVapor: boolean;
scriptLang: string;
importedComponents: Set<string>;
setupRefs: Set<string>;
setupConsts: Set<string>;
setupBindings: Set<string>;
dotValueBindings: Set<string>;
reassertBindings: Set<string>;
hasDefineSlots?: boolean;
propsAssignName?: string;
slotsAssignName?: string;
inheritAttrs: boolean;
componentName: string;
}
export { generate as generateTemplate };
declare function generate(options: TemplateCodegenOptions): {
getCommentInfo: () => {
ignoreError?: boolean;
expectError?: {
token: number;
node: import("@vue/compiler-dom").CommentNode;
};
generic?: {
content: string;
offset: number;
};
};
enter: (node: import("@vue/compiler-dom").RootNode | import("@vue/compiler-dom").TemplateChildNode | import("@vue/compiler-dom").SimpleExpressionNode) => boolean;
exit: () => Generator<Code>;
resolveCodeFeatures: (features: import("../../types").VueCodeInformation) => import("../../types").VueCodeInformation;
getInternalVariable: () => string;
scopes: {
has(value: string): boolean;
readonly size: number;
declare(...variables: string[]): void;
end(): Generator<Code, any, any>;
add(value: string): /*elided*/ any;
clear(): void;
delete(value: string): boolean;
forEach(callbackfn: (value: string, value2: string, set: Set<string>) => void, thisArg?: any): void;
[Symbol.iterator](): SetIterator<string>;
entries(): SetIterator<[string, string]>;
keys(): SetIterator<string>;
values(): SetIterator<string>;
readonly [Symbol.toStringTag]: string;
}[];
scope: () => {
has(value: string): boolean;
readonly size: number;
declare(...variables: string[]): void;
end(): Generator<Code, any, any>;
add(value: string): any;
clear(): void;
delete(value: string): boolean;
forEach(callbackfn: (value: string, value2: string, set: Set<string>) => void, thisArg?: any): void;
[Symbol.iterator](): SetIterator<string>;
entries(): SetIterator<[string, string]>;
keys(): SetIterator<string>;
values(): SetIterator<string>;
readonly [Symbol.toStringTag]: string;
};
contextAccesses: Map<string, Map<string, Set<number>>>;
dotValueAccesses: Set<string>;
accessLog: string[];
accessVariable: (source: string, name: string, offset?: number, dotValue?: boolean) => void;
generateAutoImport: () => Generator<Code>;
conditions: {
text: string;
accesses: string[];
}[];
generateConditionGuards: () => Generator<string, void, unknown>;
hoistVars: Map<string, string>;
getHoistVariable: (originalVar: string) => string;
generateHoistVariables: () => Generator<string, void, unknown>;
templateRefs: Map<string, {
typeExp: string;
offset: number;
}[]>;
addTemplateRef: (name: string, typeExp: string, offset: number) => void;
components: (() => string)[];
dollarVars: Set<string>;
inlayHints: import("../inlayHints").InlayHintInfo[];
generatedTypes: Set<string>;
inheritedAttrVars: Set<string>;
singleRootElTypes: Set<string>;
singleRootNodes: Set<import("@vue/compiler-dom").ElementNode | null>;
slots: {
name: string;
offset?: number;
tagRange: [number, number];
propsVar: string;
}[];
dynamicSlots: {
expVar: string;
propsVar: string;
}[];
inVFor: boolean;
codes: Code[];
};
+163
View File
@@ -0,0 +1,163 @@
"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 styleScopedClasses_1 = require("./styleScopedClasses");
const templateChild_1 = require("./templateChild");
function generate(options) {
// The references registry accumulates across codegen passes; start clean.
styleScopedClasses_1.references.delete(options.template);
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 scope = ctx.scope();
const { slotsAssignName, propsAssignName, vueCompilerOptions, template, } = options;
if (slotsAssignName) {
scope.declare(slotsAssignName);
}
if (propsAssignName) {
scope.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(options, ctx);
if (ctx.dollarVars.size) {
yield* (0, utils_1.generateTypedVar)('var', names_1.names.dollars, options.scriptLang, function* () {
yield `{${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 }`;
});
}
yield* scope.end();
}
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* (0, utils_1.generateTypeAlias)(names_1.names.Slots, options.scriptLang, function* () {
yield `{}`;
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 boundary = yield* boundary_1.Boundary.start('template', ...slot.tagRange, codeFeatures_1.codeFeatures.navigation);
yield `default`;
yield boundary.end();
}
yield `?: (props: typeof ${slot.propsVar}) => any }`;
}
});
}
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* (0, utils_1.generateTypeAlias)(names_1.names.InheritedAttrs, options.scriptLang, function* () {
yield options.vueCompilerOptions.checkRequiredFallthroughAttributes
? type
: `Partial<${type}>`;
});
}
function* generateTemplateRefsType(options, ctx) {
if (!ctx.templateRefs.size
|| !(options.vueCompilerOptions.inferTemplateDollarRefs
|| options.vueCompilerOptions.inferComponentDollarRefs
|| options.setupRefs.size)) {
return;
}
ctx.generatedTypes.add(names_1.names.TemplateRefs);
yield* (0, utils_1.generateTypeAlias)(names_1.names.TemplateRefs, options.scriptLang, function* () {
yield `{}`;
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 `)`;
}
}
});
}
function* generateRootElType(options, ctx) {
if (!ctx.singleRootElTypes.size || ctx.singleRootNodes.has(null)) {
return;
}
ctx.generatedTypes.add(names_1.names.RootEl);
yield* (0, utils_1.generateTypeAlias)(names_1.names.RootEl, options.scriptLang, function* () {
for (const type of ctx.singleRootElTypes) {
yield `${utils_1.newLine}| ${type}`;
}
});
}
//# sourceMappingURL=index.js.map
@@ -0,0 +1,15 @@
import type { Code, IRBlock, VueCodeInformation, VueCompilerOptions } from '../../types';
import type { TemplateCodegenContext } from './context';
export declare function generateInterpolation(options: IdentifierOptions & {
typescript: typeof import('typescript');
}, ctx: TemplateCodegenContext, block: IRBlock, features: VueCodeInformation, code: string, start: number, prefix?: string, suffix?: string, inNarrowing?: boolean): Generator<Code>;
interface IdentifierOptions {
setupRefs: Set<string>;
setupConsts: Set<string>;
setupBindings: Set<string>;
dotValueBindings: Set<string>;
vueCompilerOptions: VueCompilerOptions;
scriptLang: string;
}
export declare function generateIdentifier(options: IdentifierOptions, ctx: TemplateCodegenContext, codes: Iterable<Code>, name: string, source: string, start: number, end: number, isNarrowing?: boolean, inTypeQuery?: boolean, isNewOperand?: boolean): Generator<Code>;
export {};
+138
View File
@@ -0,0 +1,138 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateInterpolation = generateInterpolation;
exports.generateIdentifier = generateIdentifier;
const shared_1 = require("../../utils/shared");
const codeFeatures_1 = require("../codeFeatures");
const names_1 = require("../names");
const utils_1 = require("../utils");
const boundary_1 = require("../utils/boundary");
const bindingReferences_1 = require("./bindingReferences");
function* generateInterpolation(options, ctx, block, features, code, start, prefix = '', suffix = '', inNarrowing = false) {
if (prefix) {
yield prefix;
}
let prevEnd = 0;
for (const [name, offset, isShorthand, isNarrowing, inTypeQuery, isNewOperand] of forEachIdentifiers(options.typescript, ctx, block, code, prefix, suffix, inNarrowing)) {
if (isShorthand) {
yield* generateNonIdentifierCode(code.slice(prevEnd, offset + name.length), block.name, start + prevEnd, features, prevEnd > 0);
yield `: `;
}
else if (prevEnd < offset) {
yield* generateNonIdentifierCode(code.slice(prevEnd, offset), block.name, start + prevEnd, features, prevEnd > 0);
}
const codes = [[
name,
block.name,
start + offset,
isShorthand
? { ...features, __shorthandExpression: 'js' }
: features,
]];
yield* generateIdentifier(options, ctx, codes, name, block.name, start + offset, start + offset + name.length, isNarrowing, inTypeQuery, isNewOperand);
prevEnd = offset + name.length;
}
if (prevEnd < code.length) {
yield* generateNonIdentifierCode(code.slice(prevEnd), block.name, start + prevEnd, features, prevEnd > 0);
}
if (suffix) {
yield suffix;
}
}
/**
* Yield a code chunk, cutting the boundary character off as verification-only.
*
* Adjacent mappings share the boundary offset (closed interval), so both the
* neighbouring token's end and this chunk's start claim the same source offset.
* Downgrading the boundary character to verification-only keeps content-sensitive
* features (rename / navigation) from firing on the neighbouring chunk.
*/
function* generateNonIdentifierCode(code, source, offset, data, shouldCut = true) {
if (!code.length) {
return;
}
if (!shouldCut) {
yield [code, source, offset, data];
return;
}
yield [code.slice(0, 1), source, offset, { verification: data.verification }];
if (code.length > 1) {
yield [code.slice(1), source, offset + 1, data];
}
}
// Access strategy, in precedence order:
// - setup consts → direct reference
// - local-scope / global names → direct reference (the interpolation path
// filters these earlier; the v-bind shorthand path relies on this branch)
// - template refs → direct `.value`
// - dotValue bindings (narrowed at least once anywhere) → `.value` at
// every position; narrowing then works on the `.value` reference chain
// - other bindings → `__VLS_unwrap` (plain reads keep the original type)
// - otherwise → `__VLS_ctx.<name>`
function* generateIdentifier(options, ctx, codes, name, source, start, end, isNarrowing = false, inTypeQuery = false, isNewOperand = false) {
if (options.setupConsts.has(name) || (0, bindingReferences_1.shouldIdentifierSkipped)(ctx, name)) {
yield* codes;
}
else if (options.setupRefs.has(name)) {
yield* codes;
yield `.`;
const boundary = yield* boundary_1.Boundary.start(source, start, end, codeFeatures_1.codeFeatures.verification);
yield `value`;
yield boundary.end();
}
else if (options.setupBindings.has(name)) {
// First pass records narrowing accesses here; the second pass emits from dotValueBindings.
ctx.accessVariable(source, name, start, inTypeQuery || isNarrowing);
if (inTypeQuery || options.dotValueBindings.has(name)) {
yield* codes;
yield `.`;
const boundary = yield* boundary_1.Boundary.start(source, start, end, codeFeatures_1.codeFeatures.verification);
yield `value`;
yield boundary.end();
}
else {
// `new __VLS_unwrap(Foo)()` parses as `new (__VLS_unwrap(Foo)())`,
// whose target lacks a construct signature; keep the operand parenthesized.
if (isNewOperand) {
yield `(`;
}
yield `${names_1.names.unwrap}(`;
yield* codes;
yield `, ${(0, utils_1.getRefBrandArgument)(options.vueCompilerOptions, options.scriptLang)})`;
if (isNewOperand) {
yield `)`;
}
}
}
else {
// #1205, #1264
const boundary = yield* boundary_1.Boundary.start(source, start, end, codeFeatures_1.codeFeatures.verification);
if (ctx.dollarVars.has(name)) {
yield names_1.names.dollars;
}
else {
ctx.accessVariable(source, name, start);
yield names_1.names.ctx;
}
yield `.`;
yield* codes;
yield boundary.end();
}
}
function* forEachIdentifiers(ts, ctx, block, code, prefix, suffix, inNarrowing) {
if (utils_1.identifierRE.test(code) && !(0, bindingReferences_1.shouldIdentifierSkipped)(ctx, code)) {
yield [code, 0, false, inNarrowing, false, false];
return;
}
const scope = ctx.scope();
const ast = (0, utils_1.getTypeScriptAST)(ts, block, prefix + code + suffix);
for (const { id, isShorthand, isNarrowing, skipped, inTypeQuery, isNewOperand } of (0, bindingReferences_1.forEachDeclarations)(ts, ast, ast, ctx, scope, inNarrowing)) {
if (skipped) {
continue;
}
const text = (0, shared_1.getNodeText)(ts, id, ast);
yield [text, (0, shared_1.getStartEnd)(ts, id, ast).start - prefix.length, isShorthand, isNarrowing, inTypeQuery, isNewOperand];
}
scope.end();
}
//# 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>;
+41
View File
@@ -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.identifierRE.test((0, shared_1.camelize)(code))) {
yield* (0, camelized_1.generateCamelized)(code, 'template', offset, features);
}
else {
const boundary = yield* boundary_1.Boundary.start('template', offset, offset + code.length, features);
yield `'`;
yield* (0, camelized_1.generateCamelized)(code, 'template', offset, boundary.features);
yield `'`;
yield boundary.end();
}
}
else {
if (utils_1.identifierRE.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>;
+21
View File
@@ -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.identifierRE.test(code)) {
yield `.`;
yield [code, 'template', offset, features];
}
else {
yield `[`;
yield* (0, stringLiteralKey_1.generateStringLiteralKey)(code, offset, features);
yield `]`;
}
}
//# sourceMappingURL=propertyAccess.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 generateSlotOutlet(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.SlotOutletNode): Generator<Code>;
+144
View File
@@ -0,0 +1,144 @@
"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 boundary = yield* boundary_1.Boundary.start('template', nameProp.loc.start.offset, nameProp.loc.end.offset, codeFeatures_1.codeFeatures.verification);
yield options.slotsAssignName ?? names_1.names.slots;
yield* codes;
yield boundary.end();
}
else {
const boundary = yield* boundary_1.Boundary.start('template', startTagOffset, startTagEndOffset, codeFeatures_1.codeFeatures.verification);
yield `${options.slotsAssignName ?? names_1.names.slots}[`;
const boundary2 = yield* boundary_1.Boundary.start('template', startTagOffset, startTagEndOffset, codeFeatures_1.codeFeatures.verification);
yield `'default'`;
yield boundary2.end();
yield `]`;
yield boundary.end();
}
yield `)(`;
const boundary = yield* boundary_1.Boundary.start('template', startTagOffset, startTagEndOffset, 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 boundary.end();
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],
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],
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,6 @@
import * as CompilerDOM from '@vue/compiler-dom';
import type { Code, IRBlock } from '../../types';
import type { TemplateCodegenOptions } from './index';
export declare const references: WeakMap<IRBlock, [version: string, [className: string, offset: number][]]>;
export declare function generateStyleScopedClassReferences({ template, typescript: ts }: TemplateCodegenOptions, node: CompilerDOM.ElementNode): Generator<Code>;
export declare function generateStyleScopedClassReference(block: IRBlock, className: string, offset: number, fullStart?: number): Generator<Code>;
@@ -0,0 +1,159 @@
"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.references = void 0;
exports.generateStyleScopedClassReferences = generateStyleScopedClassReferences;
exports.generateStyleScopedClassReference = generateStyleScopedClassReference;
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const shared_1 = require("../../utils/shared");
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 classNameEscapeRE = /([\\'])/;
// For language-service/lib/plugins/vue-scoped-class-links.ts usage
exports.references = new WeakMap();
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_1.normalizeAttributeValue)(prop.value);
for (const [className, offset] of forEachClassName(text)) {
yield* 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* 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_1.getNodeText)(ts, name, ast);
yield* 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_1.getNodeText)(ts, property.name, ast);
yield* 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* 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 boundary = yield* boundary_1.Boundary.start(block.name, fullStart, offset + className.length, codeFeatures_1.codeFeatures.navigationAndCompletion);
yield `'`;
yield* (0, escaped_1.generateEscaped)(className, block.name, offset, boundary.features, classNameEscapeRE);
yield `'`;
yield boundary.end();
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];
+148
View File
@@ -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;
};
+152
View File
@@ -0,0 +1,152 @@
"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 shared_1 = require("../../utils/shared");
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 scope = ctx.scope();
let bindingNames = [];
const defaultInitializerRanges = [];
if (leftExpressionRange && leftExpressionText) {
const wrap = `const [`;
const collectAst = (0, utils_1.getTypeScriptAST)(options.typescript, options.template, `${wrap}${leftExpressionText}]`);
bindingNames = (0, collectBindings_1.collectBindingNames)(options.typescript, collectAst, collectAst);
const declaration = collectAst.statements[0].declarationList.declarations[0];
const initializers = [];
collectDefaultInitializers(options.typescript, declaration.name, initializers);
for (const initializer of initializers) {
const { start, end } = (0, shared_1.getStartEnd)(options.typescript, initializer, collectAst);
defaultInitializerRanges.push([start - wrap.length, end - wrap.length]);
}
defaultInitializerRanges.sort((a, b) => a[0] - b[0]);
}
// Evaluate the source before the loop bindings enter scope (`v-for="x in x"` reads the outer `x`);
// destructuring defaults (`{ a, b = a }`) are interpolated after the declaration to see the sibling aliases.
let sourceAlias;
if (source.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
sourceAlias = ctx.getInternalVariable();
// tryAsConstant keeps inline literal sources from widening to `number[]` (#6067).
yield `const ${sourceAlias} = ${names_1.names.tryAsConstant}(`;
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, source.content, source.loc.start.offset, `(`, `)`);
yield `)`;
yield utils_1.endOfLine;
}
scope.declare(...bindingNames);
yield `for (const [`;
if (leftExpressionRange && leftExpressionText) {
let lastOffset = 0;
for (const [start, end] of defaultInitializerRanges) {
if (start > lastOffset) {
yield [
leftExpressionText.slice(lastOffset, start),
'template',
leftExpressionRange.start + lastOffset,
codeFeatures_1.codeFeatures.all,
];
}
yield* (0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, leftExpressionText.slice(start, end), leftExpressionRange.start + start);
lastOffset = end;
}
if (lastOffset < leftExpressionText.length) {
yield [
leftExpressionText.slice(lastOffset),
'template',
leftExpressionRange.start + lastOffset,
codeFeatures_1.codeFeatures.all,
];
}
}
yield `] of `;
if (sourceAlias !== undefined) {
yield `${names_1.names.vFor}(${names_1.names.nonNull}(`;
yield sourceAlias;
yield `))`; // #3102
}
else {
yield (0, utils_1.asType)('any', options.scriptLang);
}
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* scope.end();
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,
};
}
function collectDefaultInitializers(ts, pattern, out) {
if (ts.isIdentifier(pattern)) {
return;
}
for (const element of pattern.elements) {
if (!ts.isBindingElement(element)) {
continue;
}
if (!ts.isIdentifier(element.name)) {
collectDefaultInitializers(ts, element.name, out);
}
if (element.initializer) {
out.push(element.initializer);
}
}
}
//# 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>;
+77
View File
@@ -0,0 +1,77 @@
"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.conditions.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 accessMark = ctx.accessLog.length;
const codes = [...(0, interpolation_1.generateInterpolation)(options, ctx, options.template, codeFeatures_1.codeFeatures.all, branch.condition.content, branch.condition.loc.start.offset, `(`, `)`, true)];
yield* codes;
ctx.conditions.push({ text: (0, muggle_string_1.toString)(codes), accesses: ctx.accessLog.slice(accessMark) });
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) {
const condition = ctx.conditions[ctx.conditions.length - 1];
condition.text = `!${condition.text}`;
}
}
ctx.conditions.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 boundary = yield* boundary_1.Boundary.start('template', slotDir.loc.start.offset, slotDir.loc.start.offset + (slotDir.rawName?.length ?? 0), codeFeatures_1.codeFeatures.withoutHighlightAndCompletion);
yield `default`;
yield boundary.end();
}
}
else {
yield `const { `;
// #932: reference for implicit default slot
const boundary = yield* boundary_1.Boundary.start('template', node.loc.start.offset, node.loc.end.offset, codeFeatures_1.codeFeatures.navigation);
yield `default`;
yield boundary.end();
}
yield `: ${slotVar} } = ${names_1.names.nonNull}(${ctxVar}.slots)${utils_1.endOfLine}`;
const scope = ctx.scope();
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);
scope.declare(...(0, collectBindings_1.collectBindingNames)(options.typescript, slotAst, slotAst));
}
for (const child of node.children) {
yield* (0, templateChild_1.generateTemplateChild)(options, ctx, child);
}
yield* scope.end();
if (slotDir) {
let isStatic = true;
if (slotDir.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
isStatic = slotDir.arg.isStatic;
}
yield `}${utils_1.newLine}`;
if (isStatic && !slotDir.arg) {
if (slotDir.loc.source.startsWith('#') || slotDir.loc.source.startsWith('v-slot:')) {
yield `/** @type {NonNullable<typeof ${ctxVar}['slots']>['`;
yield [
'',
'template',
slotDir.loc.start.offset + (slotDir.loc.source.startsWith('#')
? '#'.length
: 'v-slot:'.length),
codeFeatures_1.codeFeatures.completion,
];
yield `']} */${utils_1.endOfLine}`;
}
}
}
}
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}(${names_1.names.nonNull}(${slotVar})`;
if (types.some(t => t)) {
yield `, `;
const boundary = yield* boundary_1.Boundary.start('template', exp.loc.start.offset, exp.loc.end.offset, codeFeatures_1.codeFeatures.verification);
yield `(`;
yield* types.flatMap(type => type ? [`_`, type, `, `] : `_, `);
yield (0, utils_1.isTsLang)(options.scriptLang) ? `) => [] as any` : `) => /** @type {any} */ ([])`;
yield boundary.end();
}
yield `)${utils_1.endOfLine}`;
}
//# sourceMappingURL=vSlot.js.map
+9
View File
@@ -0,0 +1,9 @@
import type { Code, VueCodeInformation } from '../../types';
export declare class Boundary {
private source;
private endOffset;
features: VueCodeInformation;
private constructor();
static start(source: string, start: number, end: number, features: VueCodeInformation): Generator<Code, Boundary>;
end(): Code;
}
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Boundary = void 0;
class Boundary {
constructor(source, endOffset, features) {
this.source = source;
this.endOffset = endOffset;
this.features = features;
}
static *start(source, start, end, features) {
features = { ...features, __combineToken: Symbol() };
yield [``, source, start, features];
return new Boundary(source, end, features);
}
end() {
return [``, this.source, this.endOffset, this.features];
}
}
exports.Boundary = Boundary;
//# 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>;
+23
View File
@@ -0,0 +1,23 @@
"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('-');
if (!features.__combineToken) {
features = { ...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];
}
else {
yield [(0, shared_1.capitalize)(part), source, offset, features];
}
}
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>;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateEscaped = generateEscaped;
function* generateEscaped(text, source, offset, features, escapeTarget) {
const parts = text.split(escapeTarget);
if (!features.__combineToken) {
features = { ...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, features];
offset += part.length;
isEscapeTarget = !isEscapeTarget;
}
}
//# sourceMappingURL=escaped.js.map
+13
View File
@@ -0,0 +1,13 @@
import type * as ts from 'typescript';
import type { Code, IRBlock, IRScript, IRScriptSetup, VueCodeInformation, VueCompilerOptions } from '../../types';
export declare const newLine = "\n";
export declare const endOfLine = ";\n";
export declare const identifierRE: RegExp;
export declare function isTsLang(lang: string): boolean;
export declare function asType(type: string, lang: string): string;
export declare function generateTypedVar(kind: 'let' | 'var', name: string, lang: string, type: () => Generator<Code>): Generator<Code>;
export declare function generateTypeAlias(name: string, lang: string, type: () => Generator<Code>): Generator<Code>;
export declare function getRefBrandArgument(vueCompilerOptions: VueCompilerOptions, lang: string): string;
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>;
+109
View File
@@ -0,0 +1,109 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.identifierRE = exports.endOfLine = exports.newLine = void 0;
exports.isTsLang = isTsLang;
exports.asType = asType;
exports.generateTypedVar = generateTypedVar;
exports.generateTypeAlias = generateTypeAlias;
exports.getRefBrandArgument = getRefBrandArgument;
exports.getTypeScriptAST = getTypeScriptAST;
exports.generateSfcBlockSection = generateSfcBlockSection;
exports.forEachNode = forEachNode;
const codeFeatures_1 = require("../codeFeatures");
exports.newLine = `\n`;
exports.endOfLine = `;${exports.newLine}`;
exports.identifierRE = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
function isTsLang(lang) {
return lang === 'ts' || lang === 'tsx';
}
// `{} as T` in TS; `/** @type {T} */ ({})` in JS. The JSDoc cast keeps the
// same assertion semantics under checkJs, and requires no type-only syntax.
function asType(type, lang) {
return isTsLang(lang) ? `{} as ${type}` : `/** @type {${type}} */ ({})`;
}
// `let name!: T;` in TS; `var name = /** @type {T} */ ({});` in JS.
function* generateTypedVar(kind, name, lang, type) {
if (isTsLang(lang)) {
yield `${kind} ${name}!: `;
yield* type();
yield exports.endOfLine;
}
else {
yield `var ${name} = /** @type {`;
yield* type();
yield `} */ ({})${exports.endOfLine}`;
}
}
// `type name = T;` in TS; `/** @typedef {T} name */;` in JS.
function* generateTypeAlias(name, lang, type) {
if (isTsLang(lang)) {
yield `type ${name} = `;
yield* type();
yield exports.endOfLine;
}
else {
yield `/** @typedef {`;
yield* type();
yield `} ${name} */${exports.endOfLine}`;
}
}
// The phantom argument that carries the component library's `Ref` brand into
// `__VLS_unwrap` / `__VLS_withDotValue`; the helper declarations cannot
// resolve the library import themselves.
function getRefBrandArgument(vueCompilerOptions, lang) {
return asType(`import('${vueCompilerOptions.lib}').Ref<unknown>`, lang);
}
const cacheMaps = new WeakMap();
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, features: VueCodeInformation): Generator<Code>;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateStringLiteralKey = generateStringLiteralKey;
const boundary_1 = require("./boundary");
function* generateStringLiteralKey(code, offset, features) {
const boundary = yield* boundary_1.Boundary.start('template', offset, offset + code.length, features);
yield `'`;
yield [code, 'template', offset, boundary.features];
yield `'`;
yield boundary.end();
}
//# 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, features: 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, features) {
if (needToUnicode(code)) {
const boundary = yield* boundary_1.Boundary.start('template', offset, offset + code.length, features);
yield toUnicode(code);
yield boundary.end();
}
else {
yield [code, 'template', offset, features];
}
}
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 {};
+273
View File
@@ -0,0 +1,273 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
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 picomatch_1 = __importDefault(require("picomatch"));
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':
// A config that declares `plugins` replaces the inherited list; `[]` clears it
if (options.plugins) {
this.plugins = resolvePlugins(options.plugins, rootDir);
}
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])),
};
// Compiling a glob costs far more than testing it, and codegen tests every prop against these
resolvedOptions.isDataAttribute = (0, picomatch_1.default)(resolvedOptions.dataAttributes);
resolvedOptions.isHtmlAttribute = (0, picomatch_1.default)(resolvedOptions.htmlAttributes);
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 resolvePlugins(list, rootDir) {
const plugins = [];
for (let raw of list) {
raw = typeof raw === 'string' ? { name: raw } : raw;
try {
const resolve = require?.resolve;
const resolvedPath = resolve?.(raw.name, { paths: [rootDir] });
if (resolvedPath) {
const moduleExports = require(resolvedPath);
for (const plugin of Array.isArray(moduleExports) ? moduleExports : [moduleExports]) {
plugin.__moduleConfig = raw;
plugins.push(plugin);
}
}
else {
console.warn('[Vue] Load plugin failed:', raw.name);
}
}
catch (error) {
console.warn('[Vue] Resolve plugin path failed:', raw.name, error);
}
}
return plugins;
}
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') {
const dataAttributes = [];
const htmlAttributes = ['aria-*'];
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,
vapor: false,
fallthroughAttributes: false,
checkRequiredFallthroughAttributes: false,
resolveStyleImports: false,
resolveStyleClassNames: 'scoped',
fallthroughComponentNames: [
'Transition',
'KeepAlive',
'Teleport',
'Suspense',
],
dataAttributes,
htmlAttributes,
isDataAttribute: (0, picomatch_1.default)(dataAttributes),
isHtmlAttribute: (0, picomatch_1.default)(htmlAttributes),
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[];
+143
View File
@@ -0,0 +1,143 @@
"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 vue_tsx_1 = require("./plugins/vue-tsx");
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 (vue_tsx_1.serviceScriptRE.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
+32
View File
@@ -0,0 +1,32 @@
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): {
bindings: Map<string, import("./utils").BindingFlag>;
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;
};
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;
+83
View File
@@ -0,0 +1,83 @@
"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;
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 {
bindings: (0, utils_1.parseBindings)(ts, sourceFile, vueCompilerOptions.extensions),
exportDefault,
};
}
function parseOptionsFromExtression(ts, exp, sourceFile) {
let obj;
// #1882
exp = (0, utils_1.getUnwrappedExpression)(ts, exp);
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);
}
}
//# 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;
defaultPropsArg?: 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): {
bindings: Map<string, import("./utils").BindingFlag>;
leadingCommentEndOffset: number;
importSectionEndOffset: number;
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[];
};
+302
View File
@@ -0,0 +1,302 @@
"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 tsCheckRE = /^\/\/\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 => tsCheckRE.test(text.slice(range.pos, range.end)))?.end ?? 0;
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]));
return {
bindings: (0, utils_1.parseBindings)(ts, sourceFile, vueCompilerOptions.extensions),
leadingCommentEndOffset,
importSectionEndOffset,
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 defaultPropsArg;
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) {
let initializer;
if (ts.isPropertyAssignment(property)) {
initializer = property.initializer;
}
else if (ts.isMethodDeclaration(property) && _getNodeText(property.name) === 'default') {
initializer = property;
}
else {
continue;
}
if (!ts.isIdentifier(property.name)) {
continue;
}
switch (_getNodeText(property.name)) {
case 'type': {
runtimeType = _getStartEnd(initializer);
break;
}
case 'default': {
if (ts.isPropertyAssignment(property)) {
defaultValue = _getStartEnd(initializer);
}
if (ts.isFunctionLike(initializer) && initializer.parameters.length) {
const firstArg = initializer.parameters[0];
if (!firstArg.dotDotDotToken && !firstArg.type) {
defaultPropsArg = _getStartEnd(firstArg);
}
}
break;
}
case 'required': {
if (initializer.kind === ts.SyntaxKind.TrueKeyword) {
required = true;
}
break;
}
}
}
}
let name;
if (propName && ts.isStringLiteralLike(propName)) {
name = _getStartEnd(propName);
}
defineModel.push({
localName,
name,
type,
modifierType,
runtimeType,
defaultValue,
defaultPropsArg,
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
+11
View File
@@ -0,0 +1,11 @@
import type * as ts from 'typescript';
import type { TextRange } from '../types';
export declare const enum BindingFlag {
None = 0,
Variable = 1,
Const = 2,
Component = 4
}
export declare function parseBindings(ts: typeof import('typescript'), ast: ts.SourceFile, componentExtsensions: string[]): Map<string, BindingFlag>;
export declare function getClosestMultiLineCommentRange(ts: typeof import('typescript'), node: ts.Node, parents: ts.Node[], ast: ts.SourceFile): TextRange | undefined;
export declare function getUnwrappedExpression(ts: typeof import('typescript'), node: ts.Node): ts.Node;
+100
View File
@@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBindings = parseBindings;
exports.getClosestMultiLineCommentRange = getClosestMultiLineCommentRange;
exports.getUnwrappedExpression = getUnwrappedExpression;
const collectBindings_1 = require("../utils/collectBindings");
const shared_1 = require("../utils/shared");
function parseBindings(ts, ast, componentExtsensions) {
const bindings = new Map();
ts.forEachChild(ast, node => {
if (ts.isVariableStatement(node)) {
const flags = (node.declarationList.flags & ts.NodeFlags.Const)
? 0 /* BindingFlag.None */ : 1 /* BindingFlag.Variable */;
for (const decl of node.declarationList.declarations) {
for (const { start, end } of (0, collectBindings_1.collectBindingRanges)(ts, decl.name, ast)) {
bindings.set(ast.text.slice(start, end), flags);
}
}
}
else if (ts.isFunctionDeclaration(node)) {
if (node.name && ts.isIdentifier(node.name)) {
bindings.set(_getNodeText(node.name), 2 /* BindingFlag.Const */);
}
}
else if (ts.isClassDeclaration(node)) {
if (node.name) {
bindings.set(_getNodeText(node.name), 2 /* BindingFlag.Const */);
}
}
else if (ts.isEnumDeclaration(node)) {
bindings.set(_getNodeText(node.name), 2 /* BindingFlag.Const */);
}
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))) {
bindings.set(_getNodeText(name), 2 /* BindingFlag.Const */ | 4 /* BindingFlag.Component */);
}
else {
bindings.set(_getNodeText(name), 1 /* BindingFlag.Variable */);
}
}
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))) {
bindings.set(_getNodeText(element.name), 2 /* BindingFlag.Const */ | 4 /* BindingFlag.Component */);
}
else {
bindings.set(_getNodeText(element.name), 1 /* BindingFlag.Variable */);
}
}
}
else {
bindings.set(_getNodeText(namedBindings.name), 1 /* BindingFlag.Variable */);
}
}
}
}
});
return bindings;
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,
};
}
}
function getUnwrappedExpression(ts, node) {
while (ts.isParenthesizedExpression(node)
|| ts.isAssertionExpression(node)
|| ts.isNonNullExpression(node)
|| ts.isSatisfiesExpression(node)) {
node = node.expression;
}
return node;
}
//# sourceMappingURL=utils.js.map
+2
View File
@@ -0,0 +1,2 @@
import type { RawVueCompilerOptions } from '../types';
export declare function parseVueCompilerOptions(comments: string[]): RawVueCompilerOptions | undefined;
+25
View File
@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseVueCompilerOptions = parseVueCompilerOptions;
const syntaxRE = /^\s*@(?<key>.+?)\s+(?<value>.+?)\s*$/m;
function parseVueCompilerOptions(comments) {
const entries = comments
.map(text => {
try {
const match = text.match(syntaxRE);
if (match) {
const { key, value } = match.groups ?? {};
if (key === 'plugins') {
return;
}
return [key, JSON.parse(value)];
}
}
catch { }
})
.filter(item => !!item);
if (entries.length) {
return Object.fromEntries(entries);
}
}
//# sourceMappingURL=vueCompilerOptions.js.map
+2
View File
@@ -0,0 +1,2 @@
import { type VueLanguagePlugin } from './types';
export declare function createPlugins(pluginContext: Parameters<VueLanguagePlugin>[0]): import("./types").VueLanguagePluginReturn[];
+73
View File
@@ -0,0 +1,73 @@
"use strict";
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");
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 sfcBlockRE = /<(script|style)\b([\s\S]*?)>([\s\S]*?)<\/\1>/g;
const langRE = /\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(sfcBlockRE)) {
const matchText = match[0];
const tag = match[1];
const attrs = match[2];
const lang = attrs.match(langRE)?.[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;
+97
View File
@@ -0,0 +1,97 @@
"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 frontmatterRE = /^---[\s\S]*?\n---(?:\r?\n|$)/;
const codeblockRE = /(`{3}|\${2})[\s\S]+?\1/g;
const codeSnippetImportRE = /^\s*<<<\s*.+/gm;
const sfcBlockRE = /<(script|style)\b[^>]*>([\s\S]*?)<\/\1>/g;
const htmlTagRE = /(?<=<\/?)([a-z][a-z0-9-]*)\b[^>]*(?=>)/gi;
const interpolationRE = /(?<=\{\{)[\s\S]*?(?=\}\})/g;
const inlineCodeRE = /(`{1,2})[^`\n]+\1/g;
const angleBracketRE = /<[^\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 pattern of [frontmatterRE, codeblockRE, codeSnippetImportRE]) {
content = content.replace(pattern, match => ' '.repeat(match.length));
}
const ambiguousRanges = [];
for (const pattern of [inlineCodeRE, angleBracketRE]) {
for (const { 0: text, index } of content.matchAll(pattern)) {
ambiguousRanges.push([index, index + text.length]);
}
}
const semanticRanges = [];
for (const pattern of [htmlTagRE, interpolationRE]) {
for (const { 0: text, index } of content.matchAll(pattern)) {
semanticRanges.push([index, index + text.length]);
}
}
const codes = [];
for (const { 0: text, index } of content.matchAll(sfcBlockRE)) {
if (ambiguousRanges.some(([start, end]) => index >= start && index < end)) {
continue;
}
codes.push([text, undefined, index]);
codes.push('\n\n');
content = content.slice(0, index) + ' '.repeat(text.length) + content.slice(index + text.length);
}
for (const [start, end] of ambiguousRanges) {
if (semanticRanges.some(range => start >= range[0] && end <= range[1])) {
continue;
}
content = content.slice(0, start) + ' '.repeat(end - start) + content.slice(end);
}
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 endTagRE = new RegExp(`</\\s*${hitBlock.type}\\s*>`);
const insertedEndTag = endTagRE.test(oldContent) !== endTagRE.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
+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 codeFeatures_1 = require("../codegen/codeFeatures");
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, codeFeatures_1.codeFeatures.full]);
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,
codeFeatures_1.codeFeatures.structure,
], 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