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

Complete support for multi-source mapping in plugin mode #197

Merged
merged 4 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions packages/language-core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ export * from './lib/utils';
import { SourceMap } from '@volar/source-map';
import type * as ts from 'typescript';
import { LinkedCodeMap } from './lib/linkedCodeMap';
import type { CodeInformation, CodegenContext, Language, LanguagePlugin, SourceScript, VirtualCode } from './lib/types';
import type {
CodeInformation,
CodegenContext,
Language,
LanguagePlugin,
SourceScript,
VirtualCode,
} from './lib/types';

export function createLanguage<T>(
plugins: LanguagePlugin<T>[],
Expand All @@ -26,6 +33,11 @@ export function createLanguage<T>(
},
get(id) {
sync(id);
const result = scriptRegistry.get(id);
// The sync function provider may not always call the set function due to caching, so it is necessary to explicitly check isAssociationDirty.
if (result?.isAssociationDirty) {
this.set(id, result.snapshot, result.languageId);
}
return scriptRegistry.get(id);
},
set(id, snapshot, languageId, _plugins = plugins) {
Expand All @@ -41,13 +53,22 @@ export function createLanguage<T>(
console.warn(`languageId not found for ${id}`);
return;
}
let associatedOnly = false;
for (const plugin of plugins) {
if (plugin.isAssociatedFileOnly?.(id, languageId)) {
associatedOnly = true;
break;
}
}
if (scriptRegistry.has(id)) {
const sourceScript = scriptRegistry.get(id)!;
if (sourceScript.languageId !== languageId) {
// languageId changed
if (sourceScript.languageId !== languageId || sourceScript.associatedOnly !== associatedOnly) {
this.delete(id);
return this.set(id, snapshot, languageId);
}
else if (associatedOnly) {
sourceScript.snapshot = snapshot;
}
else if (sourceScript.isAssociationDirty || sourceScript.snapshot !== snapshot) {
// snapshot updated
sourceScript.snapshot = snapshot;
Expand Down Expand Up @@ -86,9 +107,12 @@ export function createLanguage<T>(
snapshot,
associatedIds: new Set(),
targetIds: new Set(),
associatedOnly
};
scriptRegistry.set(id, sourceScript);

if (associatedOnly) {
return sourceScript;
}
for (const languagePlugin of _plugins) {
const virtualCode = languagePlugin.createVirtualCode?.(id, languageId, snapshot, prepareCreateVirtualCode(sourceScript));
if (virtualCode) {
Expand Down
8 changes: 8 additions & 0 deletions packages/language-core/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface SourceScript<T = unknown> {
snapshot: ts.IScriptSnapshot;
targetIds: Set<T>;
associatedIds: Set<T>;
associatedOnly: boolean;
isAssociationDirty?: boolean;
generated?: {
root: VirtualCode;
Expand Down Expand Up @@ -111,6 +112,13 @@ export interface LanguagePlugin<T = unknown, K extends VirtualCode = VirtualCode
* Cleanup a virtual code.
*/
disposeVirtualCode?(scriptId: T, virtualCode: K): void;
/**
* Some file types should not be parsed or processed as TypeScript files,
* as they are used only as sources for generated files.
*
* This functionality is required only in TS plugin mode.
*/
isAssociatedFileOnly?(scriptId: T, languageId: string): boolean;
typescript?: TypeScriptGenericOptions<K> & TypeScriptNonTSPluginOptions<K>;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/source-map/lib/sourceMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ export class SourceMap<Data = unknown> {
}

function getLengths(mapping: Mapping, key: CodeRangeKey) {
return key == "sourceOffsets" ? mapping.lengths : mapping.generatedLengths ?? mapping.lengths;
return key == 'sourceOffsets' ? mapping.lengths : mapping.generatedLengths ?? mapping.lengths;
}
Loading
Loading