@vue/language-core
Advanced tools
Comparing version 2.2.2 to 2.2.4
@@ -37,7 +37,3 @@ "use strict"; | ||
const __VLS_nativeElements = { | ||
...{} as SVGElementTagNameMap, | ||
...{} as HTMLElementTagNameMap, | ||
}; | ||
type __VLS_NativeElements = __VLS_SpreadMerge<SVGElementTagNameMap, HTMLElementTagNameMap>; | ||
type __VLS_IntrinsicElements = ${(target >= 3.3 | ||
@@ -55,3 +51,3 @@ ? `import('${lib}/jsx-runtime').JSX.IntrinsicElements;` | ||
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A; | ||
type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void; | ||
type __VLS_SpreadMerge<A, B> = Omit<A, keyof B> & B; | ||
type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> = | ||
@@ -119,17 +115,10 @@ N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } : | ||
function __VLS_getVForSourceType(source: number): [number, number][]; | ||
function __VLS_getVForSourceType(source: string): [string, number][]; | ||
function __VLS_getVForSourceType<T extends any[]>(source: T): [ | ||
item: T[number], | ||
function __VLS_getVForSourceType<T extends number | string | any[] | Iterable<any>>(source: T): [ | ||
item: T extends number ? number | ||
: T extends string ? string | ||
: T extends any[] ? T[number] | ||
: T extends Iterable<infer T1> ? T1 | ||
: any, | ||
index: number, | ||
][]; | ||
function __VLS_getVForSourceType<T extends { [Symbol.iterator](): Iterator<any> }>(source: T): [ | ||
item: T extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never, | ||
index: number, | ||
][]; | ||
// #3845 | ||
function __VLS_getVForSourceType<T extends number | { [Symbol.iterator](): Iterator<any> }>(source: T): [ | ||
item: number | (Exclude<T, number> extends { [Symbol.iterator](): Iterator<infer T1> } ? T1 : never), | ||
index: number, | ||
][]; | ||
function __VLS_getVForSourceType<T>(source: T): [ | ||
@@ -148,18 +137,21 @@ item: T[keyof T], | ||
? T | ||
: __VLS_unknownDirective; | ||
function __VLS_withScope<T, K>(ctx: T, scope: K): ctx is T & K; | ||
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void; | ||
function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] }; | ||
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K): | ||
T extends new (...args: any) => any | ||
? (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { __ctx?: { | ||
attrs?: any, | ||
slots?: K extends { ${(0, shared_1.getSlotsPropertyName)(target)}: infer Slots } ? Slots : any, | ||
emit?: K extends { $emit: infer Emit } ? Emit : any | ||
} & { props?: ${fnPropsType}; expose?(exposed: K): void; } } | ||
? (props: ${fnPropsType}, ctx?: any) => __VLS_Element & { | ||
__ctx?: { | ||
attrs?: any; | ||
slots?: K extends { ${(0, shared_1.getSlotsPropertyName)(target)}: infer Slots } ? Slots : any; | ||
emit?: K extends { $emit: infer Emit } ? Emit : any; | ||
expose?(exposed: K): void; | ||
props?: ${fnPropsType}; | ||
} | ||
} | ||
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T> | ||
: T extends (...args: any) => any ? T | ||
: (_: {}${checkUnknownProps ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${checkUnknownProps ? '' : ' & Record<string, unknown>'} } }; | ||
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (_: T${checkUnknownComponents ? '' : ' & Record<string, unknown>'}) => void; | ||
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : []; | ||
function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S; | ||
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (attrs: T${checkUnknownComponents ? '' : ' & Record<string, unknown>'}) => void; | ||
function __VLS_asFunctionalSlot<S>(slot: S): (props: NonNullable<S> extends (props: infer P) => any ? P : {}) => void; | ||
function __VLS_tryAsConstant<const T>(t: T): T; | ||
@@ -166,0 +158,0 @@ } |
@@ -35,2 +35,12 @@ "use strict"; | ||
} | ||
if (options.vueCompilerOptions.target >= 3.5 | ||
&& options.vueCompilerOptions.inferComponentDollarRefs | ||
&& options.templateCodegen?.templateRefs.size) { | ||
yield `__typeRefs: {} as __VLS_TemplateRefs,${utils_1.newLine}`; | ||
} | ||
if (options.vueCompilerOptions.target >= 3.5 | ||
&& options.vueCompilerOptions.inferComponentDollarEl | ||
&& options.templateCodegen?.singleRootElTypes.length) { | ||
yield `__typeEl: {} as __VLS_RootEl,${utils_1.newLine}`; | ||
} | ||
if (options.sfc.script && options.scriptRanges?.exportDefault?.args) { | ||
@@ -40,8 +50,2 @@ const { args } = options.scriptRanges.exportDefault; | ||
} | ||
if (options.vueCompilerOptions.target >= 3.5 && options.templateCodegen?.templateRefs.size) { | ||
yield `__typeRefs: {} as __VLS_TemplateRefs,${utils_1.newLine}`; | ||
} | ||
if (options.vueCompilerOptions.target >= 3.5 && options.templateCodegen?.singleRootElType) { | ||
yield `__typeEl: {} as __VLS_RootEl,${utils_1.newLine}`; | ||
} | ||
yield `})`; | ||
@@ -48,0 +52,0 @@ } |
@@ -13,3 +13,2 @@ "use strict"; | ||
const src_1 = require("./src"); | ||
const styleModulesType_1 = require("./styleModulesType"); | ||
const template_1 = require("./template"); | ||
@@ -35,4 +34,7 @@ function* generateScript(options) { | ||
if (options.sfc.script?.src) { | ||
yield* (0, src_1.generateSrc)(options.sfc.script, options.sfc.script.src); | ||
yield* (0, src_1.generateSrc)(options.sfc.script.src); | ||
} | ||
if (options.sfc.scriptSetup && options.scriptSetupRanges) { | ||
yield* (0, scriptSetup_1.generateScriptSetupImports)(options.sfc.scriptSetup, options.scriptSetupRanges); | ||
} | ||
if (options.sfc.script && options.scriptRanges) { | ||
@@ -43,3 +45,2 @@ const { exportDefault, classBlockEnd } = options.scriptRanges; | ||
if (options.sfc.scriptSetup && options.scriptSetupRanges) { | ||
yield* (0, scriptSetup_1.generateScriptSetupImports)(options.sfc.scriptSetup, options.scriptSetupRanges); | ||
if (exportDefault) { | ||
@@ -100,3 +101,2 @@ yield (0, utils_1.generateSfcBlockSection)(options.sfc.script, 0, exportDefault.expression.start, codeFeatures_1.codeFeatures.all); | ||
else if (options.sfc.scriptSetup && options.scriptSetupRanges) { | ||
yield* (0, scriptSetup_1.generateScriptSetupImports)(options.sfc.scriptSetup, options.scriptSetupRanges); | ||
yield* (0, scriptSetup_1.generateScriptSetup)(options, ctx, options.sfc.scriptSetup, options.scriptSetupRanges); | ||
@@ -114,4 +114,2 @@ } | ||
} | ||
// #4788 | ||
yield* (0, styleModulesType_1.generateStyleModulesType)(options, ctx); | ||
if (options.edited) { | ||
@@ -118,0 +116,0 @@ yield `type __VLS_IntrinsicElementsCompletion = __VLS_IntrinsicElements${utils_1.endOfLine}`; |
@@ -33,13 +33,17 @@ "use strict"; | ||
} | ||
yield `(<`; | ||
yield [ | ||
scriptSetup.generic, | ||
scriptSetup.name, | ||
scriptSetup.genericOffset, | ||
codeFeatures_1.codeFeatures.all, | ||
]; | ||
if (!scriptSetup.generic.endsWith(`,`)) { | ||
yield `,`; | ||
yield `(`; | ||
if (typeof scriptSetup.generic === 'object') { | ||
yield `<`; | ||
yield [ | ||
scriptSetup.generic.text, | ||
'main', | ||
scriptSetup.generic.offset, | ||
codeFeatures_1.codeFeatures.all, | ||
]; | ||
if (!scriptSetup.generic.text.endsWith(`,`)) { | ||
yield `,`; | ||
} | ||
yield `>`; | ||
} | ||
yield `>(${utils_1.newLine}` | ||
yield `(${utils_1.newLine}` | ||
+ ` __VLS_props: NonNullable<Awaited<typeof __VLS_setup>>['props'],${utils_1.newLine}` | ||
@@ -127,12 +131,14 @@ + ` __VLS_ctx?: ${ctx.localTypes.PrettifyLocal}<Pick<NonNullable<Awaited<typeof __VLS_setup>>, 'attrs' | 'emit' | 'slots'>>,${utils_1.newLine}` // use __VLS_Prettify for less dts code | ||
} | ||
for (const { callExp } of scriptSetupRanges.useAttrs) { | ||
setupCodeModifies.push([ | ||
[`(`], | ||
callExp.start, | ||
callExp.start | ||
], [ | ||
[` as typeof __VLS_special.$attrs)`], | ||
callExp.end, | ||
callExp.end | ||
]); | ||
if (options.vueCompilerOptions.inferTemplateDollarAttrs) { | ||
for (const { callExp } of scriptSetupRanges.useAttrs) { | ||
setupCodeModifies.push([ | ||
[`(`], | ||
callExp.start, | ||
callExp.start | ||
], [ | ||
[` as typeof __VLS_dollars.$attrs)`], | ||
callExp.end, | ||
callExp.end | ||
]); | ||
} | ||
} | ||
@@ -161,3 +167,3 @@ for (const { callExp, exp, arg } of scriptSetupRanges.useCssModule) { | ||
setupCodeModifies.push([ | ||
[`(__VLS_placeholder)`], | ||
[`__VLS_placeholder`], | ||
arg.start, | ||
@@ -168,12 +174,14 @@ arg.end | ||
} | ||
for (const { callExp } of scriptSetupRanges.useSlots) { | ||
setupCodeModifies.push([ | ||
[`(`], | ||
callExp.start, | ||
callExp.start | ||
], [ | ||
[` as typeof __VLS_special.$slots)`], | ||
callExp.end, | ||
callExp.end | ||
]); | ||
if (options.vueCompilerOptions.inferTemplateDollarSlots) { | ||
for (const { callExp } of scriptSetupRanges.useSlots) { | ||
setupCodeModifies.push([ | ||
[`(`], | ||
callExp.start, | ||
callExp.start | ||
], [ | ||
[` as typeof __VLS_dollars.$slots)`], | ||
callExp.end, | ||
callExp.end | ||
]); | ||
} | ||
} | ||
@@ -217,3 +225,3 @@ const isTs = options.lang !== 'js' && options.lang !== 'jsx'; | ||
setupCodeModifies.push([ | ||
[`(__VLS_placeholder)`], | ||
[`__VLS_placeholder`], | ||
arg.start, | ||
@@ -248,3 +256,6 @@ arg.end | ||
if (syntax) { | ||
if (!options.vueCompilerOptions.skipTemplateCodegen && (options.templateCodegen?.hasSlot || scriptSetupRanges.defineSlots)) { | ||
if (!options.vueCompilerOptions.skipTemplateCodegen | ||
&& (scriptSetupRanges.defineSlots | ||
|| options.templateCodegen?.slots.length | ||
|| options.templateCodegen?.dynamicSlots.length)) { | ||
yield `const __VLS_component = `; | ||
@@ -432,3 +443,3 @@ yield* (0, component_1.generateComponent)(options, ctx, scriptSetup, scriptSetupRanges); | ||
yield* generateDefinePropType(scriptSetup, propName, localName, defineModel); | ||
if (!defineModel.required) { | ||
if (!defineModel.required && defineModel.defaultValue === undefined) { | ||
yield ` | undefined`; | ||
@@ -435,0 +446,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import type { Code, Sfc } from '../../types'; | ||
export declare function generateSrc(script: NonNullable<Sfc['script']>, src: string): Generator<Code>; | ||
import type { Code, SfcBlockAttr } from '../../types'; | ||
export declare function generateSrc(src: SfcBlockAttr): Generator<Code>; |
@@ -6,47 +6,46 @@ "use strict"; | ||
const utils_1 = require("../utils"); | ||
function* generateSrc(script, src) { | ||
if (src.endsWith('.d.ts')) { | ||
src = src.slice(0, -'.d.ts'.length); | ||
function* generateSrc(src) { | ||
if (src === true) { | ||
return; | ||
} | ||
else if (src.endsWith('.ts')) { | ||
src = src.slice(0, -'.ts'.length); | ||
let { text } = src; | ||
if (text.endsWith('.d.ts')) { | ||
text = text.slice(0, -'.d.ts'.length); | ||
} | ||
else if (src.endsWith('.tsx')) { | ||
src = src.slice(0, -'.tsx'.length) + '.jsx'; | ||
else if (text.endsWith('.ts')) { | ||
text = text.slice(0, -'.ts'.length); | ||
} | ||
if (!src.endsWith('.js') && !src.endsWith('.jsx')) { | ||
src = src + '.js'; | ||
else if (text.endsWith('.tsx')) { | ||
text = text.slice(0, -'.tsx'.length) + '.jsx'; | ||
} | ||
if (!text.endsWith('.js') && !text.endsWith('.jsx')) { | ||
text = text + '.js'; | ||
} | ||
yield `export * from `; | ||
yield [ | ||
`'${src}'`, | ||
'script', | ||
script.srcOffset - 1, | ||
{ | ||
...codeFeatures_1.codeFeatures.all, | ||
navigation: src === script.src | ||
? true | ||
: { | ||
shouldRename: () => false, | ||
resolveRenameEditText(newName) { | ||
if (newName.endsWith('.jsx') || newName.endsWith('.js')) { | ||
newName = newName.split('.').slice(0, -1).join('.'); | ||
} | ||
if (script?.src?.endsWith('.d.ts')) { | ||
newName = newName + '.d.ts'; | ||
} | ||
else if (script?.src?.endsWith('.ts')) { | ||
newName = newName + '.ts'; | ||
} | ||
else if (script?.src?.endsWith('.tsx')) { | ||
newName = newName + '.tsx'; | ||
} | ||
return newName; | ||
}, | ||
yield* (0, utils_1.generateSfcBlockAttrValue)(src, text, { | ||
...codeFeatures_1.codeFeatures.all, | ||
navigation: text === src.text | ||
? true | ||
: { | ||
shouldRename: () => false, | ||
resolveRenameEditText(newName) { | ||
if (newName.endsWith('.jsx') || newName.endsWith('.js')) { | ||
newName = newName.split('.').slice(0, -1).join('.'); | ||
} | ||
if (src?.text.endsWith('.d.ts')) { | ||
newName = newName + '.d.ts'; | ||
} | ||
else if (src?.text.endsWith('.ts')) { | ||
newName = newName + '.ts'; | ||
} | ||
else if (src?.text.endsWith('.tsx')) { | ||
newName = newName + '.tsx'; | ||
} | ||
return newName; | ||
}, | ||
}, | ||
]; | ||
}, | ||
}); | ||
yield utils_1.endOfLine; | ||
yield `export { default } from '${src}'${utils_1.endOfLine}`; | ||
yield `export { default } from '${text}'${utils_1.endOfLine}`; | ||
} | ||
//# sourceMappingURL=src.js.map |
import type { Code } from '../../types'; | ||
import { TemplateCodegenContext } from '../template/context'; | ||
import { type TemplateCodegenContext } from '../template/context'; | ||
import type { ScriptCodegenContext } from './context'; | ||
@@ -7,3 +7,2 @@ import type { ScriptCodegenOptions } from './index'; | ||
export declare function generateTemplateDirectives(options: ScriptCodegenOptions): Generator<Code>; | ||
export declare function generateCssClassProperty(styleIndex: number, classNameWithDot: string, offset: number, propertyType: string, optional: boolean): Generator<Code>; | ||
export declare function getTemplateUsageVars(options: ScriptCodegenOptions, ctx: ScriptCodegenContext): Set<string>; |
@@ -5,6 +5,7 @@ "use strict"; | ||
exports.generateTemplateDirectives = generateTemplateDirectives; | ||
exports.generateCssClassProperty = generateCssClassProperty; | ||
exports.getTemplateUsageVars = getTemplateUsageVars; | ||
const shared_1 = require("../../utils/shared"); | ||
const codeFeatures_1 = require("../codeFeatures"); | ||
const modules_1 = require("../style/modules"); | ||
const scopedClasses_1 = require("../style/scopedClasses"); | ||
const context_1 = require("../template/context"); | ||
@@ -97,4 +98,5 @@ const interpolation_1 = require("../template/interpolation"); | ||
function* generateTemplateBody(options, templateCodegenCtx) { | ||
yield* generateStyleScopedClasses(options, templateCodegenCtx); | ||
yield* (0, scopedClasses_1.generateStyleScopedClasses)(options, templateCodegenCtx); | ||
yield* (0, styleScopedClasses_1.generateStyleScopedClassReferences)(templateCodegenCtx, true); | ||
yield* (0, modules_1.generateStyleModules)(options); | ||
yield* generateCssVars(options, templateCodegenCtx); | ||
@@ -116,50 +118,2 @@ if (options.templateCodegen) { | ||
} | ||
function* generateStyleScopedClasses(options, ctx) { | ||
const firstClasses = new Set(); | ||
yield `type __VLS_StyleScopedClasses = {}`; | ||
for (let i = 0; i < options.sfc.styles.length; i++) { | ||
const style = options.sfc.styles[i]; | ||
const option = options.vueCompilerOptions.experimentalResolveStyleCssClasses; | ||
if (option === 'always' || (option === 'scoped' && style.scoped)) { | ||
for (const className of style.classNames) { | ||
if (firstClasses.has(className.text)) { | ||
ctx.scopedClasses.push({ | ||
source: 'style_' + i, | ||
className: className.text.slice(1), | ||
offset: className.offset + 1 | ||
}); | ||
continue; | ||
} | ||
firstClasses.add(className.text); | ||
yield* generateCssClassProperty(i, className.text, className.offset, 'boolean', true); | ||
} | ||
} | ||
} | ||
yield utils_1.endOfLine; | ||
} | ||
function* generateCssClassProperty(styleIndex, classNameWithDot, offset, propertyType, optional) { | ||
yield `${utils_1.newLine} & { `; | ||
yield [ | ||
'', | ||
'style_' + styleIndex, | ||
offset, | ||
codeFeatures_1.codeFeatures.navigation, | ||
]; | ||
yield `'`; | ||
yield [ | ||
classNameWithDot.slice(1), | ||
'style_' + styleIndex, | ||
offset + 1, | ||
codeFeatures_1.codeFeatures.navigation, | ||
]; | ||
yield `'`; | ||
yield [ | ||
'', | ||
'style_' + styleIndex, | ||
offset + classNameWithDot.length, | ||
codeFeatures_1.codeFeatures.navigationWithoutRename, | ||
]; | ||
yield `${optional ? '?' : ''}: ${propertyType}`; | ||
yield ` }`; | ||
} | ||
function* generateCssVars(options, ctx) { | ||
@@ -166,0 +120,0 @@ if (!options.sfc.styles.length) { |
@@ -6,2 +6,99 @@ import type * as CompilerDOM from '@vue/compiler-dom'; | ||
export type TemplateCodegenContext = ReturnType<typeof createTemplateCodegenContext>; | ||
/** | ||
* Creates and returns a Context object used for generating type-checkable TS code | ||
* from the template section of a .vue file. | ||
* | ||
* ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives. | ||
* | ||
* Vue language tooling supports a number of directives for suppressing diagnostics within | ||
* Vue templates (https://github.com/vuejs/language-tools/pull/3215) | ||
* | ||
* Here is an overview for how support for how @vue-expect-error is implemented within this file | ||
* (@vue-expect-error is the most complicated directive to support due to its behavior of raising | ||
* a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics). | ||
* | ||
* Given .vue code: | ||
* | ||
* ```vue | ||
* <script setup lang="ts"> | ||
* defineProps<{ | ||
* knownProp1: string; | ||
* knownProp2: string; | ||
* knownProp3: string; | ||
* knownProp4_will_trigger_unused_expect_error: string; | ||
* }>(); | ||
* </script> | ||
* | ||
* <template> | ||
* {{ knownProp1 }} | ||
* {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] --> | ||
* {{ knownProp2 }} | ||
* <!-- @vue-expect-error This suppresses an Unknown Property Error --> | ||
* {{ suppressed_error_unknownProp }} | ||
* {{ knownProp3 }} | ||
* <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) --> | ||
* {{ knownProp4_will_trigger_unused_expect_error }} | ||
* </template> | ||
* ``` | ||
* | ||
* The above code should raise two diagnostics: | ||
* | ||
* 1. Property 'error_unknownProp' does not exist on type [...] | ||
* 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive | ||
* that covers code that doesn't actually raise an error -- note that all `@vue-...` directives | ||
* will ultimately translate into `@ts-...` diagnostics. | ||
* | ||
* The above code will produce the following type-checkable TS code (note: omitting asterisks | ||
* to prevent VSCode syntax double-greying out double-commented code). | ||
* | ||
* ```ts | ||
* ( __VLS_ctx.knownProp1 ); | ||
* ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...] | ||
* ( __VLS_ctx.knownProp2 ); | ||
* // @vue-expect-error start | ||
* ( __VLS_ctx.suppressed_error_unknownProp ); | ||
* // @ts-expect-error __VLS_TS_EXPECT_ERROR | ||
* ; | ||
* // @vue-expect-error end of INTERPOLATION | ||
* ( __VLS_ctx.knownProp3 ); | ||
* // @vue-expect-error start | ||
* ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error ); | ||
* // @ts-expect-error __VLS_TS_EXPECT_ERROR | ||
* ; | ||
* // @vue-expect-error end of INTERPOLATION | ||
* ``` | ||
* | ||
* In the generated code, there are actually 3 diagnostic errors that'll be raised in the first | ||
* pass on this generated code (but through cleverness described below, not all of them will be | ||
* propagated back to the original .vue file): | ||
* | ||
* 1. Property 'error_unknownProp' does not exist on type [...] | ||
* 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR` | ||
* 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR` | ||
* | ||
* Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`; | ||
* Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`; | ||
* any `@vue-` prefixed directives in the comments are only for debugging purposes. | ||
* | ||
* As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but | ||
* only 2 should be propagated back to the original .vue file. | ||
* | ||
* (The reason we structure things this way is somewhat complicated, but in short it allows us | ||
* to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors | ||
* while covering a number of edge cases.) | ||
* | ||
* So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR` | ||
* directives should be reported as an unused directive or not. | ||
* | ||
* To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the | ||
* `verification` property of the `CodeInformation` object attached to the mapping between source .vue | ||
* and generated .ts code. The `verification` property determines whether "verification" (which includes | ||
* semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided, | ||
* can be used to determine whether a given diagnostic should be reported back "upwards" to the original | ||
* .vue file or not. | ||
* | ||
* See the comments in the code below for how and where we use this hook to keep track of whether | ||
* an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive, | ||
* and additionally how we use that to determine whether to propagate diagnostics back upward. | ||
*/ | ||
export declare function createTemplateCodegenContext(options: Pick<TemplateCodegenOptions, 'scriptSetupBindingNames' | 'edited'>): { | ||
@@ -38,3 +135,3 @@ codeFeatures: { | ||
}[]; | ||
specialVars: Set<string>; | ||
dollarVars: Set<string>; | ||
accessExternalVariables: Map<string, Set<number>>; | ||
@@ -53,6 +150,8 @@ lastGenericComment: { | ||
inlayHints: InlayHintInfo[]; | ||
hasSlot: boolean; | ||
bindingAttrLocs: CompilerDOM.SourceLocation[]; | ||
inheritedAttrVars: Set<string>; | ||
templateRefs: Map<string, [varName: string, offset: number]>; | ||
templateRefs: Map<string, { | ||
typeExp: string; | ||
offset: number; | ||
}>; | ||
currentComponent: { | ||
@@ -62,4 +161,4 @@ ctxVar: string; | ||
} | undefined; | ||
singleRootElType: string | undefined; | ||
singleRootNode: CompilerDOM.ElementNode | undefined; | ||
singleRootElTypes: string[]; | ||
singleRootNodes: Set<CompilerDOM.ElementNode | null>; | ||
accessExternalVariable(name: string, offset?: number): void; | ||
@@ -70,2 +169,4 @@ hasLocalVariable: (name: string) => boolean; | ||
getInternalVariable: () => string; | ||
getHoistVariable: (originalVar: string) => string; | ||
generateHoistVariables: () => Generator<string, void, unknown>; | ||
ignoreError: () => Generator<Code>; | ||
@@ -72,0 +173,0 @@ expectError: (prevNode: CompilerDOM.CommentNode) => Generator<Code>; |
@@ -6,2 +6,99 @@ "use strict"; | ||
const utils_1 = require("../utils"); | ||
/** | ||
* Creates and returns a Context object used for generating type-checkable TS code | ||
* from the template section of a .vue file. | ||
* | ||
* ## Implementation Notes for supporting `@vue-ignore`, `@vue-expect-error`, and `@vue-skip` directives. | ||
* | ||
* Vue language tooling supports a number of directives for suppressing diagnostics within | ||
* Vue templates (https://github.com/vuejs/language-tools/pull/3215) | ||
* | ||
* Here is an overview for how support for how @vue-expect-error is implemented within this file | ||
* (@vue-expect-error is the most complicated directive to support due to its behavior of raising | ||
* a diagnostic when it is annotating a piece of code that doesn't actually have any errors/warning/diagnostics). | ||
* | ||
* Given .vue code: | ||
* | ||
* ```vue | ||
* <script setup lang="ts"> | ||
* defineProps<{ | ||
* knownProp1: string; | ||
* knownProp2: string; | ||
* knownProp3: string; | ||
* knownProp4_will_trigger_unused_expect_error: string; | ||
* }>(); | ||
* </script> | ||
* | ||
* <template> | ||
* {{ knownProp1 }} | ||
* {{ error_unknownProp }} <!-- ERROR: Property 'error_unknownProp' does not exist on type [...] --> | ||
* {{ knownProp2 }} | ||
* <!-- @vue-expect-error This suppresses an Unknown Property Error --> | ||
* {{ suppressed_error_unknownProp }} | ||
* {{ knownProp3 }} | ||
* <!-- @vue-expect-error This will trigger Unused '@ts-expect-error' directive.ts(2578) --> | ||
* {{ knownProp4_will_trigger_unused_expect_error }} | ||
* </template> | ||
* ``` | ||
* | ||
* The above code should raise two diagnostics: | ||
* | ||
* 1. Property 'error_unknownProp' does not exist on type [...] | ||
* 2. Unused '@ts-expect-error' directive.ts(2578) -- this is the bottom `@vue-expect-error` directive | ||
* that covers code that doesn't actually raise an error -- note that all `@vue-...` directives | ||
* will ultimately translate into `@ts-...` diagnostics. | ||
* | ||
* The above code will produce the following type-checkable TS code (note: omitting asterisks | ||
* to prevent VSCode syntax double-greying out double-commented code). | ||
* | ||
* ```ts | ||
* ( __VLS_ctx.knownProp1 ); | ||
* ( __VLS_ctx.error_unknownProp ); // ERROR: Property 'error_unknownProp' does not exist on type [...] | ||
* ( __VLS_ctx.knownProp2 ); | ||
* // @vue-expect-error start | ||
* ( __VLS_ctx.suppressed_error_unknownProp ); | ||
* // @ts-expect-error __VLS_TS_EXPECT_ERROR | ||
* ; | ||
* // @vue-expect-error end of INTERPOLATION | ||
* ( __VLS_ctx.knownProp3 ); | ||
* // @vue-expect-error start | ||
* ( __VLS_ctx.knownProp4_will_trigger_unused_expect_error ); | ||
* // @ts-expect-error __VLS_TS_EXPECT_ERROR | ||
* ; | ||
* // @vue-expect-error end of INTERPOLATION | ||
* ``` | ||
* | ||
* In the generated code, there are actually 3 diagnostic errors that'll be raised in the first | ||
* pass on this generated code (but through cleverness described below, not all of them will be | ||
* propagated back to the original .vue file): | ||
* | ||
* 1. Property 'error_unknownProp' does not exist on type [...] | ||
* 2. Unused '@ts-expect-error' directive.ts(2578) from the 1st `@ts-expect-error __VLS_TS_EXPECT_ERROR` | ||
* 3. Unused '@ts-expect-error' directive.ts(2578) from the 2nd `@ts-expect-error __VLS_TS_EXPECT_ERROR` | ||
* | ||
* Be sure to pay careful attention to the mixture of `@vue-expect-error` and `@ts-expect-error`; | ||
* Within the TS file, the only "real" directives recognized by TS are going to be prefixed with `@ts-`; | ||
* any `@vue-` prefixed directives in the comments are only for debugging purposes. | ||
* | ||
* As mentioned above, there are 3 diagnostics errors that'll be generated for the above code, but | ||
* only 2 should be propagated back to the original .vue file. | ||
* | ||
* (The reason we structure things this way is somewhat complicated, but in short it allows us | ||
* to lean on TS as much as possible to generate actual `unused @ts-expect-error directive` errors | ||
* while covering a number of edge cases.) | ||
* | ||
* So, we need a way to dynamically decide whether each of the `@ts-expect-error __VLS_TS_EXPECT_ERROR` | ||
* directives should be reported as an unused directive or not. | ||
* | ||
* To do this, we'll make use of the `shouldReport` callback that'll optionally be provided to the | ||
* `verification` property of the `CodeInformation` object attached to the mapping between source .vue | ||
* and generated .ts code. The `verification` property determines whether "verification" (which includes | ||
* semantic diagnostics) should be performed on the generated .ts code, and `shouldReport`, if provided, | ||
* can be used to determine whether a given diagnostic should be reported back "upwards" to the original | ||
* .vue file or not. | ||
* | ||
* See the comments in the code below for how and where we use this hook to keep track of whether | ||
* an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive, | ||
* and additionally how we use that to determine whether to propagate diagnostics back upward. | ||
*/ | ||
function createTemplateCodegenContext(options) { | ||
@@ -15,2 +112,4 @@ let ignoredError = false; | ||
if (ignoredError) { | ||
// We are currently in a region of code covered by a @vue-ignore directive, so don't | ||
// even bother performing any type-checking: set verification to false. | ||
return { | ||
@@ -22,2 +121,6 @@ ...features, | ||
if (expectErrorToken) { | ||
// We are currently in a region of code covered by a @vue-expect-error directive. We need to | ||
// keep track of the number of errors encountered within this region so that we can know whether | ||
// we will need to propagate an "unused ts-expect-error" diagnostic back to the original | ||
// .vue file or not. | ||
const token = expectErrorToken; | ||
@@ -37,4 +140,5 @@ return { | ||
} | ||
const hoistVars = new Map(); | ||
const localVars = new Map(); | ||
const specialVars = new Set(); | ||
const dollarVars = new Set(); | ||
const accessExternalVariables = new Map(); | ||
@@ -60,3 +164,3 @@ const slots = []; | ||
dynamicSlots, | ||
specialVars, | ||
dollarVars, | ||
accessExternalVariables, | ||
@@ -68,3 +172,2 @@ lastGenericComment, | ||
inlayHints, | ||
hasSlot: false, | ||
bindingAttrLocs, | ||
@@ -74,4 +177,4 @@ inheritedAttrVars, | ||
currentComponent: undefined, | ||
singleRootElType: undefined, | ||
singleRootNode: undefined, | ||
singleRootElTypes: [], | ||
singleRootNodes: new Set(), | ||
accessExternalVariable(name, offset) { | ||
@@ -98,2 +201,20 @@ let arr = accessExternalVariables.get(name); | ||
}, | ||
getHoistVariable: (originalVar) => { | ||
let name = hoistVars.get(originalVar); | ||
if (name === undefined) { | ||
hoistVars.set(originalVar, name = `__VLS_${variableId++}`); | ||
} | ||
return name; | ||
}, | ||
generateHoistVariables: function* () { | ||
// trick to avoid TS 4081 (#5186) | ||
if (hoistVars.size) { | ||
yield `// @ts-ignore${utils_1.newLine}`; | ||
yield `var `; | ||
for (const [originalVar, hoistVar] of hoistVars) { | ||
yield `${hoistVar} = ${originalVar}, `; | ||
} | ||
yield utils_1.endOfLine; | ||
} | ||
}, | ||
ignoreError: function* () { | ||
@@ -119,2 +240,5 @@ if (!ignoredError) { | ||
verification: { | ||
// If no errors/warnings/diagnostics were reported within the region of code covered | ||
// by the @vue-expect-error directive, then we should allow any `unused @ts-expect-error` | ||
// diagnostics to be reported upward. | ||
shouldReport: () => token.errors === 0, | ||
@@ -121,0 +245,0 @@ }, |
@@ -5,3 +5,3 @@ import * as CompilerDOM from '@vue/compiler-dom'; | ||
import type { TemplateCodegenOptions } from './index'; | ||
export declare function generateComponent(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>; | ||
export declare function generateComponent(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, isVForChild: boolean): Generator<Code>; | ||
export declare function generateElement(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, isVForChild: boolean): Generator<Code>; |
@@ -20,3 +20,3 @@ "use strict"; | ||
const colonReg = /:/g; | ||
function* generateComponent(options, ctx, node) { | ||
function* generateComponent(options, ctx, node, isVForChild) { | ||
const tagOffsets = [node.loc.start.offset + options.template.content.slice(node.loc.start.offset).indexOf(node.tag)]; | ||
@@ -32,11 +32,9 @@ if (!node.isSelfClosing && options.template.lang === 'html') { | ||
const matchImportName = possibleOriginalNames.find(name => options.scriptSetupImportComponentNames.has(name)); | ||
const var_originalComponent = matchImportName ?? ctx.getInternalVariable(); | ||
const var_functionalComponent = ctx.getInternalVariable(); | ||
const var_componentInstance = ctx.getInternalVariable(); | ||
const var_componentEmit = ctx.getInternalVariable(); | ||
const var_componentEvents = ctx.getInternalVariable(); | ||
const var_defineComponentCtx = ctx.getInternalVariable(); | ||
const componentOriginalVar = matchImportName ?? ctx.getInternalVariable(); | ||
const componentFunctionalVar = ctx.getInternalVariable(); | ||
const componentVNodeVar = ctx.getInternalVariable(); | ||
const componentCtxVar = ctx.getInternalVariable(); | ||
const isComponentTag = node.tag.toLowerCase() === 'component'; | ||
ctx.currentComponent = { | ||
ctxVar: var_defineComponentCtx, | ||
ctxVar: componentCtxVar, | ||
used: false | ||
@@ -74,10 +72,9 @@ }; | ||
if (matchImportName) { | ||
// hover, renaming / find references support | ||
yield `// @ts-ignore${utils_1.newLine}`; // #2304 | ||
yield `/** @type { [`; | ||
// navigation support | ||
yield `/** @type {[`; | ||
for (const tagOffset of tagOffsets) { | ||
yield `typeof `; | ||
if (var_originalComponent === node.tag) { | ||
if (componentOriginalVar === node.tag) { | ||
yield [ | ||
var_originalComponent, | ||
componentOriginalVar, | ||
'template', | ||
@@ -100,10 +97,10 @@ tagOffset, | ||
} | ||
yield `] } */${utils_1.endOfLine}`; | ||
yield `]} */${utils_1.endOfLine}`; | ||
} | ||
else if (dynamicTagInfo) { | ||
yield `const ${var_originalComponent} = (`; | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, dynamicTagInfo.tag, dynamicTagInfo.offsets[0], dynamicTagInfo.astHolder, '(', ')'); | ||
yield `const ${componentOriginalVar} = (`; | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, dynamicTagInfo.tag, dynamicTagInfo.offsets[0], dynamicTagInfo.astHolder, `(`, `)`); | ||
if (dynamicTagInfo.offsets[1] !== undefined) { | ||
yield `,`; | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.withoutCompletion, dynamicTagInfo.tag, dynamicTagInfo.offsets[1], dynamicTagInfo.astHolder, '(', ')'); | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.withoutCompletion, dynamicTagInfo.tag, dynamicTagInfo.offsets[1], dynamicTagInfo.astHolder, `(`, `)`); | ||
} | ||
@@ -113,3 +110,3 @@ yield `)${utils_1.endOfLine}`; | ||
else if (!isComponentTag) { | ||
yield `const ${var_originalComponent} = ({} as __VLS_WithComponent<'${getCanonicalComponentName(node.tag)}', __VLS_LocalComponents, `; | ||
yield `const ${componentOriginalVar} = ({} as __VLS_WithComponent<'${getCanonicalComponentName(node.tag)}', __VLS_LocalComponents, `; | ||
if (options.selfComponentName && possibleOriginalNames.includes(options.selfComponentName)) { | ||
@@ -131,4 +128,4 @@ yield `typeof __VLS_self & (new () => { ` | ||
if (utils_1.variableNameRegex.test(camelizedTag)) { | ||
// renaming / find references support | ||
yield `/** @type { [`; | ||
// navigation support | ||
yield `/** @type {[`; | ||
for (const tagOffset of tagOffsets) { | ||
@@ -147,3 +144,3 @@ for (const shouldCapitalize of (node.tag[0] === node.tag[0].toUpperCase() ? [false] : [true, false])) { | ||
} | ||
yield `] } */${utils_1.endOfLine}`; | ||
yield `]} */${utils_1.endOfLine}`; | ||
// auto import support | ||
@@ -163,6 +160,6 @@ if (options.edited) { | ||
else { | ||
yield `const ${var_originalComponent} = {} as any${utils_1.endOfLine}`; | ||
yield `const ${componentOriginalVar} = {} as any${utils_1.endOfLine}`; | ||
} | ||
yield `// @ts-ignore${utils_1.newLine}`; | ||
yield `const ${var_functionalComponent} = __VLS_asFunctionalComponent(${var_originalComponent}, new ${var_originalComponent}({${utils_1.newLine}`; | ||
yield `const ${componentFunctionalVar} = __VLS_asFunctionalComponent(${componentOriginalVar}, new ${componentOriginalVar}({${utils_1.newLine}`; | ||
yield* (0, elementProps_1.generateElementProps)(options, ctx, node, props, options.vueCompilerOptions.checkUnknownProps, false); | ||
@@ -174,42 +171,42 @@ yield `}))${utils_1.endOfLine}`; | ||
shouldReport(_source, code) { | ||
// https://typescript.tv/errors/#ts6133 | ||
return String(code) !== '6133'; | ||
}, | ||
} | ||
}), var_componentInstance); | ||
yield ` = ${var_functionalComponent}`; | ||
}), componentVNodeVar); | ||
yield ` = ${componentFunctionalVar}`; | ||
yield* generateComponentGeneric(ctx); | ||
yield `(`; | ||
yield* (0, utils_1.wrapWith)(tagOffsets[0], tagOffsets[0] + node.tag.length, ctx.codeFeatures.verification, `{${utils_1.newLine}`, ...(0, elementProps_1.generateElementProps)(options, ctx, node, props, options.vueCompilerOptions.checkUnknownProps, true, failedPropExps), `}`); | ||
yield `, ...__VLS_functionalComponentArgsRest(${var_functionalComponent}))${utils_1.endOfLine}`; | ||
yield `, ...__VLS_functionalComponentArgsRest(${componentFunctionalVar}))${utils_1.endOfLine}`; | ||
yield* generateFailedPropExps(options, ctx, failedPropExps); | ||
const [refName, offset] = yield* generateVScope(options, ctx, node, props); | ||
const isRootNode = node === ctx.singleRootNode; | ||
yield* (0, elementEvents_1.generateElementEvents)(options, ctx, node, componentFunctionalVar, componentVNodeVar, componentCtxVar); | ||
yield* (0, elementDirectives_1.generateElementDirectives)(options, ctx, node); | ||
const [refName, offset] = yield* generateElementReference(options, ctx, node); | ||
const tag = (0, shared_2.hyphenateTag)(node.tag); | ||
const isRootNode = ctx.singleRootNodes.has(node) && !options.vueCompilerOptions.fallthroughComponentNames.includes(tag); | ||
if (refName || isRootNode) { | ||
const varName = ctx.getInternalVariable(); | ||
const componentInstanceVar = ctx.getInternalVariable(); | ||
ctx.currentComponent.used = true; | ||
yield `var ${varName} = {} as (Parameters<NonNullable<typeof ${var_defineComponentCtx}['expose']>>[0] | null)`; | ||
if (node.codegenNode?.type === CompilerDOM.NodeTypes.VNODE_CALL | ||
&& node.codegenNode.props?.type === CompilerDOM.NodeTypes.JS_OBJECT_EXPRESSION | ||
&& node.codegenNode.props.properties.some(({ key }) => key.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && key.content === 'ref_for')) { | ||
yield `var ${componentInstanceVar} = {} as (Parameters<NonNullable<typeof ${componentCtxVar}['expose']>>[0] | null)`; | ||
if (isVForChild) { | ||
yield `[]`; | ||
} | ||
yield `${utils_1.endOfLine}`; | ||
if (refName) { | ||
ctx.templateRefs.set(refName, [varName, offset]); | ||
if (refName && offset) { | ||
ctx.templateRefs.set(refName, { | ||
typeExp: `typeof ${ctx.getHoistVariable(componentInstanceVar)}`, | ||
offset | ||
}); | ||
} | ||
if (isRootNode) { | ||
ctx.singleRootElType = `NonNullable<typeof ${varName}>['$el']`; | ||
ctx.singleRootElTypes.push(`NonNullable<typeof ${componentInstanceVar}>['$el']`); | ||
} | ||
} | ||
const usedComponentEventsVar = yield* (0, elementEvents_1.generateElementEvents)(options, ctx, node, var_functionalComponent, var_componentInstance, var_componentEvents); | ||
if (usedComponentEventsVar) { | ||
ctx.currentComponent.used = true; | ||
yield `let ${var_componentEmit}!: typeof ${var_defineComponentCtx}.emit${utils_1.endOfLine}`; | ||
yield `let ${var_componentEvents}!: __VLS_NormalizeEmits<typeof ${var_componentEmit}>${utils_1.endOfLine}`; | ||
} | ||
if (hasVBindAttrs(options, ctx, node)) { | ||
const attrsVar = ctx.getInternalVariable(); | ||
yield `let ${attrsVar}!: Parameters<typeof ${componentFunctionalVar}>[0]${utils_1.endOfLine}`; | ||
ctx.inheritedAttrVars.add(attrsVar); | ||
yield `let ${attrsVar}!: Parameters<typeof ${var_functionalComponent}>[0];\n`; | ||
} | ||
(0, styleScopedClasses_1.collectStyleScopedClassReferences)(options, ctx, node); | ||
const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot'); | ||
@@ -220,6 +217,8 @@ if (slotDir) { | ||
else { | ||
yield* (0, elementChildren_1.generateElementChildren)(options, ctx, node, true); | ||
// #932: reference for default slot | ||
yield* (0, vSlot_1.generateImplicitDefaultSlot)(ctx, node); | ||
yield* (0, elementChildren_1.generateElementChildren)(options, ctx, node); | ||
} | ||
if (ctx.currentComponent.used) { | ||
yield `var ${var_defineComponentCtx}!: __VLS_PickFunctionalComponentCtx<typeof ${var_originalComponent}, typeof ${var_componentInstance}>${utils_1.endOfLine}`; | ||
yield `var ${componentCtxVar}!: __VLS_PickFunctionalComponentCtx<typeof ${componentOriginalVar}, typeof ${componentVNodeVar}>${utils_1.endOfLine}`; | ||
} | ||
@@ -243,12 +242,16 @@ } | ||
yield* generateFailedPropExps(options, ctx, failedPropExps); | ||
const [refName, offset] = yield* generateVScope(options, ctx, node, node.props); | ||
if (refName) { | ||
let refValue = `__VLS_nativeElements['${node.tag}']`; | ||
yield* (0, elementDirectives_1.generateElementDirectives)(options, ctx, node); | ||
const [refName, offset] = yield* generateElementReference(options, ctx, node); | ||
if (refName && offset) { | ||
let typeExp = `__VLS_NativeElements['${node.tag}']`; | ||
if (isVForChild) { | ||
refValue = `[${refValue}]`; | ||
typeExp += `[]`; | ||
} | ||
ctx.templateRefs.set(refName, [refValue, offset]); | ||
ctx.templateRefs.set(refName, { | ||
typeExp, | ||
offset | ||
}); | ||
} | ||
if (ctx.singleRootNode === node) { | ||
ctx.singleRootElType = `typeof __VLS_nativeElements['${node.tag}']`; | ||
if (ctx.singleRootNodes.has(node)) { | ||
ctx.singleRootElTypes.push(`__VLS_NativeElements['${node.tag}']`); | ||
} | ||
@@ -258,2 +261,3 @@ if (hasVBindAttrs(options, ctx, node)) { | ||
} | ||
(0, styleScopedClasses_1.collectStyleScopedClassReferences)(options, ctx, node); | ||
yield* (0, elementChildren_1.generateElementChildren)(options, ctx, node); | ||
@@ -267,30 +271,2 @@ } | ||
} | ||
function* generateVScope(options, ctx, node, props) { | ||
const vScope = props.find(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE && (prop.name === 'scope' || prop.name === 'data')); | ||
let inScope = false; | ||
let originalConditionsNum = ctx.blockConditions.length; | ||
if (vScope?.type === CompilerDOM.NodeTypes.DIRECTIVE && vScope.exp) { | ||
const scopeVar = ctx.getInternalVariable(); | ||
const condition = `__VLS_withScope(__VLS_ctx, ${scopeVar})`; | ||
yield `const ${scopeVar} = `; | ||
yield [ | ||
vScope.exp.loc.source, | ||
'template', | ||
vScope.exp.loc.start.offset, | ||
ctx.codeFeatures.all, | ||
]; | ||
yield utils_1.endOfLine; | ||
yield `if (${condition}) {${utils_1.newLine}`; | ||
ctx.blockConditions.push(condition); | ||
inScope = true; | ||
} | ||
yield* (0, elementDirectives_1.generateElementDirectives)(options, ctx, node); | ||
const [refName, offset] = yield* generateReferencesForElements(options, ctx, node); // <el ref="foo" /> | ||
(0, styleScopedClasses_1.collectStyleScopedClassReferences)(options, ctx, node); | ||
if (inScope) { | ||
yield `}${utils_1.newLine}`; | ||
ctx.blockConditions.length = originalConditionsNum; | ||
} | ||
return [refName, offset]; | ||
} | ||
function getCanonicalComponentName(tagText) { | ||
@@ -334,3 +310,3 @@ return utils_1.variableNameRegex.test(tagText) | ||
} | ||
function* generateReferencesForElements(options, ctx, node) { | ||
function* generateElementReference(options, ctx, node) { | ||
for (const prop of node.props) { | ||
@@ -341,6 +317,6 @@ if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE | ||
const [content, startOffset] = (0, utils_1.normalizeAttributeValue)(prop.value); | ||
yield `// @ts-ignore navigation for \`const ${content} = ref()\`${utils_1.newLine}`; | ||
yield `/** @type { typeof __VLS_ctx`; | ||
// navigation support for `const foo = ref()` | ||
yield `/** @type {typeof __VLS_ctx`; | ||
yield* (0, propertyAccess_1.generatePropertyAccess)(options, ctx, content, startOffset, ctx.codeFeatures.navigation, prop.value.loc); | ||
yield ` } */${utils_1.endOfLine}`; | ||
yield `} */${utils_1.endOfLine}`; | ||
if (utils_1.variableNameRegex.test(content) && !options.templateRefNames.has(content)) { | ||
@@ -355,3 +331,3 @@ ctx.accessExternalVariable(content, startOffset); | ||
function hasVBindAttrs(options, ctx, node) { | ||
return options.vueCompilerOptions.fallthroughAttributes && (node === ctx.singleRootNode || | ||
return options.vueCompilerOptions.fallthroughAttributes && ((options.inheritAttrs && ctx.singleRootNodes.has(node)) || | ||
node.props.some(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE | ||
@@ -358,0 +334,0 @@ && prop.name === 'bind' |
@@ -5,2 +5,2 @@ import * as CompilerDOM from '@vue/compiler-dom'; | ||
import type { TemplateCodegenOptions } from './index'; | ||
export declare function generateElementChildren(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, isDefaultSlot?: boolean): Generator<Code>; | ||
export declare function generateElementChildren(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateElementChildren = generateElementChildren; | ||
const CompilerDOM = require("@vue/compiler-dom"); | ||
const utils_1 = require("../utils"); | ||
const templateChild_1 = require("./templateChild"); | ||
function* generateElementChildren(options, ctx, node, isDefaultSlot = false) { | ||
function* generateElementChildren(options, ctx, node) { | ||
yield* ctx.resetDirectiveComments('end of element children start'); | ||
@@ -15,13 +13,3 @@ let prev; | ||
yield* ctx.generateAutoImportCompletion(); | ||
// fix https://github.com/vuejs/language-tools/issues/932 | ||
if (ctx.currentComponent | ||
&& isDefaultSlot | ||
&& node.children.length | ||
&& node.tagType === CompilerDOM.ElementTypes.COMPONENT) { | ||
ctx.currentComponent.used = true; | ||
yield `${ctx.currentComponent.ctxVar}.slots!.`; | ||
yield* (0, utils_1.wrapWith)(node.children[0].loc.start.offset, node.children[node.children.length - 1].loc.end.offset, ctx.codeFeatures.navigation, `default`); | ||
yield utils_1.endOfLine; | ||
} | ||
} | ||
//# sourceMappingURL=elementChildren.js.map |
@@ -12,2 +12,3 @@ "use strict"; | ||
const stringLiteralKey_1 = require("../utils/stringLiteralKey"); | ||
const elementProps_1 = require("./elementProps"); | ||
const interpolation_1 = require("./interpolation"); | ||
@@ -90,3 +91,3 @@ const objectProperty_1 = require("./objectProperty"); | ||
yield `: `; | ||
yield* (0, utils_1.wrapWith)(exp.loc.start.offset, exp.loc.end.offset, ctx.codeFeatures.verification, ...(0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, exp.content, exp.loc.start.offset, exp.loc, `(`, `)`)); | ||
yield* (0, elementProps_1.generatePropExp)(options, ctx, prop, exp, ctx.codeFeatures.all); | ||
} | ||
@@ -93,0 +94,0 @@ function getPropRenameApply(oldName) { |
@@ -6,5 +6,5 @@ import * as CompilerDOM from '@vue/compiler-dom'; | ||
import type { TemplateCodegenOptions } from './index'; | ||
export declare function generateElementEvents(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, componentVar: string, componentInstanceVar: string, eventsVar: string): Generator<Code, boolean>; | ||
export declare function generateElementEvents(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, componentFunctionalVar: string, componentVNodeVar: string, componentCtxVar: string): Generator<Code>; | ||
export declare function generateEventArg(ctx: TemplateCodegenContext, name: string, start: number, directive?: string): Generator<Code>; | ||
export declare function generateEventExpression(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode): Generator<Code>; | ||
export declare function isCompoundExpression(ts: typeof import('typescript'), ast: ts.SourceFile): boolean; |
@@ -12,4 +12,5 @@ "use strict"; | ||
const interpolation_1 = require("./interpolation"); | ||
function* generateElementEvents(options, ctx, node, componentVar, componentInstanceVar, eventsVar) { | ||
let usedComponentEventsVar = false; | ||
function* generateElementEvents(options, ctx, node, componentFunctionalVar, componentVNodeVar, componentCtxVar) { | ||
let emitVar; | ||
let eventsVar; | ||
let propsVar; | ||
@@ -22,6 +23,10 @@ for (const prop of node.props) { | ||
&& !prop.arg.loc.source.endsWith(']')) { | ||
usedComponentEventsVar = true; | ||
if (!propsVar) { | ||
ctx.currentComponent.used = true; | ||
if (!emitVar) { | ||
emitVar = ctx.getInternalVariable(); | ||
eventsVar = ctx.getInternalVariable(); | ||
propsVar = ctx.getInternalVariable(); | ||
yield `let ${propsVar}!: __VLS_FunctionalComponentProps<typeof ${componentVar}, typeof ${componentInstanceVar}>${utils_1.endOfLine}`; | ||
yield `let ${emitVar}!: typeof ${componentCtxVar}.emit${utils_1.endOfLine}`; | ||
yield `let ${eventsVar}!: __VLS_NormalizeEmits<typeof ${emitVar}>${utils_1.endOfLine}`; | ||
yield `let ${propsVar}!: __VLS_FunctionalComponentProps<typeof ${componentFunctionalVar}, typeof ${componentVNodeVar}>${utils_1.endOfLine}`; | ||
} | ||
@@ -45,3 +50,2 @@ let source = prop.arg.loc.source; | ||
} | ||
return usedComponentEventsVar; | ||
} | ||
@@ -64,4 +68,4 @@ function* generateEventArg(ctx, name, start, directive = 'on') { | ||
if (prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { | ||
let prefix = '('; | ||
let suffix = ')'; | ||
let prefix = `(`; | ||
let suffix = `)`; | ||
let isFirstMapping = true; | ||
@@ -73,6 +77,6 @@ const ast = (0, utils_1.createTsAst)(options.ts, prop.exp, prop.exp.content); | ||
ctx.addLocalVariable('$event'); | ||
prefix = ''; | ||
suffix = ''; | ||
prefix = ``; | ||
suffix = ``; | ||
for (const blockCondition of ctx.blockConditions) { | ||
prefix += `if (!(${blockCondition})) return${utils_1.endOfLine}`; | ||
prefix += `if (!${blockCondition}) return${utils_1.endOfLine}`; | ||
} | ||
@@ -79,0 +83,0 @@ } |
@@ -11,2 +11,2 @@ import * as CompilerDOM from '@vue/compiler-dom'; | ||
export declare function generateElementProps(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, props: CompilerDOM.ElementNode['props'], strictPropsCheck: boolean, enableCodeFeatures: boolean, failedPropExps?: FailedPropExpression[]): Generator<Code>; | ||
export declare function generatePropExp(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode, exp: CompilerDOM.SimpleExpressionNode | undefined, features: VueCodeInformation, enableCodeFeatures: boolean): Generator<Code>; | ||
export declare function generatePropExp(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, prop: CompilerDOM.DirectiveNode, exp: CompilerDOM.SimpleExpressionNode | undefined, features: VueCodeInformation, enableCodeFeatures?: boolean): Generator<Code>; |
@@ -43,8 +43,8 @@ "use strict"; | ||
&& prop.arg.loc.source.endsWith(']')) { | ||
failedPropExps?.push({ node: prop.arg, prefix: '(', suffix: ')' }); | ||
failedPropExps?.push({ node: prop.exp, prefix: '() => {', suffix: '}' }); | ||
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: ')' }); | ||
failedPropExps?.push({ node: prop.exp, prefix: `(`, suffix: `)` }); | ||
} | ||
@@ -70,3 +70,3 @@ } | ||
if (prop.exp && prop.exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY) { | ||
failedPropExps?.push({ node: prop.exp, prefix: '(', suffix: ')' }); | ||
failedPropExps?.push({ node: prop.exp, prefix: `(`, suffix: `)` }); | ||
} | ||
@@ -87,3 +87,3 @@ continue; | ||
? (0, objectProperty_1.generateObjectProperty)(options, ctx, propName, prop.arg.loc.start.offset, codeInfo, prop.loc.name_2 ??= {}, shouldCamelize) | ||
: (0, utils_1.wrapWith)(prop.loc.start.offset, prop.loc.start.offset + 'v-model'.length, ctx.codeFeatures.verification, propName)), `: (`, ...generatePropExp(options, ctx, prop, prop.exp, ctx.codeFeatures.all, enableCodeFeatures), `)`); | ||
: (0, utils_1.wrapWith)(prop.loc.start.offset, prop.loc.start.offset + 'v-model'.length, ctx.codeFeatures.verification, propName)), `: `, ...generatePropExp(options, ctx, prop, prop.exp, ctx.codeFeatures.all, enableCodeFeatures)); | ||
if (enableCodeFeatures) { | ||
@@ -129,5 +129,5 @@ yield* codes; | ||
} | ||
const codes = (0, utils_1.wrapWith)(prop.loc.start.offset, prop.loc.end.offset, ctx.codeFeatures.verification, ...(0, objectProperty_1.generateObjectProperty)(options, ctx, prop.name, prop.loc.start.offset, codeInfo, prop.loc.name_1 ??= {}, shouldCamelize), `: (`, ...(prop.value | ||
const codes = (0, utils_1.wrapWith)(prop.loc.start.offset, prop.loc.end.offset, ctx.codeFeatures.verification, ...(0, objectProperty_1.generateObjectProperty)(options, ctx, prop.name, prop.loc.start.offset, codeInfo, prop.loc.name_1 ??= {}, shouldCamelize), `: `, ...(prop.value | ||
? generateAttrValue(prop.value, ctx.codeFeatures.withoutNavigation) | ||
: [`true`]), `)`); | ||
: [`true`])); | ||
if (enableCodeFeatures) { | ||
@@ -166,3 +166,3 @@ yield* codes; | ||
} | ||
function* generatePropExp(options, ctx, prop, exp, features, enableCodeFeatures) { | ||
function* generatePropExp(options, ctx, prop, exp, features, enableCodeFeatures = true) { | ||
const isShorthand = prop.arg?.loc.start.offset === prop.exp?.loc.start.offset; | ||
@@ -177,3 +177,3 @@ if (isShorthand && features.completion) { | ||
if (!isShorthand) { // vue 3.4+ | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', features, exp.loc.source, exp.loc.start.offset, exp.loc, '(', ')'); | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', features, exp.loc.source, exp.loc.start.offset, exp.loc, `(`, `)`); | ||
} | ||
@@ -240,2 +240,4 @@ else { | ||
shouldReport(_source, code) { | ||
// https://typescript.tv/errors/#ts2353 | ||
// https://typescript.tv/errors/#ts2561 | ||
if (String(code) === '2353' || String(code) === '2561') { | ||
@@ -242,0 +244,0 @@ return false; |
@@ -21,6 +21,14 @@ "use strict"; | ||
const slotsPropertyName = (0, shared_1.getSlotsPropertyName)(options.vueCompilerOptions.target); | ||
ctx.specialVars.add(slotsPropertyName); | ||
ctx.specialVars.add('$attrs'); | ||
ctx.specialVars.add('$refs'); | ||
ctx.specialVars.add('$el'); | ||
if (options.vueCompilerOptions.inferTemplateDollarSlots) { | ||
ctx.dollarVars.add(slotsPropertyName); | ||
} | ||
if (options.vueCompilerOptions.inferTemplateDollarAttrs) { | ||
ctx.dollarVars.add('$attrs'); | ||
} | ||
if (options.vueCompilerOptions.inferTemplateDollarRefs) { | ||
ctx.dollarVars.add('$refs'); | ||
} | ||
if (options.vueCompilerOptions.inferTemplateDollarEl) { | ||
ctx.dollarVars.add('$el'); | ||
} | ||
if (options.template.ast) { | ||
@@ -30,2 +38,4 @@ yield* (0, templateChild_1.generateTemplateChild)(options, ctx, options.template.ast, undefined); | ||
yield* (0, styleScopedClasses_1.generateStyleScopedClassReferences)(ctx); | ||
yield* ctx.generateAutoImportCompletion(); | ||
yield* ctx.generateHoistVariables(); | ||
const speicalTypes = [ | ||
@@ -37,8 +47,7 @@ [slotsPropertyName, yield* generateSlots(options, ctx)], | ||
]; | ||
yield `var __VLS_special!: {${utils_1.newLine}`; | ||
yield `var __VLS_dollars!: {${utils_1.newLine}`; | ||
for (const [name, type] of speicalTypes) { | ||
yield `${name}: ${type}${utils_1.endOfLine}`; | ||
} | ||
yield `} & { [K in keyof typeof __VLS_ctx]: unknown }${utils_1.endOfLine}`; | ||
yield* ctx.generateAutoImportCompletion(); | ||
yield `} & { [K in keyof import('${options.vueCompilerOptions.lib}').ComponentPublicInstance]: unknown }${utils_1.endOfLine}`; | ||
return ctx; | ||
@@ -51,3 +60,2 @@ } | ||
for (const { expVar, propsVar } of ctx.dynamicSlots) { | ||
ctx.hasSlot = true; | ||
yield `${utils_1.newLine}& { [K in NonNullable<typeof ${expVar}>]?: (props: typeof ${propsVar}) => any }`; | ||
@@ -57,3 +65,2 @@ } | ||
yield `${utils_1.newLine}& { `; | ||
ctx.hasSlot = true; | ||
if (slot.name && slot.offset !== undefined) { | ||
@@ -80,3 +87,3 @@ yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, slot.name, slot.offset, ctx.codeFeatures.withoutHighlightAndCompletion, slot.nodeLoc); | ||
for (const loc of ctx.bindingAttrLocs) { | ||
yield `__VLS_special.`; | ||
yield `__VLS_dollars.`; | ||
yield [ | ||
@@ -96,5 +103,5 @@ loc.source, | ||
yield `type __VLS_TemplateRefs = {${utils_1.newLine}`; | ||
for (const [name, [varName, offset]] of ctx.templateRefs) { | ||
for (const [name, { typeExp, offset }] of ctx.templateRefs) { | ||
yield* (0, objectProperty_1.generateObjectProperty)(options, ctx, name, offset, ctx.codeFeatures.navigationAndCompletion); | ||
yield `: typeof ${varName},${utils_1.newLine}`; | ||
yield `: ${typeExp},${utils_1.newLine}`; | ||
} | ||
@@ -106,3 +113,10 @@ yield `}${utils_1.endOfLine}`; | ||
yield `type __VLS_RootEl = `; | ||
yield ctx.singleRootElType ?? `any`; | ||
if (ctx.singleRootElTypes.length && !ctx.singleRootNodes.has(null)) { | ||
for (const type of ctx.singleRootElTypes) { | ||
yield `${utils_1.newLine}| ${type}`; | ||
} | ||
} | ||
else { | ||
yield `any`; | ||
} | ||
yield utils_1.endOfLine; | ||
@@ -109,0 +123,0 @@ return `__VLS_RootEl`; |
@@ -90,3 +90,3 @@ "use strict"; | ||
const nextVar = ctxVars[i + 1]; | ||
yield* generateVar(code, ctx.specialVars, destructuredPropNames, templateRefNames, curVar); | ||
yield* generateVar(code, ctx.dollarVars, destructuredPropNames, templateRefNames, curVar); | ||
if (nextVar.isShorthand) { | ||
@@ -101,3 +101,3 @@ yield [code.slice(curVar.offset + curVar.text.length, nextVar.offset + nextVar.text.length), curVar.offset + curVar.text.length]; | ||
const lastVar = ctxVars.at(-1); | ||
yield* generateVar(code, ctx.specialVars, destructuredPropNames, templateRefNames, lastVar); | ||
yield* generateVar(code, ctx.dollarVars, destructuredPropNames, templateRefNames, lastVar); | ||
if (lastVar.offset + lastVar.text.length < code.length) { | ||
@@ -111,3 +111,3 @@ yield [code.slice(lastVar.offset + lastVar.text.length), lastVar.offset + lastVar.text.length, 'endText']; | ||
} | ||
function* generateVar(code, specialVars, destructuredPropNames, templateRefNames, curVar) { | ||
function* generateVar(code, dollarVars, destructuredPropNames, templateRefNames, curVar) { | ||
// fix https://github.com/vuejs/language-tools/issues/1205 | ||
@@ -124,4 +124,4 @@ // fix https://github.com/vuejs/language-tools/issues/1264 | ||
else { | ||
if (specialVars.has(curVar.text)) { | ||
yield [`__VLS_special.`, undefined]; | ||
if (dollarVars.has(curVar.text)) { | ||
yield [`__VLS_dollars.`, undefined]; | ||
} | ||
@@ -128,0 +128,0 @@ else if (!isDestructuredProp) { |
@@ -13,2 +13,3 @@ "use strict"; | ||
const startTagOffset = node.loc.start.offset + options.template.content.slice(node.loc.start.offset).indexOf(node.tag); | ||
const startTagEndOffset = startTagOffset + node.tag.length; | ||
const propsVar = ctx.getInternalVariable(); | ||
@@ -26,3 +27,3 @@ const nameProp = node.props.find(prop => { | ||
if (options.hasDefineSlots) { | ||
yield `__VLS_normalizeSlot(`; | ||
yield `__VLS_asFunctionalSlot(`; | ||
if (nameProp) { | ||
@@ -42,3 +43,3 @@ let codes; | ||
`[`, | ||
...(0, elementProps_1.generatePropExp)(options, ctx, nameProp, nameProp.exp, ctx.codeFeatures.all, true), | ||
...(0, elementProps_1.generatePropExp)(options, ctx, nameProp, nameProp.exp, ctx.codeFeatures.all), | ||
`]` | ||
@@ -53,6 +54,6 @@ ]; | ||
else { | ||
yield* (0, utils_1.wrapWith)(node.loc.start.offset, node.loc.end.offset, ctx.codeFeatures.verification, `${options.slotsAssignName ?? '__VLS_slots'}['default']`); | ||
yield* (0, utils_1.wrapWith)(startTagOffset, startTagEndOffset, ctx.codeFeatures.verification, `${options.slotsAssignName ?? '__VLS_slots'}[`, ...(0, utils_1.wrapWith)(startTagOffset, startTagEndOffset, ctx.codeFeatures.verification, `'default'`), `]`); | ||
} | ||
yield `)?.(`; | ||
yield* (0, utils_1.wrapWith)(startTagOffset, startTagOffset + node.tag.length, ctx.codeFeatures.verification, `{${utils_1.newLine}`, ...(0, elementProps_1.generateElementProps)(options, ctx, node, node.props.filter(prop => prop !== nameProp), true, true), `}`); | ||
yield `)(`; | ||
yield* (0, utils_1.wrapWith)(startTagOffset, startTagEndOffset, ctx.codeFeatures.verification, `{${utils_1.newLine}`, ...(0, elementProps_1.generateElementProps)(options, ctx, node, node.props.filter(prop => prop !== nameProp), true, true), `}`); | ||
yield `)${utils_1.endOfLine}`; | ||
@@ -71,3 +72,3 @@ } | ||
nodeLoc: node.loc, | ||
propsVar, | ||
propsVar: ctx.getHoistVariable(propsVar), | ||
}); | ||
@@ -86,4 +87,4 @@ } | ||
ctx.dynamicSlots.push({ | ||
expVar, | ||
propsVar, | ||
expVar: ctx.getHoistVariable(expVar), | ||
propsVar: ctx.getHoistVariable(propsVar), | ||
}); | ||
@@ -94,5 +95,5 @@ } | ||
name: 'default', | ||
tagRange: [startTagOffset, startTagOffset + node.tag.length], | ||
tagRange: [startTagOffset, startTagEndOffset], | ||
nodeLoc: node.loc, | ||
propsVar, | ||
propsVar: ctx.getHoistVariable(propsVar), | ||
}); | ||
@@ -99,0 +100,0 @@ } |
@@ -9,8 +9,4 @@ "use strict"; | ||
function* generateStyleScopedClassReferences(ctx, withDot = false) { | ||
if (!ctx.emptyClassOffsets.length && !ctx.scopedClasses.length) { | ||
return; | ||
} | ||
yield `[`; | ||
for (const offset of ctx.emptyClassOffsets) { | ||
yield `'`; | ||
yield `/** @type {__VLS_StyleScopedClasses['`; | ||
yield [ | ||
@@ -22,5 +18,6 @@ '', | ||
]; | ||
yield `', `; | ||
yield `']} */${utils_1.endOfLine}`; | ||
} | ||
for (const { source, className, offset } of ctx.scopedClasses) { | ||
yield `/** @type {__VLS_StyleScopedClasses[`; | ||
yield [ | ||
@@ -40,7 +37,6 @@ '', | ||
offset + className.length, | ||
ctx.codeFeatures.navigationWithoutRename, | ||
ctx.codeFeatures.navigation, | ||
]; | ||
yield `, `; | ||
yield `]} */${utils_1.endOfLine}`; | ||
} | ||
yield `] as (keyof __VLS_StyleScopedClasses)[]${utils_1.endOfLine}`; | ||
function* escapeString(source, className, offset, escapeTargets) { | ||
@@ -47,0 +43,0 @@ let count = 0; |
@@ -7,2 +7,3 @@ "use strict"; | ||
const CompilerDOM = require("@vue/compiler-dom"); | ||
const shared_1 = require("../../utils/shared"); | ||
const utils_1 = require("../utils"); | ||
@@ -15,2 +16,3 @@ const element_1 = require("./element"); | ||
const vSlot_1 = require("./vSlot"); | ||
const commentDirectiveRegex = /^<!--\s*@vue-(?<name>[-\w]+)\b(?<content>[\s\S]*)-->$/; | ||
// @ts-ignore | ||
@@ -33,25 +35,31 @@ const transformContext = { | ||
if (prevNode?.type === CompilerDOM.NodeTypes.COMMENT) { | ||
const commentText = prevNode.content.trim().split(' ')[0]; | ||
if (/^@vue-skip\b[\s\S]*/.test(commentText)) { | ||
yield `// @vue-skip${utils_1.newLine}`; | ||
return; | ||
} | ||
else if (/^@vue-ignore\b[\s\S]*/.test(commentText)) { | ||
yield* ctx.ignoreError(); | ||
} | ||
else if (/^@vue-expect-error\b[\s\S]*/.test(commentText)) { | ||
yield* ctx.expectError(prevNode); | ||
} | ||
else { | ||
const match = prevNode.loc.source.match(/^<!--\s*@vue-generic\b\s*\{(?<content>[^}]*)\}/); | ||
if (match) { | ||
const { content } = match.groups ?? {}; | ||
ctx.lastGenericComment = { | ||
content, | ||
offset: prevNode.loc.start.offset + match[0].indexOf(content) | ||
}; | ||
const match = prevNode.loc.source.match(commentDirectiveRegex); | ||
if (match) { | ||
const { name, content } = match.groups; | ||
switch (name) { | ||
case 'skip': { | ||
yield `// @vue-skip${utils_1.newLine}`; | ||
return; | ||
} | ||
case 'ignore': { | ||
yield* ctx.ignoreError(); | ||
break; | ||
} | ||
case 'expect-error': { | ||
yield* ctx.expectError(prevNode); | ||
break; | ||
} | ||
case 'generic': { | ||
const text = content.trim(); | ||
if (text.startsWith('{') && text.endsWith('}')) { | ||
ctx.lastGenericComment = { | ||
content: text.slice(1, -1), | ||
offset: prevNode.loc.start.offset + prevNode.loc.source.indexOf('{') + 1, | ||
}; | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
const shouldInheritRootNodeAttrs = options.inheritAttrs; | ||
const cur = node; | ||
@@ -62,6 +70,6 @@ if (cur.codegenNode?.type === CompilerDOM.NodeTypes.JS_CACHE_EXPRESSION) { | ||
if (node.type === CompilerDOM.NodeTypes.ROOT) { | ||
for (const item of collectSingleRootNodes(options, node.children)) { | ||
ctx.singleRootNodes.add(item); | ||
} | ||
let prev; | ||
if (shouldInheritRootNodeAttrs && node.children.length === 1 && node.children[0].type === CompilerDOM.NodeTypes.ELEMENT) { | ||
ctx.singleRootNode = node.children[0]; | ||
} | ||
for (const childNode of node.children) { | ||
@@ -98,3 +106,3 @@ yield* generateTemplateChild(options, ctx, childNode, prev); | ||
const { currentComponent } = ctx; | ||
yield* (0, element_1.generateComponent)(options, ctx, node); | ||
yield* (0, element_1.generateComponent)(options, ctx, node, isVForChild); | ||
ctx.currentComponent = currentComponent; | ||
@@ -134,2 +142,26 @@ } | ||
} | ||
function* collectSingleRootNodes(options, children) { | ||
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); | ||
} | ||
return; | ||
} | ||
else if (child.type !== CompilerDOM.NodeTypes.ELEMENT) { | ||
return; | ||
} | ||
yield child; | ||
const tag = (0, shared_1.hyphenateTag)(child.tag); | ||
if (options.vueCompilerOptions.fallthroughComponentNames.includes(tag)) { | ||
yield* collectSingleRootNodes(options, child.children); | ||
} | ||
} | ||
// TODO: track https://github.com/vuejs/vue-next/issues/3498 | ||
@@ -155,7 +187,7 @@ function getVForNode(node) { | ||
function getVIfNode(node) { | ||
const forDirective = node.props.find((prop) => prop.type === CompilerDOM.NodeTypes.DIRECTIVE | ||
const ifDirective = node.props.find((prop) => prop.type === CompilerDOM.NodeTypes.DIRECTIVE | ||
&& prop.name === 'if'); | ||
if (forDirective) { | ||
if (ifDirective) { | ||
let ifNode; | ||
CompilerDOM.processIf(node, forDirective, transformContext, _ifNode => { | ||
CompilerDOM.processIf(node, ifDirective, transformContext, _ifNode => { | ||
ifNode = { ..._ifNode }; | ||
@@ -168,3 +200,3 @@ return undefined; | ||
...node, | ||
props: node.props.filter(prop => prop !== forDirective), | ||
props: node.props.filter(prop => prop !== ifDirective), | ||
}]; | ||
@@ -171,0 +203,0 @@ } |
@@ -27,3 +27,3 @@ "use strict"; | ||
yield `__VLS_getVForSourceType(`; | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, source.content, source.loc.start.offset, source.loc, '(', ')'); | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, source.content, source.loc.start.offset, source.loc, `(`, `)`); | ||
yield `!)`; // #3102 | ||
@@ -50,3 +50,3 @@ } | ||
&& !prop.value.isStatic) { | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, prop.value.content, prop.value.loc.start.offset, prop.value.loc, '(', ')'); | ||
yield* (0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, prop.value.content, prop.value.loc.start.offset, prop.value.loc, `(`, `)`); | ||
yield utils_1.endOfLine; | ||
@@ -53,0 +53,0 @@ } |
@@ -10,3 +10,3 @@ "use strict"; | ||
function* generateVIf(options, ctx, node) { | ||
let originalBlockConditionsLength = ctx.blockConditions.length; | ||
const originalBlockConditionsLength = ctx.blockConditions.length; | ||
for (let i = 0; i < node.branches.length; i++) { | ||
@@ -26,3 +26,3 @@ const branch = node.branches[i]; | ||
const codes = [ | ||
...(0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, branch.condition.content, branch.condition.loc.start.offset, branch.condition.loc, '(', ')'), | ||
...(0, interpolation_1.generateInterpolation)(options, ctx, 'template', ctx.codeFeatures.all, branch.condition.content, branch.condition.loc.start.offset, branch.condition.loc, `(`, `)`), | ||
]; | ||
@@ -48,3 +48,3 @@ for (const code of codes) { | ||
if (addedBlockCondition) { | ||
ctx.blockConditions[ctx.blockConditions.length - 1] = `!(${ctx.blockConditions[ctx.blockConditions.length - 1]})`; | ||
ctx.blockConditions[ctx.blockConditions.length - 1] = `!${ctx.blockConditions[ctx.blockConditions.length - 1]}`; | ||
} | ||
@@ -51,0 +51,0 @@ } |
@@ -6,1 +6,2 @@ import * as CompilerDOM from '@vue/compiler-dom'; | ||
export declare function generateVSlot(options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode, slotDir: CompilerDOM.DirectiveNode): Generator<Code>; | ||
export declare function generateImplicitDefaultSlot(ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode): Generator<Code, void, any>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateVSlot = generateVSlot; | ||
exports.generateImplicitDefaultSlot = generateImplicitDefaultSlot; | ||
const CompilerDOM = require("@vue/compiler-dom"); | ||
@@ -80,2 +81,13 @@ const utils_1 = require("../utils"); | ||
} | ||
function* generateImplicitDefaultSlot(ctx, node) { | ||
if (!ctx.currentComponent) { | ||
return; | ||
} | ||
if (node.children.length) { | ||
ctx.currentComponent.used = true; | ||
yield `${ctx.currentComponent.ctxVar}.slots!.`; | ||
yield* (0, utils_1.wrapWith)(node.children[0].loc.start.offset, node.children[node.children.length - 1].loc.end.offset, ctx.codeFeatures.navigation, `default`); | ||
yield utils_1.endOfLine; | ||
} | ||
} | ||
//# sourceMappingURL=vSlot.js.map |
import * as CompilerDOM from '@vue/compiler-dom'; | ||
import type * as ts from 'typescript'; | ||
import type { Code, SfcBlock, VueCodeInformation } from '../../types'; | ||
import type { Code, SfcBlock, SfcBlockAttr, VueCodeInformation } from '../../types'; | ||
export declare const newLine = "\n"; | ||
@@ -22,1 +22,2 @@ export declare const endOfLine = ";\n"; | ||
export declare function generateSfcBlockSection(block: SfcBlock, start: number, end: number, features: VueCodeInformation): Code; | ||
export declare function generateSfcBlockAttrValue(src: SfcBlockAttr & object, text: string, features: VueCodeInformation): Generator<Code>; |
@@ -10,6 +10,7 @@ "use strict"; | ||
exports.generateSfcBlockSection = generateSfcBlockSection; | ||
exports.generateSfcBlockAttrValue = generateSfcBlockAttrValue; | ||
const scriptSetupRanges_1 = require("../../parsers/scriptSetupRanges"); | ||
exports.newLine = `\n`; | ||
exports.endOfLine = `;${exports.newLine}`; | ||
exports.combineLastMapping = { __combineLastMapping: true }; | ||
exports.combineLastMapping = { __combineOffset: 1 }; | ||
exports.variableNameRegex = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/; | ||
@@ -25,3 +26,3 @@ function* wrapWith(startOffset, endOffset, features, ...wrapCodes) { | ||
} | ||
yield ['', 'template', endOffset, { __combineOffsetMapping: offset }]; | ||
yield ['', 'template', endOffset, { __combineOffset: offset }]; | ||
} | ||
@@ -81,2 +82,17 @@ function collectVars(ts, node, ast, results = []) { | ||
} | ||
function* generateSfcBlockAttrValue(src, text, features) { | ||
const { offset, quotes } = src; | ||
if (!quotes) { | ||
yield [``, 'main', offset, { verification: true }]; | ||
} | ||
yield [ | ||
`'${text}'`, | ||
'main', | ||
quotes ? offset - 1 : offset, | ||
features | ||
]; | ||
if (!quotes) { | ||
yield [``, 'main', offset + text.length, { __combineOffset: 2 }]; | ||
} | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -199,23 +199,18 @@ "use strict"; | ||
defineProps = { | ||
...parseCallExpression(node), | ||
...parseCallExpressionAssignment(node, parent), | ||
statement: getStatementRange(ts, parents, node, ast), | ||
argNode: node.arguments[0] | ||
}; | ||
if (ts.isVariableDeclaration(parent)) { | ||
if (ts.isObjectBindingPattern(parent.name)) { | ||
defineProps.destructured = new Map(); | ||
const identifiers = (0, utils_1.collectIdentifiers)(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); | ||
} | ||
if (ts.isVariableDeclaration(parent) && ts.isObjectBindingPattern(parent.name)) { | ||
defineProps.destructured = new Map(); | ||
const identifiers = (0, utils_1.collectIdentifiers)(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 { | ||
defineProps.name = _getNodeText(parent.name); | ||
} | ||
} | ||
@@ -241,8 +236,5 @@ else if (ts.isCallExpression(parent) | ||
defineEmits = { | ||
...parseCallExpression(node), | ||
...parseCallExpressionAssignment(node, parent), | ||
statement: getStatementRange(ts, parents, node, ast) | ||
}; | ||
if (ts.isVariableDeclaration(parent)) { | ||
defineEmits.name = _getNodeText(parent.name); | ||
} | ||
if (node.typeArguments?.length && ts.isTypeLiteralNode(node.typeArguments[0])) { | ||
@@ -262,8 +254,5 @@ for (const member of node.typeArguments[0].members) { | ||
defineSlots = { | ||
...parseCallExpression(node), | ||
...parseCallExpressionAssignment(node, parent), | ||
statement: getStatementRange(ts, parents, node, ast) | ||
}; | ||
if (ts.isVariableDeclaration(parent)) { | ||
defineSlots.name = _getNodeText(parent.name); | ||
} | ||
} | ||
@@ -301,6 +290,3 @@ else if (vueCompilerOptions.macros.defineExpose.includes(callText)) { | ||
&& !node.typeArguments?.length) { | ||
useTemplateRef.push({ | ||
name: ts.isVariableDeclaration(parent) ? _getNodeText(parent.name) : undefined, | ||
...parseCallExpression(node) | ||
}); | ||
useTemplateRef.push(parseCallExpressionAssignment(node, parent)); | ||
} | ||
@@ -325,2 +311,8 @@ } | ||
} | ||
function parseCallExpressionAssignment(node, parent) { | ||
return { | ||
name: ts.isVariableDeclaration(parent) ? _getNodeText(parent.name) : undefined, | ||
...parseCallExpression(node), | ||
}; | ||
} | ||
function _getStartEnd(node) { | ||
@@ -327,0 +319,0 @@ return getStartEnd(ts, node, ast); |
@@ -9,2 +9,3 @@ "use strict"; | ||
const inlineCodeblockReg = /`[^\n`]+?`/g; | ||
const latexBlockReg = /(\${2,})[\s\S]+?\1/g; | ||
const scriptSetupReg = /\\\<[\s\S]+?\>\n?/g; | ||
@@ -35,2 +36,4 @@ const sfcBlockReg = /\<(script|style)\b[\s\S]*?\>([\s\S]*?)\<\/\1\>/g; | ||
.replace(inlineCodeblockReg, match => `\`${' '.repeat(match.length - 2)}\``) | ||
// latex block | ||
.replace(latexBlockReg, (match, quotes) => quotes + ' '.repeat(match.length - quotes.length * 2) + quotes) | ||
// # \<script setup> | ||
@@ -37,0 +40,0 @@ .replace(scriptSetupReg, match => ' '.repeat(match.length)) |
@@ -63,6 +63,6 @@ "use strict"; | ||
if (node.type === CompilerDOM.NodeTypes.COMMENT) { | ||
const match = node.loc.source.match(/^<!--\s*@vue-generic\b\s*\{(?<content>[^}]*)\}/); | ||
const match = node.loc.source.match(/^<!--\s*@vue-generic\s*\{(?<content>[\s\S]*)\}\s*-->$/); | ||
if (match) { | ||
const { content } = match.groups ?? {}; | ||
addFormatCodes(content, node.loc.start.offset + match[0].indexOf(content), formatBrackets.generic); | ||
const { content } = match.groups; | ||
addFormatCodes(content, node.loc.start.offset + node.loc.source.indexOf('{') + 1, formatBrackets.generic); | ||
} | ||
@@ -69,0 +69,0 @@ } |
@@ -172,3 +172,3 @@ import type { Mapping } from '@volar/language-core'; | ||
}[]; | ||
specialVars: Set<string>; | ||
dollarVars: Set<string>; | ||
accessExternalVariables: Map<string, Set<number>>; | ||
@@ -187,6 +187,8 @@ lastGenericComment: { | ||
inlayHints: import("../codegen/inlayHints").InlayHintInfo[]; | ||
hasSlot: boolean; | ||
bindingAttrLocs: import("@vue/compiler-dom").SourceLocation[]; | ||
inheritedAttrVars: Set<string>; | ||
templateRefs: Map<string, [varName: string, offset: number]>; | ||
templateRefs: Map<string, { | ||
typeExp: string; | ||
offset: number; | ||
}>; | ||
currentComponent: { | ||
@@ -196,4 +198,4 @@ ctxVar: string; | ||
} | undefined; | ||
singleRootElType: string | undefined; | ||
singleRootNode: import("@vue/compiler-dom").ElementNode | undefined; | ||
singleRootElTypes: string[]; | ||
singleRootNodes: Set<import("@vue/compiler-dom").ElementNode | null>; | ||
accessExternalVariable(name: string, offset?: number): void; | ||
@@ -204,2 +206,4 @@ hasLocalVariable: (name: string) => boolean; | ||
getInternalVariable: () => string; | ||
getHoistVariable: (originalVar: string) => string; | ||
generateHoistVariables: () => Generator<string, void, unknown>; | ||
ignoreError: () => Generator<Code>; | ||
@@ -206,0 +210,0 @@ expectError: (prevNode: import("@vue/compiler-dom").CommentNode) => Generator<Code>; |
@@ -56,12 +56,12 @@ "use strict"; | ||
exports.default = plugin; | ||
function createTsx(fileName, _sfc, ctx, appendGlobalTypes) { | ||
function createTsx(fileName, sfc, ctx, appendGlobalTypes) { | ||
const ts = ctx.modules.typescript; | ||
const getLang = (0, alien_signals_1.computed)(() => { | ||
return !_sfc.script && !_sfc.scriptSetup ? 'ts' | ||
: _sfc.scriptSetup && _sfc.scriptSetup.lang !== 'js' ? _sfc.scriptSetup.lang | ||
: _sfc.script && _sfc.script.lang !== 'js' ? _sfc.script.lang | ||
return !sfc.script && !sfc.scriptSetup ? 'ts' | ||
: sfc.scriptSetup && sfc.scriptSetup.lang !== 'js' ? sfc.scriptSetup.lang | ||
: sfc.script && sfc.script.lang !== 'js' ? sfc.script.lang | ||
: 'js'; | ||
}); | ||
const getResolvedOptions = (0, alien_signals_1.computed)(() => { | ||
const options = (0, vueCompilerOptions_1.parseVueCompilerOptions)(_sfc.comments); | ||
const options = (0, vueCompilerOptions_1.parseVueCompilerOptions)(sfc.comments); | ||
if (options) { | ||
@@ -74,7 +74,7 @@ const resolver = new ts_1.CompilerOptionsResolver(); | ||
}); | ||
const getScriptRanges = (0, alien_signals_1.computed)(() => _sfc.script | ||
? (0, scriptRanges_1.parseScriptRanges)(ts, _sfc.script.ast, !!_sfc.scriptSetup, false) | ||
const getScriptRanges = (0, alien_signals_1.computed)(() => sfc.script | ||
? (0, scriptRanges_1.parseScriptRanges)(ts, sfc.script.ast, !!sfc.scriptSetup, false) | ||
: undefined); | ||
const getScriptSetupRanges = (0, alien_signals_1.computed)(() => _sfc.scriptSetup | ||
? (0, scriptSetupRanges_1.parseScriptSetupRanges)(ts, _sfc.scriptSetup.ast, getResolvedOptions()) | ||
const getScriptSetupRanges = (0, alien_signals_1.computed)(() => sfc.scriptSetup | ||
? (0, scriptSetupRanges_1.parseScriptSetupRanges)(ts, sfc.scriptSetup.ast, getResolvedOptions()) | ||
: undefined); | ||
@@ -84,5 +84,5 @@ const getSetupBindingNames = (0, signals_1.computedSet)((0, alien_signals_1.computed)(() => { | ||
const bindings = getScriptSetupRanges()?.bindings; | ||
if (_sfc.scriptSetup && bindings) { | ||
if (sfc.scriptSetup && bindings) { | ||
for (const { range } of bindings) { | ||
newNames.add(_sfc.scriptSetup.content.slice(range.start, range.end)); | ||
newNames.add(sfc.scriptSetup.content.slice(range.start, range.end)); | ||
} | ||
@@ -95,3 +95,3 @@ } | ||
const bindings = getScriptSetupRanges()?.bindings; | ||
if (_sfc.scriptSetup && bindings) { | ||
if (sfc.scriptSetup && bindings) { | ||
for (const { range, moduleName, isDefaultImport, isNamespace } of bindings) { | ||
@@ -102,3 +102,3 @@ if (moduleName | ||
&& ctx.vueCompilerOptions.extensions.some(ext => moduleName.endsWith(ext))) { | ||
newNames.add(_sfc.scriptSetup.content.slice(range.start, range.end)); | ||
newNames.add(sfc.scriptSetup.content.slice(range.start, range.end)); | ||
} | ||
@@ -132,8 +132,8 @@ } | ||
const { exportDefault } = getScriptRanges() ?? {}; | ||
if (_sfc.script && exportDefault?.nameOption) { | ||
if (sfc.script && exportDefault?.nameOption) { | ||
const { nameOption } = exportDefault; | ||
return _sfc.script.content.slice(nameOption.start + 1, nameOption.end - 1); | ||
return sfc.script.content.slice(nameOption.start + 1, nameOption.end - 1); | ||
} | ||
const { defineOptions } = getScriptSetupRanges() ?? {}; | ||
if (_sfc.scriptSetup && defineOptions?.name) { | ||
if (sfc.scriptSetup && defineOptions?.name) { | ||
return defineOptions.name; | ||
@@ -145,3 +145,3 @@ } | ||
const getGeneratedTemplate = (0, alien_signals_1.computed)(() => { | ||
if (getResolvedOptions().skipTemplateCodegen || !_sfc.template) { | ||
if (getResolvedOptions().skipTemplateCodegen || !sfc.template) { | ||
return; | ||
@@ -154,3 +154,3 @@ } | ||
vueCompilerOptions: getResolvedOptions(), | ||
template: _sfc.template, | ||
template: sfc.template, | ||
edited: getResolvedOptions().__test || (fileEditTimes.get(fileName) ?? 0) >= 2, | ||
@@ -179,5 +179,5 @@ scriptSetupBindingNames: getSetupBindingNames(), | ||
const getGeneratedScript = (0, alien_signals_1.computed)(() => { | ||
const codes = []; | ||
const linkedCodeMappings = []; | ||
let generatedLength = 0; | ||
const codes = []; | ||
const codegen = (0, script_1.generateScript)({ | ||
@@ -187,3 +187,3 @@ ts, | ||
vueCompilerOptions: getResolvedOptions(), | ||
sfc: _sfc, | ||
sfc: sfc, | ||
edited: getResolvedOptions().__test || (fileEditTimes.get(fileName) ?? 0) >= 2, | ||
@@ -190,0 +190,0 @@ fileName, |
@@ -15,4 +15,3 @@ import type { CodeInformation } from '@volar/language-core'; | ||
export interface VueCodeInformation extends CodeInformation { | ||
__combineLastMapping?: boolean; | ||
__combineOffsetMapping?: number; | ||
__combineOffset?: number; | ||
} | ||
@@ -31,4 +30,11 @@ export type Code = Segment<VueCodeInformation>; | ||
checkUnknownComponents: boolean; | ||
inferComponentDollarEl: boolean; | ||
inferComponentDollarRefs: boolean; | ||
inferTemplateDollarAttrs: boolean; | ||
inferTemplateDollarEl: boolean; | ||
inferTemplateDollarRefs: boolean; | ||
inferTemplateDollarSlots: boolean; | ||
skipTemplateCodegen: boolean; | ||
fallthroughAttributes: boolean; | ||
fallthroughComponentNames: string[]; | ||
dataAttributes: string[]; | ||
@@ -108,2 +114,7 @@ htmlAttributes: string[]; | ||
} | ||
export type SfcBlockAttr = true | { | ||
text: string; | ||
offset: number; | ||
quotes: boolean; | ||
}; | ||
export interface Sfc { | ||
@@ -118,9 +129,7 @@ content: string; | ||
script: (SfcBlock & { | ||
src: string | undefined; | ||
srcOffset: number; | ||
src: SfcBlockAttr | undefined; | ||
ast: ts.SourceFile; | ||
}) | undefined; | ||
scriptSetup: SfcBlock & { | ||
generic: string | undefined; | ||
genericOffset: number; | ||
generic: SfcBlockAttr | undefined; | ||
ast: ts.SourceFile; | ||
@@ -130,6 +139,3 @@ } | undefined; | ||
scoped: boolean; | ||
module?: { | ||
name: string; | ||
offset?: number; | ||
}; | ||
module?: SfcBlockAttr | undefined; | ||
cssVars: { | ||
@@ -149,7 +155,10 @@ text: string; | ||
declare module '@vue/compiler-sfc' { | ||
interface SFCBlock { | ||
__src?: SfcBlockAttr; | ||
} | ||
interface SFCScriptBlock { | ||
__generic?: SfcBlockAttr; | ||
} | ||
interface SFCStyleBlock { | ||
__module?: { | ||
name: string; | ||
offset?: number; | ||
}; | ||
__module?: SfcBlockAttr; | ||
} | ||
@@ -156,0 +165,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parse = parse; | ||
const compiler = require("@vue/compiler-dom"); | ||
const CompilerDOM = require("@vue/compiler-dom"); | ||
function parse(source) { | ||
const errors = []; | ||
const ast = compiler.parse(source, { | ||
const ast = CompilerDOM.parse(source, { | ||
// there are no components at SFC parsing level | ||
@@ -32,7 +32,7 @@ isNativeTag: () => true, | ||
ast.children.forEach(node => { | ||
if (node.type === compiler.NodeTypes.COMMENT) { | ||
if (node.type === CompilerDOM.NodeTypes.COMMENT) { | ||
descriptor.comments.push(node.content); | ||
return; | ||
} | ||
else if (node.type !== compiler.NodeTypes.ELEMENT) { | ||
else if (node.type !== CompilerDOM.NodeTypes.ELEMENT) { | ||
return; | ||
@@ -103,11 +103,19 @@ } | ||
node.props.forEach(p => { | ||
if (p.type === compiler.NodeTypes.ATTRIBUTE) { | ||
if (p.type === CompilerDOM.NodeTypes.ATTRIBUTE) { | ||
attrs[p.name] = p.value ? p.value.content || true : true; | ||
if (p.name === 'lang') { | ||
block.lang = p.value && p.value.content; | ||
block.lang = p.value?.content; | ||
} | ||
else if (p.name === 'src') { | ||
block.src = p.value && p.value.content; | ||
block.__src = parseAttr(p, node); | ||
} | ||
else if (type === 'style') { | ||
else if (isScriptBlock(block)) { | ||
if (p.name === 'setup' || p.name === 'vapor') { | ||
block.setup = attrs[p.name]; | ||
} | ||
else if (p.name === 'generic') { | ||
block.__generic = parseAttr(p, node); | ||
} | ||
} | ||
else if (isStyleBlock(block)) { | ||
if (p.name === 'scoped') { | ||
@@ -117,12 +125,5 @@ block.scoped = true; | ||
else if (p.name === 'module') { | ||
block.__module = { | ||
name: p.value?.content ?? '$style', | ||
offset: p.value?.content ? p.value?.loc.start.offset - node.loc.start.offset : undefined | ||
}; | ||
block.__module = parseAttr(p, node); | ||
} | ||
} | ||
else if (type === 'script' | ||
&& (p.name === 'setup' || p.name === 'vapor')) { | ||
block.setup = attrs[p.name]; | ||
} | ||
} | ||
@@ -132,2 +133,25 @@ }); | ||
} | ||
function isScriptBlock(block) { | ||
return block.type === 'script'; | ||
} | ||
function isStyleBlock(block) { | ||
return block.type === 'style'; | ||
} | ||
function parseAttr(p, node) { | ||
if (!p.value) { | ||
return true; | ||
} | ||
const text = p.value.content; | ||
const source = p.value.loc.source; | ||
let offset = p.value.loc.start.offset - node.loc.start.offset; | ||
const quotes = source.startsWith('"') || source.startsWith("'"); | ||
if (quotes) { | ||
offset++; | ||
} | ||
return { | ||
text, | ||
offset, | ||
quotes, | ||
}; | ||
} | ||
//# sourceMappingURL=parseSfc.js.map |
@@ -13,2 +13,3 @@ "use strict"; | ||
const languagePlugin_1 = require("../languagePlugin"); | ||
const shared_2 = require("./shared"); | ||
function createParsedCommandLineByJson(ts, parseConfigHost, rootDir, json, configFileName = rootDir + '/jsconfig.json', skipGlobalTypesSetup = false) { | ||
@@ -178,2 +179,6 @@ const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost); | ||
}, | ||
fallthroughComponentNames: [ | ||
...defaults.fallthroughComponentNames, | ||
...this.options.fallthroughComponentNames ?? [] | ||
].map(shared_2.hyphenateTag), | ||
// https://github.com/vuejs/vue-next/blob/master/packages/compiler-dom/src/transforms/vModel.ts#L49-L51 | ||
@@ -222,4 +227,16 @@ // https://vuejs.org/guide/essentials/forms.html#form-input-bindings | ||
checkUnknownComponents: strictTemplates, | ||
inferComponentDollarEl: false, | ||
inferComponentDollarRefs: false, | ||
inferTemplateDollarAttrs: false, | ||
inferTemplateDollarEl: false, | ||
inferTemplateDollarRefs: false, | ||
inferTemplateDollarSlots: false, | ||
skipTemplateCodegen: false, | ||
fallthroughAttributes: false, | ||
fallthroughComponentNames: [ | ||
'Transition', | ||
'KeepAlive', | ||
'Teleport', | ||
'Suspense', | ||
], | ||
dataAttributes: [], | ||
@@ -226,0 +243,0 @@ htmlAttributes: ['aria-*'], |
@@ -174,9 +174,8 @@ "use strict"; | ||
const newMappings = []; | ||
let lastValidMapping; | ||
for (let i = 0; i < mappings.length; i++) { | ||
const mapping = mappings[i]; | ||
if (mapping.data.__combineOffsetMapping !== undefined) { | ||
const offsetMapping = mappings[i - mapping.data.__combineOffsetMapping]; | ||
if (mapping.data.__combineOffset !== undefined) { | ||
const offsetMapping = mappings[i - mapping.data.__combineOffset]; | ||
if (typeof offsetMapping === 'string' || !offsetMapping) { | ||
throw new Error('Invalid offset mapping, mappings: ' + mappings.length + ', i: ' + i + ', offset: ' + mapping.data.__combineOffsetMapping); | ||
throw new Error('Invalid offset mapping, mappings: ' + mappings.length + ', i: ' + i + ', offset: ' + mapping.data.__combineOffset); | ||
} | ||
@@ -188,11 +187,2 @@ offsetMapping.sourceOffsets.push(...mapping.sourceOffsets); | ||
} | ||
else if (mapping.data.__combineLastMapping) { | ||
lastValidMapping.sourceOffsets.push(...mapping.sourceOffsets); | ||
lastValidMapping.generatedOffsets.push(...mapping.generatedOffsets); | ||
lastValidMapping.lengths.push(...mapping.lengths); | ||
continue; | ||
} | ||
else { | ||
lastValidMapping = mapping; | ||
} | ||
newMappings.push(mapping); | ||
@@ -199,0 +189,0 @@ } |
@@ -35,8 +35,4 @@ "use strict"; | ||
const getScript = computedNullableSfcBlock('script', 'js', (0, alien_signals_1.computed)(() => getParseResult()?.descriptor.script ?? undefined), (block, base) => { | ||
const src = (0, alien_signals_1.computed)(() => block().src); | ||
const srcOffset = (0, alien_signals_1.computed)(() => { | ||
const _src = src(); | ||
return _src ? getUntrackedSnapshot().getText(0, base.startTagEnd).lastIndexOf(_src) - base.startTagEnd : -1; | ||
}); | ||
const ast = (0, alien_signals_1.computed)(() => { | ||
const getSrc = computedAttrValue('__src', base, block); | ||
const getAst = (0, alien_signals_1.computed)(() => { | ||
for (const plugin of plugins) { | ||
@@ -51,17 +47,9 @@ const ast = plugin.compileSFCScript?.(base.lang, base.content); | ||
return mergeObject(base, { | ||
get src() { return src(); }, | ||
get srcOffset() { return srcOffset(); }, | ||
get ast() { return ast(); }, | ||
get src() { return getSrc(); }, | ||
get ast() { return getAst(); }, | ||
}); | ||
}); | ||
const getOriginalScriptSetup = computedNullableSfcBlock('scriptSetup', 'js', (0, alien_signals_1.computed)(() => getParseResult()?.descriptor.scriptSetup ?? undefined), (block, base) => { | ||
const generic = (0, alien_signals_1.computed)(() => { | ||
const _block = block(); | ||
return typeof _block.attrs.generic === 'string' ? _block.attrs.generic : undefined; | ||
}); | ||
const genericOffset = (0, alien_signals_1.computed)(() => { | ||
const _generic = generic(); | ||
return _generic !== undefined ? getUntrackedSnapshot().getText(0, base.startTagEnd).lastIndexOf(_generic) - base.startTagEnd : -1; | ||
}); | ||
const ast = (0, alien_signals_1.computed)(() => { | ||
const getGeneric = computedAttrValue('__generic', base, block); | ||
const getAst = (0, alien_signals_1.computed)(() => { | ||
for (const plugin of plugins) { | ||
@@ -76,5 +64,4 @@ const ast = plugin.compileSFCScript?.(base.lang, base.content); | ||
return mergeObject(base, { | ||
get generic() { return generic(); }, | ||
get genericOffset() { return genericOffset(); }, | ||
get ast() { return ast(); }, | ||
get generic() { return getGeneric(); }, | ||
get ast() { return getAst(); }, | ||
}); | ||
@@ -105,9 +92,3 @@ }); | ||
const base = computedSfcBlock('style_' + i, 'css', getBlock); | ||
const getModule = (0, alien_signals_1.computed)(() => { | ||
const { __module } = getBlock(); | ||
return __module ? { | ||
name: __module.name, | ||
offset: __module.offset ? base.start + __module.offset : undefined | ||
} : undefined; | ||
}); | ||
const getModule = computedAttrValue('__module', base, getBlock); | ||
const getScoped = (0, alien_signals_1.computed)(() => !!getBlock().scoped); | ||
@@ -250,2 +231,14 @@ const getCssVars = (0, alien_signals_1.computed)(() => [...(0, parseCssVars_1.parseCssVars)(base.content)]); | ||
} | ||
function computedAttrValue(key, base, getBlock) { | ||
return (0, alien_signals_1.computed)(() => { | ||
const val = getBlock()[key]; | ||
if (typeof val === 'object') { | ||
return { | ||
...val, | ||
offset: base.start + val.offset, | ||
}; | ||
} | ||
return val; | ||
}); | ||
} | ||
} | ||
@@ -252,0 +245,0 @@ function mergeObject(a, b) { |
@@ -13,13 +13,10 @@ import type { VirtualCode } from '@volar/language-core'; | ||
private _snapshot; | ||
_vueSfc: () => import("@vue/compiler-sfc").SFCParseResult | undefined; | ||
_sfc: import("../types").Sfc; | ||
_mappings: () => { | ||
sourceOffsets: number[]; | ||
generatedOffsets: number[]; | ||
lengths: number[]; | ||
data: import("@volar/language-core").CodeInformation; | ||
}[]; | ||
_embeddedCodes: () => VirtualCode[]; | ||
private _vueSfc; | ||
private _sfc; | ||
private _embeddedCodes; | ||
private _mappings; | ||
get snapshot(): ts.IScriptSnapshot; | ||
get vueSfc(): import("@vue/compiler-sfc").SFCParseResult | undefined; | ||
get sfc(): import("../types").Sfc; | ||
get embeddedCodes(): VirtualCode[]; | ||
get snapshot(): ts.IScriptSnapshot; | ||
get mappings(): { | ||
@@ -26,0 +23,0 @@ sourceOffsets: number[]; |
@@ -11,8 +11,14 @@ "use strict"; | ||
// others | ||
get snapshot() { | ||
return this._snapshot(); | ||
} | ||
get vueSfc() { | ||
return this._vueSfc(); | ||
} | ||
get sfc() { | ||
return this._sfc; | ||
} | ||
get embeddedCodes() { | ||
return this._embeddedCodes(); | ||
} | ||
get snapshot() { | ||
return this._snapshot(); | ||
} | ||
get mappings() { | ||
@@ -34,2 +40,3 @@ return this._mappings(); | ||
this._sfc = (0, computedSfc_1.computedSfc)(this.ts, this.plugins, this.fileName, this._snapshot, this._vueSfc); | ||
this._embeddedCodes = (0, computedEmbeddedCodes_1.computedEmbeddedCodes)(this.plugins, this.fileName, this._sfc); | ||
this._mappings = (0, alien_signals_1.computed)(() => { | ||
@@ -44,3 +51,2 @@ const snapshot = this._snapshot(); | ||
}); | ||
this._embeddedCodes = (0, computedEmbeddedCodes_1.computedEmbeddedCodes)(this.plugins, this.fileName, this._sfc); | ||
this._snapshot(initSnapshot); | ||
@@ -47,0 +53,0 @@ } |
{ | ||
"name": "@vue/language-core", | ||
"version": "2.2.2", | ||
"version": "2.2.4", | ||
"license": "MIT", | ||
@@ -40,3 +40,3 @@ "files": [ | ||
}, | ||
"gitHead": "30757908b67f40f779c36795665163634fb81868" | ||
"gitHead": "c28986596935cb43979c9d437c25f292bdb36cef" | ||
} |
362006
8341
138