Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ESLint supports #2220

Merged
merged 10 commits into from Dec 18, 2022
4 changes: 2 additions & 2 deletions packages/language-core/src/documentRegistry.ts
Expand Up @@ -66,7 +66,7 @@ export function createDocumentRegistry() {
}
},

fromEmbeddedLocation: function* (fileName: string, offset: number) {
fromEmbeddedLocation: function* (fileName: string, offset: number, baseOnRight: boolean = false) {

if (fileName.endsWith('/__VLS_types.ts')) { // TODO: monkey fix
return;
Expand All @@ -78,7 +78,7 @@ export function createDocumentRegistry() {

const sourceMap = getSourceMap(mapped.sourceFile, mapped.embedded.mappings);

for (const vueRange of sourceMap.toSourceOffsets(offset)) {
for (const vueRange of sourceMap.toSourceOffsets(offset, baseOnRight)) {
yield {
fileName: mapped.sourceFile.fileName,
offset: vueRange[0],
Expand Down
12 changes: 3 additions & 9 deletions packages/language-service/src/documents.ts
Expand Up @@ -110,7 +110,7 @@ export class SourceMap<Data = undefined> extends SourceMapBase<Data> {
to: 'sourceRange' | 'generatedRange',
baseOffset: 'left' | 'right',
) {
for (const mapped of this.matcing(fromDoc.offsetAt(position), from, to)) {
for (const mapped of this.matcing(fromDoc.offsetAt(position), from, to, baseOffset === 'right')) {
if (!filter(mapped[1].data)) {
continue;
}
Expand All @@ -124,21 +124,15 @@ export class SourceMap<Data = undefined> extends SourceMapBase<Data> {
}

protected matchSourcePosition(position: vscode.Position, mapping: Mapping, baseOffset: 'left' | 'right') {
let offset = this.matchOffset(this.mappedDocument.offsetAt(position), mapping['generatedRange'], mapping['sourceRange']);
let offset = this.matchOffset(this.mappedDocument.offsetAt(position), mapping['generatedRange'], mapping['sourceRange'], baseOffset === 'right');
if (offset !== undefined) {
if (baseOffset === 'right') {
offset += (mapping.sourceRange[1] - mapping.sourceRange[0]) - (mapping.generatedRange[1] - mapping.generatedRange[0]);
}
return this.sourceDocument.positionAt(offset);
}
}

protected matchGeneratedPosition(position: vscode.Position, mapping: Mapping, baseOffset: 'left' | 'right') {
let offset = this.matchOffset(this.sourceDocument.offsetAt(position), mapping['sourceRange'], mapping['generatedRange']);
let offset = this.matchOffset(this.sourceDocument.offsetAt(position), mapping['sourceRange'], mapping['generatedRange'], baseOffset === 'right');
if (offset !== undefined) {
if (baseOffset === 'right') {
offset += (mapping.generatedRange[1] - mapping.generatedRange[0]) - (mapping.sourceRange[1] - mapping.sourceRange[0]);
}
return this.mappedDocument.positionAt(offset);
}
}
Expand Down
28 changes: 16 additions & 12 deletions packages/source-map/src/index.ts
Expand Up @@ -82,27 +82,27 @@ export class SourceMapBase<Data = undefined> {
constructor(public readonly mappings: Mapping<Data>[]) {
}

public toSourceOffset(start: number) {
for (const mapped of this.matcing(start, 'generatedRange', 'sourceRange')) {
public toSourceOffset(start: number, baseOnRight: boolean = false) {
for (const mapped of this.matcing(start, 'generatedRange', 'sourceRange', baseOnRight)) {
return mapped;
}
}

public toGeneratedOffset(start: number) {
for (const mapped of this.matcing(start, 'sourceRange', 'generatedRange')) {
public toGeneratedOffset(start: number, baseOnRight: boolean = false) {
for (const mapped of this.matcing(start, 'sourceRange', 'generatedRange', baseOnRight)) {
return mapped;
}
}

public toSourceOffsets(start: number) {
return this.matcing(start, 'generatedRange', 'sourceRange');
public toSourceOffsets(start: number, baseOnRight: boolean = false) {
return this.matcing(start, 'generatedRange', 'sourceRange', baseOnRight);
}

public toGeneratedOffsets(start: number) {
return this.matcing(start, 'sourceRange', 'generatedRange');
public toGeneratedOffsets(start: number, baseOnRight: boolean = false) {
return this.matcing(start, 'sourceRange', 'generatedRange', baseOnRight);
}

public * matcing(startOffset: number, from: 'sourceRange' | 'generatedRange', to: 'sourceRange' | 'generatedRange') {
public * matcing(startOffset: number, from: 'sourceRange' | 'generatedRange', to: 'sourceRange' | 'generatedRange', baseOnRight: boolean) {

const memo = this.memo[from];

Expand All @@ -124,17 +124,21 @@ export class SourceMapBase<Data = undefined> {
}
skip.add(mapping);

const mapped = this.matchOffset(startOffset, mapping[from], mapping[to]);
const mapped = this.matchOffset(startOffset, mapping[from], mapping[to], baseOnRight);
if (mapped !== undefined) {
yield [mapped, mapping] as const;
}
}
}
}

public matchOffset(start: number, mappedFromRange: [number, number], mappedToRange: [number, number]): number | undefined {
public matchOffset(start: number, mappedFromRange: [number, number], mappedToRange: [number, number], baseOnRight: boolean): number | undefined {
if (start >= mappedFromRange[0] && start <= mappedFromRange[1]) {
return mappedToRange[0] + start - mappedFromRange[0];
let offset = mappedToRange[0] + start - mappedFromRange[0];
if (baseOnRight) {
offset += (mappedToRange[1] - mappedToRange[0]) - (mappedFromRange[1] - mappedFromRange[0]);
}
return offset;
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/typescript/src/getProgram.ts
Expand Up @@ -109,6 +109,7 @@ export function getProgram(
for (const end of core.mapper.fromEmbeddedLocation(
diagnostic.file.fileName,
diagnostic.start + diagnostic.length,
true,
)) {

if (end.mapping && !end.mapping.data.diagnostic)
Expand Down
16 changes: 14 additions & 2 deletions packages/typescript/src/index.ts
Expand Up @@ -4,11 +4,18 @@ import * as embedded from '@volar/language-core';

export function createLanguageService(host: embedded.LanguageServiceHost, mods: embedded.LanguageModule[]) {

type _LanguageService = {
__internal__: {
languageService: ts.LanguageService;
context: embedded.EmbeddedLanguageContext;
};
} & ts.LanguageService;

const core = embedded.createEmbeddedLanguageServiceHost(host, mods);
const ts = host.getTypeScriptModule();
const ls = ts.createLanguageService(core.typescriptLanguageServiceHost);

return new Proxy<Partial<ts.LanguageService>>({
return new Proxy<Partial<_LanguageService>>({
organizeImports,

// only support for .ts for now, not support for .vue
Expand All @@ -35,14 +42,19 @@ export function createLanguageService(host: embedded.LanguageServiceHost, mods:
// getEditsForRefactor: tsLanguageService.rawLs.getEditsForRefactor,

getProgram: () => getProgram(ts, core, ls),

__internal__: {
context: core,
languageService: ls,
},
}, {
get: (target: any, property: keyof ts.LanguageService) => {
if (property in target) {
return target[property];
}
return ls[property];
},
}) as ts.LanguageService;
}) as _LanguageService;

// apis
function organizeImports(args: ts.OrganizeImportsArgs, formatOptions: ts.FormatCodeSettings, preferences: ts.UserPreferences | undefined): ReturnType<ts.LanguageService['organizeImports']> {
Expand Down