Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/amdX.ts
3290 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { AppResourcePath, FileAccess, nodeModulesAsarPath, nodeModulesPath, Schemas, VSCODE_AUTHORITY } from './base/common/network.js';
7
import * as platform from './base/common/platform.js';
8
import { IProductConfiguration } from './base/common/product.js';
9
import { URI } from './base/common/uri.js';
10
import { generateUuid } from './base/common/uuid.js';
11
12
export const canASAR = false; // TODO@esm: ASAR disabled in ESM
13
14
declare const window: any;
15
declare const document: any;
16
declare const self: any;
17
declare const globalThis: any;
18
19
class DefineCall {
20
constructor(
21
public readonly id: string | null | undefined,
22
public readonly dependencies: string[] | null | undefined,
23
public readonly callback: any
24
) { }
25
}
26
27
enum AMDModuleImporterState {
28
Uninitialized = 1,
29
InitializedInternal,
30
InitializedExternal
31
}
32
33
class AMDModuleImporter {
34
public static INSTANCE = new AMDModuleImporter();
35
36
private readonly _isWebWorker = (typeof self === 'object' && self.constructor && self.constructor.name === 'DedicatedWorkerGlobalScope');
37
private readonly _isRenderer = typeof document === 'object';
38
39
private readonly _defineCalls: DefineCall[] = [];
40
private _state = AMDModuleImporterState.Uninitialized;
41
private _amdPolicy: Pick<TrustedTypePolicy<{
42
createScriptURL(value: string): string;
43
}>, 'name' | 'createScriptURL'> | undefined;
44
45
constructor() { }
46
47
private _initialize(): void {
48
if (this._state === AMDModuleImporterState.Uninitialized) {
49
if (globalThis.define) {
50
this._state = AMDModuleImporterState.InitializedExternal;
51
return;
52
}
53
} else {
54
return;
55
}
56
57
this._state = AMDModuleImporterState.InitializedInternal;
58
59
globalThis.define = (id: any, dependencies: any, callback: any) => {
60
if (typeof id !== 'string') {
61
callback = dependencies;
62
dependencies = id;
63
id = null;
64
}
65
if (typeof dependencies !== 'object' || !Array.isArray(dependencies)) {
66
callback = dependencies;
67
dependencies = null;
68
}
69
// if (!dependencies) {
70
// dependencies = ['require', 'exports', 'module'];
71
// }
72
this._defineCalls.push(new DefineCall(id, dependencies, callback));
73
};
74
75
globalThis.define.amd = true;
76
77
if (this._isRenderer) {
78
this._amdPolicy = globalThis._VSCODE_WEB_PACKAGE_TTP ?? window.trustedTypes?.createPolicy('amdLoader', {
79
createScriptURL(value: any) {
80
if (value.startsWith(window.location.origin)) {
81
return value;
82
}
83
if (value.startsWith(`${Schemas.vscodeFileResource}://${VSCODE_AUTHORITY}`)) {
84
return value;
85
}
86
throw new Error(`[trusted_script_src] Invalid script url: ${value}`);
87
}
88
});
89
} else if (this._isWebWorker) {
90
this._amdPolicy = globalThis._VSCODE_WEB_PACKAGE_TTP ?? globalThis.trustedTypes?.createPolicy('amdLoader', {
91
createScriptURL(value: string) {
92
return value;
93
}
94
});
95
}
96
}
97
98
public async load<T>(scriptSrc: string): Promise<T> {
99
this._initialize();
100
101
if (this._state === AMDModuleImporterState.InitializedExternal) {
102
return new Promise<T>(resolve => {
103
const tmpModuleId = generateUuid();
104
globalThis.define(tmpModuleId, [scriptSrc], function (moduleResult: T) {
105
resolve(moduleResult);
106
});
107
});
108
}
109
110
const defineCall = await (this._isWebWorker ? this._workerLoadScript(scriptSrc) : this._isRenderer ? this._rendererLoadScript(scriptSrc) : this._nodeJSLoadScript(scriptSrc));
111
if (!defineCall) {
112
console.warn(`Did not receive a define call from script ${scriptSrc}`);
113
return <T>undefined;
114
}
115
// TODO@esm require, module
116
const exports = {};
117
const dependencyObjs: any[] = [];
118
const dependencyModules: string[] = [];
119
120
if (Array.isArray(defineCall.dependencies)) {
121
122
for (const mod of defineCall.dependencies) {
123
if (mod === 'exports') {
124
dependencyObjs.push(exports);
125
} else {
126
dependencyModules.push(mod);
127
}
128
}
129
}
130
131
if (dependencyModules.length > 0) {
132
throw new Error(`Cannot resolve dependencies for script ${scriptSrc}. The dependencies are: ${dependencyModules.join(', ')}`);
133
}
134
if (typeof defineCall.callback === 'function') {
135
return defineCall.callback(...dependencyObjs) ?? exports;
136
} else {
137
return defineCall.callback;
138
}
139
}
140
141
private _rendererLoadScript(scriptSrc: string): Promise<DefineCall | undefined> {
142
return new Promise<DefineCall | undefined>((resolve, reject) => {
143
const scriptElement = document.createElement('script');
144
scriptElement.setAttribute('async', 'async');
145
scriptElement.setAttribute('type', 'text/javascript');
146
147
const unbind = () => {
148
scriptElement.removeEventListener('load', loadEventListener);
149
scriptElement.removeEventListener('error', errorEventListener);
150
};
151
152
const loadEventListener = (e: any) => {
153
unbind();
154
resolve(this._defineCalls.pop());
155
};
156
157
const errorEventListener = (e: any) => {
158
unbind();
159
reject(e);
160
};
161
162
scriptElement.addEventListener('load', loadEventListener);
163
scriptElement.addEventListener('error', errorEventListener);
164
if (this._amdPolicy) {
165
scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as unknown as string;
166
}
167
scriptElement.setAttribute('src', scriptSrc);
168
window.document.getElementsByTagName('head')[0].appendChild(scriptElement);
169
});
170
}
171
172
private async _workerLoadScript(scriptSrc: string): Promise<DefineCall | undefined> {
173
if (this._amdPolicy) {
174
scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as unknown as string;
175
}
176
await import(scriptSrc);
177
return this._defineCalls.pop();
178
}
179
180
private async _nodeJSLoadScript(scriptSrc: string): Promise<DefineCall | undefined> {
181
try {
182
const fs = (await import(`${'fs'}`)).default;
183
const vm = (await import(`${'vm'}`)).default;
184
const module = (await import(`${'module'}`)).default;
185
186
const filePath = URI.parse(scriptSrc).fsPath;
187
const content = fs.readFileSync(filePath).toString();
188
const scriptSource = module.wrap(content.replace(/^#!.*/, ''));
189
const script = new vm.Script(scriptSource);
190
const compileWrapper = script.runInThisContext();
191
compileWrapper.apply();
192
return this._defineCalls.pop();
193
} catch (error) {
194
throw error;
195
}
196
}
197
}
198
199
const cache = new Map<string, Promise<any>>();
200
201
/**
202
* Utility for importing an AMD node module. This util supports AMD and ESM contexts and should be used while the ESM adoption
203
* is on its way.
204
*
205
* e.g. pass in `vscode-textmate/release/main.js`
206
*/
207
export async function importAMDNodeModule<T>(nodeModuleName: string, pathInsideNodeModule: string, isBuilt?: boolean): Promise<T> {
208
if (isBuilt === undefined) {
209
const product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration;
210
isBuilt = Boolean((product ?? globalThis.vscode?.context?.configuration()?.product)?.commit);
211
}
212
213
const nodeModulePath = pathInsideNodeModule ? `${nodeModuleName}/${pathInsideNodeModule}` : nodeModuleName;
214
if (cache.has(nodeModulePath)) {
215
return cache.get(nodeModulePath)!;
216
}
217
let scriptSrc: string;
218
if (/^\w[\w\d+.-]*:\/\//.test(nodeModulePath)) {
219
// looks like a URL
220
// bit of a special case for: src/vs/workbench/services/languageDetection/browser/languageDetectionWebWorker.ts
221
scriptSrc = nodeModulePath;
222
} else {
223
const useASAR = (canASAR && isBuilt && !platform.isWeb);
224
const actualNodeModulesPath = (useASAR ? nodeModulesAsarPath : nodeModulesPath);
225
const resourcePath: AppResourcePath = `${actualNodeModulesPath}/${nodeModulePath}`;
226
scriptSrc = FileAccess.asBrowserUri(resourcePath).toString(true);
227
}
228
const result = AMDModuleImporter.INSTANCE.load<T>(scriptSrc);
229
cache.set(nodeModulePath, result);
230
return result;
231
}
232
233
export function resolveAmdNodeModulePath(nodeModuleName: string, pathInsideNodeModule: string): string {
234
const product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration;
235
const isBuilt = Boolean((product ?? globalThis.vscode?.context?.configuration()?.product)?.commit);
236
const useASAR = (canASAR && isBuilt && !platform.isWeb);
237
238
const nodeModulePath = `${nodeModuleName}/${pathInsideNodeModule}`;
239
const actualNodeModulesPath = (useASAR ? nodeModulesAsarPath : nodeModulesPath);
240
const resourcePath: AppResourcePath = `${actualNodeModulesPath}/${nodeModulePath}`;
241
return FileAccess.asBrowserUri(resourcePath).toString(true);
242
}
243
244