mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 03:54:24 +01:00
@@ -19,16 +19,20 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||||||
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||||
import { platform } from 'vs/base/common/process';
|
import { platform } from 'vs/base/common/process';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
|
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||||
|
|
||||||
|
|
||||||
interface LoadFunction {
|
interface LoadFunction {
|
||||||
(request: string): any;
|
(request: string): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface INodeModuleFactory {
|
interface IAlternativeModuleProvider {
|
||||||
|
alternativeModuleName(name: string): string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface INodeModuleFactory extends Partial<IAlternativeModuleProvider> {
|
||||||
readonly nodeModuleName: string | string[];
|
readonly nodeModuleName: string | string[];
|
||||||
load(request: string, parent: URI, original: LoadFunction): any;
|
load(request: string, parent: URI, original: LoadFunction): any;
|
||||||
alternativeModuleName?(name: string): string | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class RequireInterceptor {
|
export abstract class RequireInterceptor {
|
||||||
@@ -60,6 +64,7 @@ export abstract class RequireInterceptor {
|
|||||||
|
|
||||||
this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider, this._logService));
|
this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider, this._logService));
|
||||||
this.register(this._instaService.createInstance(KeytarNodeModuleFactory, extensionPaths));
|
this.register(this._instaService.createInstance(KeytarNodeModuleFactory, extensionPaths));
|
||||||
|
this.register(this._instaService.createInstance(NodeModuleAliasingModuleFactory));
|
||||||
if (this._initData.remote.isRemote) {
|
if (this._initData.remote.isRemote) {
|
||||||
this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme));
|
this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme));
|
||||||
}
|
}
|
||||||
@@ -67,7 +72,8 @@ export abstract class RequireInterceptor {
|
|||||||
|
|
||||||
protected abstract _installInterceptor(): void;
|
protected abstract _installInterceptor(): void;
|
||||||
|
|
||||||
public register(interceptor: INodeModuleFactory): void {
|
public register(interceptor: INodeModuleFactory | IAlternativeModuleProvider): void {
|
||||||
|
if ('nodeModuleName' in interceptor) {
|
||||||
if (Array.isArray(interceptor.nodeModuleName)) {
|
if (Array.isArray(interceptor.nodeModuleName)) {
|
||||||
for (let moduleName of interceptor.nodeModuleName) {
|
for (let moduleName of interceptor.nodeModuleName) {
|
||||||
this._factories.set(moduleName, interceptor);
|
this._factories.set(moduleName, interceptor);
|
||||||
@@ -75,6 +81,8 @@ export abstract class RequireInterceptor {
|
|||||||
} else {
|
} else {
|
||||||
this._factories.set(interceptor.nodeModuleName, interceptor);
|
this._factories.set(interceptor.nodeModuleName, interceptor);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof interceptor.alternativeModuleName === 'function') {
|
if (typeof interceptor.alternativeModuleName === 'function') {
|
||||||
this._alternatives.push((moduleName) => {
|
this._alternatives.push((moduleName) => {
|
||||||
return interceptor.alternativeModuleName!(moduleName);
|
return interceptor.alternativeModuleName!(moduleName);
|
||||||
@@ -83,6 +91,60 @@ export abstract class RequireInterceptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region --- module renames
|
||||||
|
|
||||||
|
class NodeModuleAliasingModuleFactory implements IAlternativeModuleProvider {
|
||||||
|
/**
|
||||||
|
* Map of aliased internal node_modules, used to allow for modules to be
|
||||||
|
* renamed without breaking extensions. In the form "original -> new name".
|
||||||
|
*/
|
||||||
|
private static readonly aliased: ReadonlyMap<string, string> = new Map([
|
||||||
|
['vscode-ripgrep', '@vscode/ripgrep'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
private readonly re?: RegExp;
|
||||||
|
|
||||||
|
constructor(@IExtHostInitDataService initData: IExtHostInitDataService) {
|
||||||
|
if (initData.environment.appRoot && NodeModuleAliasingModuleFactory.aliased.size) {
|
||||||
|
const root = escapeRegExpCharacters(this.forceForwardSlashes(initData.environment.appRoot.fsPath));
|
||||||
|
// decompose ${appRoot}/node_modules/foo/bin to ['${appRoot}/node_modules/', 'foo', '/bin'],
|
||||||
|
// and likewise the more complex form ${appRoot}/node_modules.asar.unpacked/@vcode/foo/bin
|
||||||
|
// to ['${appRoot}/node_modules.asar.unpacked/',' @vscode/foo', '/bin'].
|
||||||
|
const npmIdChrs = `[a-z0-9_.-]`;
|
||||||
|
const npmModuleName = `@${npmIdChrs}+\\/${npmIdChrs}+|${npmIdChrs}+`;
|
||||||
|
const moduleFolders = 'node_modules|node_modules\\.asar(?:\\.unpacked)?';
|
||||||
|
this.re = new RegExp(`^(${root}/${moduleFolders}\\/)(${npmModuleName})(.*)$`, 'i');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public alternativeModuleName(name: string): string | undefined {
|
||||||
|
if (!this.re) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = this.re.exec(this.forceForwardSlashes(name));
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, prefix, moduleName, suffix] = result;
|
||||||
|
const dealiased = NodeModuleAliasingModuleFactory.aliased.get(moduleName);
|
||||||
|
if (dealiased === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(`${moduleName} as been renamed to ${dealiased}, please update your imports`);
|
||||||
|
|
||||||
|
return prefix + dealiased + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private forceForwardSlashes(str: string) {
|
||||||
|
return str.replace(/\\/g, '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region --- vscode-module
|
//#region --- vscode-module
|
||||||
|
|
||||||
class VSCodeNodeModuleFactory implements INodeModuleFactory {
|
class VSCodeNodeModuleFactory implements INodeModuleFactory {
|
||||||
|
|||||||
@@ -23,8 +23,25 @@ class NodeModuleRequireInterceptor extends RequireInterceptor {
|
|||||||
protected _installInterceptor(): void {
|
protected _installInterceptor(): void {
|
||||||
const that = this;
|
const that = this;
|
||||||
const node_module = <any>require.__$__nodeRequire('module');
|
const node_module = <any>require.__$__nodeRequire('module');
|
||||||
const original = node_module._load;
|
const originalLoad = node_module._load;
|
||||||
node_module._load = function load(request: string, parent: { filename: string; }, isMain: boolean) {
|
node_module._load = function load(request: string, parent: { filename: string; }, isMain: boolean) {
|
||||||
|
request = applyAlternatives(request);
|
||||||
|
if (!that._factories.has(request)) {
|
||||||
|
return originalLoad.apply(this, arguments);
|
||||||
|
}
|
||||||
|
return that._factories.get(request)!.load(
|
||||||
|
request,
|
||||||
|
URI.file(realpathSync(parent.filename)),
|
||||||
|
request => originalLoad.apply(this, [request, parent, isMain])
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const originalLookup = node_module._resolveLookupPaths;
|
||||||
|
node_module._resolveLookupPaths = (request: string, parent: unknown) => {
|
||||||
|
return originalLookup.call(this, applyAlternatives(request), parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyAlternatives = (request: string) => {
|
||||||
for (let alternativeModuleName of that._alternatives) {
|
for (let alternativeModuleName of that._alternatives) {
|
||||||
let alternative = alternativeModuleName(request);
|
let alternative = alternativeModuleName(request);
|
||||||
if (alternative) {
|
if (alternative) {
|
||||||
@@ -32,14 +49,7 @@ class NodeModuleRequireInterceptor extends RequireInterceptor {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!that._factories.has(request)) {
|
return request;
|
||||||
return original.apply(this, arguments);
|
|
||||||
}
|
|
||||||
return that._factories.get(request)!.load(
|
|
||||||
request,
|
|
||||||
URI.file(realpathSync(parent.filename)),
|
|
||||||
request => original.apply(this, [request, parent, isMain])
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user