Skip to content

Commit

Permalink
feat: redo nativeTags (#3279)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Jun 14, 2023
1 parent a1855c6 commit fb1121a
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 111 deletions.
5 changes: 2 additions & 3 deletions packages/vue-component-meta/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function createComponentMetaCheckerWorker(
};

return {
...baseCreate(_host, parsedCommandLine.vueOptions, checkerOptions, globalComponentName, ts),
...baseCreate(_host, vue.resolveVueCompilerOptions(parsedCommandLine.vueOptions), checkerOptions, globalComponentName, ts),
updateFile(fileName: string, text: string) {
fileName = (fileName as path.OsPath).replace(/\\/g, '/') as path.PosixPath;
scriptSnapshots.set(fileName, ts.ScriptSnapshot.fromString(text));
Expand All @@ -110,12 +110,11 @@ function createComponentMetaCheckerWorker(

export function baseCreate(
_host: vue.TypeScriptLanguageHost,
_vueCompilerOptions: Partial<vue.VueCompilerOptions>,
vueCompilerOptions: vue.VueCompilerOptions,
checkerOptions: MetaCheckerOptions,
globalComponentName: string,
ts: typeof import('typescript/lib/tsserverlibrary'),
) {
const vueCompilerOptions = vue.resolveVueCompilerOptions(_vueCompilerOptions);
const globalComponentSnapshot = ts.ScriptSnapshot.fromString('<script setup lang="ts"></script>');
const metaSnapshots: Record<string, ts.IScriptSnapshot> = {};
const host = new Proxy<Partial<vue.TypeScriptLanguageHost>>({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@
"jsxTemplates": {
"deprecated": true,
"description": "Deprecated since v1.5.0."
},
"nativeTags": {
"deprecated": true,
"description": "Deprecated since v1.5.1."
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions packages/vue-language-core/schemas/vue-tsconfig.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
"type": "boolean",
"markdownDescription": "https://github.com/vuejs/language-tools/issues/577"
},
"nativeTags": {
"type": "array",
"default": [
"div",
"img",
"..."
],
"markdownDescription": "List of valid intrinsic elements."
},
"dataAttributes": {
"type": "array",
"default": [ ],
Expand Down
95 changes: 63 additions & 32 deletions packages/vue-language-core/src/generators/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export function generate(
codegenStack: boolean,
) {

const nativeTags = new Set(vueCompilerOptions.nativeTags);
const [codes, codeStacks] = codegenStack ? muggle.track([] as Code[]) : [[], []];
const [formatCodes, formatCodeStacks] = codegenStack ? muggle.track([] as Code[]) : [[], []];
const [cssCodes, cssCodeStacks] = codegenStack ? muggle.track([] as Code[]) : [[], []];
Expand Down Expand Up @@ -179,39 +180,38 @@ export function generate(

const data: Record<string, string> = {};

codes.push(`let __VLS_templateComponents!: __VLS_IntrinsicElements\n`);
codes.push(`let __VLS_templateComponents!: {}\n`);

for (const tagName in tagNames) {

if (nativeTags.has(tagName))
continue;

const isNamespacedTag = tagName.indexOf('.') >= 0;
if (isNamespacedTag)
continue;

const varName = validTsVar.test(tagName) ? tagName : capitalize(camelize(tagName.replace(/:/g, '-')));
const validName = validTsVar.test(tagName) ? tagName : capitalize(camelize(tagName.replace(/:/g, '-')));

codes.push(
`& __VLS_WithComponent<'${varName}', typeof __VLS_components, `,
`& __VLS_WithComponent<'${validName}', typeof __VLS_components, `,
// order is important: https://github.com/vuejs/language-tools/issues/2010
`"${capitalize(camelize(tagName))}", `,
`"${camelize(tagName)}", `,
`"${tagName}"`,
'>\n',
);

data[tagName] = varName;
data[tagName] = validName;
}

codes.push(`;\n`);

for (const tagName in tagNames) {

const varName = data[tagName];
if (!varName)
continue;

const tagOffsets = tagNames[tagName];
const tagRanges: [number, number][] = tagOffsets.map(offset => [offset, offset + tagName.length]);
const names = new Set([
const names = new Set(nativeTags.has(tagName) ? [tagName] : [
// order is important: https://github.com/vuejs/language-tools/issues/2010
capitalize(camelize(tagName)),
camelize(tagName),
Expand All @@ -221,7 +221,7 @@ export function generate(
for (const name of names) {
for (const tagRange of tagRanges) {
codes.push(
name === tagName ? '__VLS_templateComponents' : '__VLS_components',
nativeTags.has(tagName) ? '({} as __VLS_IntrinsicElements)' : '__VLS_components',
...createPropertyAccessCode([
name,
'template',
Expand All @@ -240,25 +240,29 @@ export function generate(
}
codes.push('\n');

codes.push(
'// @ts-ignore\n', // #2304
'[',
);
for (const tagRange of tagRanges) {
codes.push([
varName,
'template',
tagRange,
{
completion: {
additional: true,
autoImportOnly: true,
const validName = data[tagName];

if (validName) {
codes.push(
'// @ts-ignore\n', // #2304
'[',
);
for (const tagRange of tagRanges) {
codes.push([
validName,
'template',
tagRange,
{
completion: {
additional: true,
autoImportOnly: true,
},
},
},
]);
codes.push(',');
]);
codes.push(',');
}
codes.push(`];\n`);
}
codes.push(`];\n`);
}

return data;
Expand Down Expand Up @@ -635,7 +639,23 @@ export function generate(
}
}

if (isNamespacedTag) {
const isIntrinsicElement = nativeTags.has(tag) && tagOffsets.length;

if (isIntrinsicElement) {
codes.push(
'const ',
var_originalComponent,
` = ({} as __VLS_IntrinsicElements)[`,
...createStringLiteralKeyCode([
tag,
'template',
tagOffsets[0],
capabilitiesPresets.diagnosticOnly,
]),
'];\n',
);
}
else if (isNamespacedTag) {
codes.push(
`const ${var_originalComponent} = `,
...createInterpolationCode(tag, node.loc, startTagOffset, capabilitiesPresets.all, '', ''),
Expand All @@ -659,10 +679,18 @@ export function generate(
codes.push(
`const ${var_functionalComponent} = __VLS_asFunctionalComponent(`,
`${var_originalComponent}, `,
`new ${var_originalComponent}({`,
...createPropsCode(node, props, 'extraReferences'),
'}));\n',
);
if (isIntrinsicElement) {
codes.push('{}');
}
else {
codes.push(
`new ${var_originalComponent}({`,
...createPropsCode(node, props, 'extraReferences'),
'})',
);
}
codes.push(');\n');

for (const offset of tagOffsets) {
if (isNamespacedTag) {
Expand All @@ -672,7 +700,10 @@ export function generate(
continue;
}
else {
if (componentVars[tag]) {
if (isIntrinsicElement) {
codes.push(`({} as __VLS_IntrinsicElements).`);
}
else {
codes.push(`__VLS_templateComponents.`);
}
codes.push(
Expand Down
1 change: 1 addition & 0 deletions packages/vue-language-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface VueCompilerOptions {
jsxSlots: boolean;
strictTemplates: boolean;
skipTemplateCodegen: boolean;
nativeTags: string[];
dataAttributes: string[];
htmlAttributes: string[];
optionsWrapper: [string, string] | [];
Expand Down
33 changes: 33 additions & 0 deletions packages/vue-language-core/src/utils/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,31 @@ function getPartialVueCompilerOptions(
}
}

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element
const HTML_TAGS =
'html,body,base,head,link,meta,style,title,address,article,aside,footer,' +
'header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,' +
'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' +
'data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,' +
'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' +
'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' +
'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' +
'option,output,progress,select,textarea,details,dialog,menu,' +
'summary,template,blockquote,iframe,tfoot';

// https://developer.mozilla.org/en-US/docs/Web/SVG/Element
const SVG_TAGS =
'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' +
'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' +
'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' +
'feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,' +
'feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,' +
'fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,' +
'foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,' +
'mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,' +
'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' +
'text,textPath,title,tspan,unknown,use,view';

export function resolveVueCompilerOptions(vueOptions: Partial<VueCompilerOptions>): VueCompilerOptions {
const target = vueOptions.target ?? 3.3;
const lib = vueOptions.lib || (target < 2.7 ? '@vue/runtime-dom' : 'vue');
Expand All @@ -212,6 +237,14 @@ export function resolveVueCompilerOptions(vueOptions: Partial<VueCompilerOptions
jsxSlots: vueOptions.jsxSlots ?? false,
strictTemplates: vueOptions.strictTemplates ?? false,
skipTemplateCodegen: vueOptions.skipTemplateCodegen ?? false,
nativeTags: vueOptions.nativeTags ?? [...new Set([
...HTML_TAGS.split(','),
...SVG_TAGS.split(','),
// fix https://github.com/johnsoncodehk/volar/issues/1340
'hgroup',
'slot',
'component',
])],
dataAttributes: vueOptions.dataAttributes ?? [],
htmlAttributes: vueOptions.htmlAttributes ?? ['aria-*'],
optionsWrapper: vueOptions.optionsWrapper ?? (
Expand Down
10 changes: 5 additions & 5 deletions packages/vue-language-server/src/languageServerPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function createServerPlugin(connection: Connection) {

const ts = modules.typescript;
const vueFileExtensions: string[] = ['vue'];
const hostToVueOptions = new WeakMap<embedded.TypeScriptLanguageHost, Partial<VueCompilerOptions>>();
const hostToVueOptions = new WeakMap<embedded.TypeScriptLanguageHost, VueCompilerOptions>();

if (initOptions.additionalExtensions) {
for (const additionalExtension of initOptions.additionalExtensions) {
Expand All @@ -38,7 +38,7 @@ export function createServerPlugin(connection: Connection) {
const vueLanguageServiceSettings = getVueLanguageServiceSettings();

if (ctx) {
hostToVueOptions.set(ctx.host, vueOptions);
hostToVueOptions.set(ctx.host, vue.resolveVueCompilerOptions(vueOptions));
}

return vue.resolveConfig(
Expand Down Expand Up @@ -109,14 +109,14 @@ export function createServerPlugin(connection: Connection) {
connection.onRequest(DetectNameCasingRequest.type, async params => {
const languageService = await getService(params.textDocument.uri);
if (languageService) {
return nameCasing.detect(ts, languageService.context, params.textDocument.uri);
return nameCasing.detect(ts, languageService.context, params.textDocument.uri, hostToVueOptions.get(languageService.context.rawHost)!);
}
});

connection.onRequest(GetConvertTagCasingEditsRequest.type, async params => {
const languageService = await getService(params.textDocument.uri);
if (languageService) {
return nameCasing.convertTagName(ts, languageService.context, params.textDocument.uri, params.casing);
return nameCasing.convertTagName(ts, languageService.context, params.textDocument.uri, params.casing, hostToVueOptions.get(languageService.context.rawHost)!);
}
});

Expand All @@ -125,7 +125,7 @@ export function createServerPlugin(connection: Connection) {
if (languageService) {
const vueOptions = hostToVueOptions.get(languageService.context.host);
if (vueOptions) {
return nameCasing.convertAttrName(ts, languageService.context, params.textDocument.uri, params.casing);
return nameCasing.convertAttrName(ts, languageService.context, params.textDocument.uri, params.casing, hostToVueOptions.get(languageService.context.rawHost)!);
}
}
});
Expand Down

0 comments on commit fb1121a

Please sign in to comment.