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