@volar/language-core 2.3.0-alpha.5 → 2.3.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -56,14 +56,15 @@ function createLanguage(plugins, scriptRegistry, sync) {
56
56
  this.delete(id);
57
57
  return this.set(id, snapshot, languageId);
58
58
  }
59
- else if (sourceScript.snapshot !== snapshot) {
59
+ else if (sourceScript.isAssociationDirty || sourceScript.snapshot !== snapshot) {
60
60
  // snapshot updated
61
61
  sourceScript.snapshot = snapshot;
62
+ const codegenCtx = prepareCreateVirtualCode(sourceScript);
62
63
  if (sourceScript.generated) {
63
64
  const { updateVirtualCode, createVirtualCode } = sourceScript.generated.languagePlugin;
64
65
  const newVirtualCode = updateVirtualCode
65
- ? updateVirtualCode(id, sourceScript.generated.root, snapshot)
66
- : createVirtualCode?.(id, languageId, snapshot);
66
+ ? updateVirtualCode(id, sourceScript.generated.root, snapshot, codegenCtx)
67
+ : createVirtualCode?.(id, languageId, snapshot, codegenCtx);
67
68
  if (newVirtualCode) {
68
69
  sourceScript.generated.root = newVirtualCode;
69
70
  sourceScript.generated.embeddedCodes.clear();
@@ -78,6 +79,7 @@ function createLanguage(plugins, scriptRegistry, sync) {
78
79
  return;
79
80
  }
80
81
  }
82
+ triggerTargetsDirty(sourceScript);
81
83
  }
82
84
  else {
83
85
  // not changed
@@ -86,10 +88,16 @@ function createLanguage(plugins, scriptRegistry, sync) {
86
88
  }
87
89
  else {
88
90
  // created
89
- const sourceScript = { id, languageId, snapshot };
91
+ const sourceScript = {
92
+ id: id,
93
+ languageId,
94
+ snapshot,
95
+ associatedIds: new Set(),
96
+ targetIds: new Set(),
97
+ };
90
98
  scriptRegistry.set(id, sourceScript);
91
99
  for (const languagePlugin of _plugins) {
92
- const virtualCode = languagePlugin.createVirtualCode?.(id, languageId, snapshot);
100
+ const virtualCode = languagePlugin.createVirtualCode?.(id, languageId, snapshot, prepareCreateVirtualCode(sourceScript));
93
101
  if (virtualCode) {
94
102
  sourceScript.generated = {
95
103
  root: virtualCode,
@@ -107,29 +115,42 @@ function createLanguage(plugins, scriptRegistry, sync) {
107
115
  }
108
116
  },
109
117
  delete(id) {
110
- const value = scriptRegistry.get(id);
111
- if (value) {
112
- if (value.generated) {
113
- value.generated.languagePlugin.disposeVirtualCode?.(id, value.generated.root);
114
- }
118
+ const sourceScript = scriptRegistry.get(id);
119
+ if (sourceScript) {
120
+ sourceScript.generated?.languagePlugin.disposeVirtualCode?.(id, sourceScript.generated.root);
115
121
  scriptRegistry.delete(id);
122
+ triggerTargetsDirty(sourceScript);
116
123
  }
117
124
  },
118
125
  },
119
126
  maps: {
120
127
  get(virtualCode) {
121
- const sourceScript = virtualCodeToSourceScriptMap.get(virtualCode);
128
+ for (const map of this.forEach(virtualCode)) {
129
+ return map[2];
130
+ }
131
+ throw `no map found for ${virtualCode.id}`;
132
+ },
133
+ *forEach(virtualCode) {
122
134
  let mapCache = virtualCodeToSourceMap.get(virtualCode.snapshot);
123
- if (mapCache?.[0] !== sourceScript.snapshot) {
124
- if (virtualCode.mappings.some(mapping => mapping.source)) {
125
- throw 'not implemented';
135
+ if (!mapCache) {
136
+ virtualCodeToSourceMap.set(virtualCode.snapshot, mapCache = new WeakMap());
137
+ }
138
+ const sourceScript = virtualCodeToSourceScriptMap.get(virtualCode);
139
+ if (!mapCache.has(sourceScript.snapshot)) {
140
+ mapCache.set(sourceScript.snapshot, new source_map_1.SourceMap(virtualCode.mappings));
141
+ }
142
+ yield [sourceScript.id, sourceScript.snapshot, mapCache.get(sourceScript.snapshot)];
143
+ if (virtualCode.associatedScriptMappings) {
144
+ for (const [relatedScriptId, relatedMappings] of virtualCode.associatedScriptMappings) {
145
+ const relatedSourceScript = scriptRegistry.get(relatedScriptId);
146
+ if (relatedSourceScript) {
147
+ if (!mapCache.has(relatedSourceScript.snapshot)) {
148
+ mapCache.set(relatedSourceScript.snapshot, new source_map_1.SourceMap(relatedMappings));
149
+ }
150
+ yield [relatedSourceScript.id, relatedSourceScript.snapshot, mapCache.get(relatedSourceScript.snapshot)];
151
+ }
126
152
  }
127
- virtualCodeToSourceMap.set(virtualCode.snapshot, mapCache = [
128
- sourceScript.snapshot,
129
- new source_map_1.SourceMap(virtualCode.mappings),
130
- ]);
131
153
  }
132
- return mapCache[1];
133
154
  },
134
155
  },
135
156
  linkedCodeMaps: {
@@ -148,6 +169,32 @@ function createLanguage(plugins, scriptRegistry, sync) {
148
169
  },
149
170
  },
150
171
  };
172
+ function triggerTargetsDirty(sourceScript) {
173
+ sourceScript.targetIds.forEach(id => {
174
+ const sourceScript = scriptRegistry.get(id);
175
+ if (sourceScript) {
176
+ sourceScript.isAssociationDirty = true;
177
+ }
178
+ });
179
+ }
180
+ function prepareCreateVirtualCode(sourceScript) {
181
+ for (const id of sourceScript.associatedIds) {
182
+ scriptRegistry.get(id)?.targetIds.delete(sourceScript.id);
183
+ }
184
+ sourceScript.associatedIds.clear();
185
+ sourceScript.isAssociationDirty = false;
186
+ return {
187
+ getAssociatedScript(id) {
188
+ sync(id);
189
+ const relatedSourceScript = scriptRegistry.get(id);
190
+ if (relatedSourceScript) {
191
+ relatedSourceScript.targetIds.add(sourceScript.id);
192
+ sourceScript.associatedIds.add(relatedSourceScript.id);
193
+ }
194
+ return relatedSourceScript;
195
+ },
196
+ };
197
+ }
151
198
  }
152
199
  exports.createLanguage = createLanguage;
153
200
  function* forEachEmbeddedCode(virtualCode) {
@@ -1,4 +1,4 @@
1
1
  import { SourceMap } from '@volar/source-map';
2
- export declare class LinkedCodeMap extends SourceMap {
2
+ export declare class LinkedCodeMap extends SourceMap<any> {
3
3
  getLinkedOffsets(start: number): Generator<number, void, unknown>;
4
4
  }
package/lib/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Mapping, SourceMap } from '@volar/source-map';
2
2
  import type * as ts from 'typescript';
3
3
  import type { LinkedCodeMap } from './linkedCodeMap';
4
- export interface Language<T> {
4
+ export interface Language<T = unknown> {
5
5
  plugins: LanguagePlugin<T>[];
6
6
  scripts: {
7
7
  get(id: T): SourceScript<T> | undefined;
@@ -11,6 +11,7 @@ export interface Language<T> {
11
11
  };
12
12
  maps: {
13
13
  get(virtualCode: VirtualCode): SourceMap<CodeInformation>;
14
+ forEach(virtualCode: VirtualCode): Generator<[id: T, snapshot: ts.IScriptSnapshot, map: SourceMap<CodeInformation>]>;
14
15
  };
15
16
  linkedCodeMaps: {
16
17
  get(virtualCode: VirtualCode): LinkedCodeMap | undefined;
@@ -27,10 +28,13 @@ export interface Language<T> {
27
28
  asFileName(scriptId: T): string;
28
29
  };
29
30
  }
30
- export interface SourceScript<T> {
31
+ export interface SourceScript<T = unknown> {
31
32
  id: T;
32
33
  languageId: string;
33
34
  snapshot: ts.IScriptSnapshot;
35
+ targetIds: Set<T>;
36
+ associatedIds: Set<T>;
37
+ isAssociationDirty?: boolean;
34
38
  generated?: {
35
39
  root: VirtualCode;
36
40
  languagePlugin: LanguagePlugin<T>;
@@ -43,6 +47,7 @@ export interface VirtualCode {
43
47
  languageId: string;
44
48
  snapshot: ts.IScriptSnapshot;
45
49
  mappings: CodeMapping[];
50
+ associatedScriptMappings?: Map<unknown, CodeMapping[]>;
46
51
  embeddedCodes?: VirtualCode[];
47
52
  linkedCodeMappings?: Mapping[];
48
53
  }
@@ -75,11 +80,13 @@ export interface TypeScriptServiceScript {
75
80
  code: VirtualCode;
76
81
  extension: '.ts' | '.js' | '.mts' | '.mjs' | '.cjs' | '.cts' | '.d.ts' | string;
77
82
  scriptKind: ts.ScriptKind;
83
+ /** See #188 */
84
+ preventLeadingOffset?: boolean;
78
85
  }
79
86
  export interface TypeScriptExtraServiceScript extends TypeScriptServiceScript {
80
87
  fileName: string;
81
88
  }
82
- export interface LanguagePlugin<T, K extends VirtualCode = VirtualCode> {
89
+ export interface LanguagePlugin<T = unknown, K extends VirtualCode = VirtualCode> {
83
90
  /**
84
91
  * For files that are not opened in the IDE, the language ID will not be synchronized to the language server, so a hook is needed to parse the language ID of files that are known extension but not opened in the IDE.
85
92
  */
@@ -87,30 +94,33 @@ export interface LanguagePlugin<T, K extends VirtualCode = VirtualCode> {
87
94
  /**
88
95
  * Generate a virtual code.
89
96
  */
90
- createVirtualCode?(scriptId: T, languageId: string, snapshot: ts.IScriptSnapshot): K | undefined;
97
+ createVirtualCode?(scriptId: T, languageId: string, snapshot: ts.IScriptSnapshot, ctx: CodegenContext<T>): K | undefined;
91
98
  /**
92
99
  * Incremental update a virtual code. If not provide, call createVirtualCode again.
93
100
  */
94
- updateVirtualCode?(scriptId: T, virtualCode: K, newSnapshot: ts.IScriptSnapshot): K | undefined;
101
+ updateVirtualCode?(scriptId: T, virtualCode: K, newSnapshot: ts.IScriptSnapshot, ctx: CodegenContext<T>): K | undefined;
95
102
  /**
96
103
  * Cleanup a virtual code.
97
104
  */
98
105
  disposeVirtualCode?(scriptId: T, virtualCode: K): void;
99
106
  typescript?: TypeScriptGenericOptions<K> & TypeScriptNonTSPluginOptions<K>;
100
107
  }
108
+ export interface CodegenContext<T = unknown> {
109
+ getAssociatedScript(scriptId: T): SourceScript<T> | undefined;
110
+ }
101
111
  /**
102
112
  * The following options available to all situations.
103
113
  */
104
- interface TypeScriptGenericOptions<T> {
114
+ interface TypeScriptGenericOptions<K> {
105
115
  extraFileExtensions: ts.FileExtensionInfo[];
106
116
  resolveHiddenExtensions?: boolean;
107
- getServiceScript(rootVirtualCode: T): TypeScriptServiceScript | undefined;
117
+ getServiceScript(root: K): TypeScriptServiceScript | undefined;
108
118
  }
109
119
  /**
110
120
  * The following options will not be available in TS plugin.
111
121
  */
112
- interface TypeScriptNonTSPluginOptions<T> {
113
- getExtraServiceScripts?(fileName: string, rootVirtualCode: T): TypeScriptExtraServiceScript[];
122
+ interface TypeScriptNonTSPluginOptions<K> {
123
+ getExtraServiceScripts?(fileName: string, rootVirtualCode: K): TypeScriptExtraServiceScript[];
114
124
  resolveLanguageServiceHost?(host: ts.LanguageServiceHost): ts.LanguageServiceHost;
115
125
  }
116
126
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volar/language-core",
3
- "version": "2.3.0-alpha.5",
3
+ "version": "2.3.0-alpha.7",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -12,7 +12,7 @@
12
12
  "directory": "packages/language-core"
13
13
  },
14
14
  "dependencies": {
15
- "@volar/source-map": "2.3.0-alpha.5"
15
+ "@volar/source-map": "2.3.0-alpha.7"
16
16
  },
17
- "gitHead": "c3f6867de39095913ceaa2256ad35a9ca1a90487"
17
+ "gitHead": "3cc2a62516113c5789e4f54766e25063099a13a5"
18
18
  }