mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 03:57:41 -05:00
Add /~ as a layer template, adopt it, simplify and align code import rules (#140857)
This commit is contained in:
1072
.eslintrc.json
1072
.eslintrc.json
File diff suppressed because it is too large
Load Diff
@@ -29,16 +29,8 @@ module.exports = new class {
|
||||
}
|
||||
create(context) {
|
||||
const options = context.options;
|
||||
const { configs, warnings } = this._processOptions(options);
|
||||
const configs = this._processOptions(options);
|
||||
const relativeFilename = getRelativeFilename(context);
|
||||
if (warnings.length > 0) {
|
||||
// configuration warnings
|
||||
context.report({
|
||||
loc: { line: 1, column: 0 },
|
||||
message: warnings.join('\n')
|
||||
});
|
||||
return {};
|
||||
}
|
||||
for (const config of configs) {
|
||||
if (minimatch(relativeFilename, config.target)) {
|
||||
return (0, utils_1.createImportRuleListener)((node, value) => this._checkImport(context, config, node, value));
|
||||
@@ -54,24 +46,104 @@ module.exports = new class {
|
||||
if (this._optionsCache.has(options)) {
|
||||
return this._optionsCache.get(options);
|
||||
}
|
||||
function orSegment(variants) {
|
||||
return (variants.length === 1 ? variants[0] : `{${variants.join(',')}}`);
|
||||
}
|
||||
const layerRules = [
|
||||
{ layer: 'common', deps: orSegment(['common']) },
|
||||
{ layer: 'worker', deps: orSegment(['common', 'worker']) },
|
||||
{ layer: 'browser', deps: orSegment(['common', 'browser']), isBrowser: true },
|
||||
{ layer: 'electron-sandbox', deps: orSegment(['common', 'browser', 'electron-sandbox']), isBrowser: true },
|
||||
{ layer: 'node', deps: orSegment(['common', 'node']), isNode: true },
|
||||
{ layer: 'electron-browser', deps: orSegment(['common', 'browser', 'node', 'electron-sandbox', 'electron-browser']), isBrowser: true, isNode: true },
|
||||
{ layer: 'electron-main', deps: orSegment(['common', 'node', 'electron-main']), isNode: true },
|
||||
];
|
||||
function findLayer(layer) {
|
||||
for (const layerRule of layerRules) {
|
||||
if (layerRule.layer === layer) {
|
||||
return layerRule;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function generateConfig(layerRule, target, rawRestrictions) {
|
||||
const restrictions = [];
|
||||
const testRestrictions = ['assert', 'sinon', 'sinon-test'];
|
||||
if (layerRule.isBrowser) {
|
||||
restrictions.push('vs/css!./**/*');
|
||||
}
|
||||
if (layerRule.isNode) {
|
||||
restrictions.push('@microsoft/*', '@vscode/*', '@parcel/*', '*');
|
||||
}
|
||||
for (const rawRestriction of rawRestrictions) {
|
||||
let importPattern;
|
||||
let when = undefined;
|
||||
if (typeof rawRestriction === 'string') {
|
||||
importPattern = rawRestriction;
|
||||
}
|
||||
else {
|
||||
importPattern = rawRestriction.pattern;
|
||||
when = rawRestriction.when;
|
||||
}
|
||||
if (typeof when === 'undefined'
|
||||
|| (when === 'hasBrowser' && layerRule.isBrowser)
|
||||
|| (when === 'hasNode' && layerRule.isNode)) {
|
||||
restrictions.push(importPattern.replace(/\/\~$/, `/${layerRule.deps}/**`));
|
||||
testRestrictions.push(importPattern.replace(/\/\~$/, `/test/${layerRule.deps}/**`));
|
||||
}
|
||||
else if (when === 'test') {
|
||||
testRestrictions.push(importPattern.replace(/\/\~$/, `/${layerRule.deps}/**`));
|
||||
testRestrictions.push(importPattern.replace(/\/\~$/, `/test/${layerRule.deps}/**`));
|
||||
}
|
||||
}
|
||||
testRestrictions.push(...restrictions);
|
||||
return [
|
||||
{
|
||||
target: target.replace(/\/\~$/, `/${layerRule.layer}/**`),
|
||||
restrictions: restrictions
|
||||
},
|
||||
{
|
||||
target: target.replace(/\/\~$/, `/test/${layerRule.layer}/**`),
|
||||
restrictions: testRestrictions
|
||||
}
|
||||
];
|
||||
}
|
||||
const configs = [];
|
||||
const warnings = [];
|
||||
for (const option of options) {
|
||||
const target = option.target;
|
||||
const restrictions = (typeof option.restrictions === 'string' ? [option.restrictions] : option.restrictions.slice(0));
|
||||
if (/^src\/vs\/.*\/\*\*/.test(target)) {
|
||||
const amdTarget = target.substring('src/'.length);
|
||||
// Allow importing itself
|
||||
if (restrictions.includes(amdTarget)) {
|
||||
warnings.push(`target ${target}: '${amdTarget}' is automatically included in restrictions.`);
|
||||
}
|
||||
restrictions.push(amdTarget);
|
||||
const targetIsVS = /^src\/vs\//.test(target);
|
||||
const restrictions = (typeof option.restrictions === 'string' ? [option.restrictions] : option.restrictions).slice(0);
|
||||
if (targetIsVS) {
|
||||
// Always add "vs/nls"
|
||||
restrictions.push('vs/nls');
|
||||
}
|
||||
if (targetIsVS && option.layer) {
|
||||
// single layer => simple substitution for /~
|
||||
const layerRule = findLayer(option.layer);
|
||||
if (layerRule) {
|
||||
const [config, testConfig] = generateConfig(layerRule, target, restrictions);
|
||||
if (option.test) {
|
||||
configs.push(testConfig);
|
||||
}
|
||||
else {
|
||||
configs.push(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targetIsVS && /\/\~$/.test(target)) {
|
||||
// generate all layers
|
||||
for (const layerRule of layerRules) {
|
||||
const [config, testConfig] = generateConfig(layerRule, target, restrictions);
|
||||
configs.push(config);
|
||||
configs.push(testConfig);
|
||||
}
|
||||
}
|
||||
else {
|
||||
configs.push({ target, restrictions: restrictions.filter(r => typeof r === 'string') });
|
||||
}
|
||||
configs.push({ target, restrictions });
|
||||
}
|
||||
const result = { configs, warnings };
|
||||
this._optionsCache.set(options, result);
|
||||
return result;
|
||||
this._optionsCache.set(options, configs);
|
||||
return configs;
|
||||
}
|
||||
_checkImport(context, config, node, importPath) {
|
||||
// resolve relative paths
|
||||
|
||||
@@ -11,9 +11,16 @@ import { createImportRuleListener } from './utils';
|
||||
|
||||
const REPO_ROOT = path.normalize(path.join(__dirname, '../../../'));
|
||||
|
||||
interface ConditionalPattern {
|
||||
when?: 'hasBrowser' | 'hasNode' | 'test';
|
||||
pattern: string;
|
||||
}
|
||||
|
||||
interface RawImportPatternsConfig {
|
||||
target: string;
|
||||
restrictions: string | string[];
|
||||
layer?: 'common' | 'worker' | 'browser' | 'electron-sandbox' | 'node' | 'electron-browser' | 'electron-main';
|
||||
test?: boolean;
|
||||
restrictions: string | (string | ConditionalPattern)[];
|
||||
}
|
||||
|
||||
interface ImportPatternsConfig {
|
||||
@@ -35,18 +42,9 @@ export = new class implements eslint.Rule.RuleModule {
|
||||
|
||||
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
|
||||
const options = <RawImportPatternsConfig[]>context.options;
|
||||
const { configs, warnings } = this._processOptions(options);
|
||||
const configs = this._processOptions(options);
|
||||
const relativeFilename = getRelativeFilename(context);
|
||||
|
||||
if (warnings.length > 0) {
|
||||
// configuration warnings
|
||||
context.report({
|
||||
loc: { line: 1, column: 0 },
|
||||
message: warnings.join('\n')
|
||||
});
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const config of configs) {
|
||||
if (minimatch(relativeFilename, config.target)) {
|
||||
return createImportRuleListener((node, value) => this._checkImport(context, config, node, value));
|
||||
@@ -61,30 +59,127 @@ export = new class implements eslint.Rule.RuleModule {
|
||||
return {};
|
||||
}
|
||||
|
||||
private _optionsCache = new WeakMap<RawImportPatternsConfig[], { configs: ImportPatternsConfig[]; warnings: string[]; }>();
|
||||
private _optionsCache = new WeakMap<RawImportPatternsConfig[], ImportPatternsConfig[]>();
|
||||
|
||||
private _processOptions(options: RawImportPatternsConfig[]): { configs: ImportPatternsConfig[]; warnings: string[]; } {
|
||||
private _processOptions(options: RawImportPatternsConfig[]): ImportPatternsConfig[] {
|
||||
if (this._optionsCache.has(options)) {
|
||||
return this._optionsCache.get(options)!;
|
||||
}
|
||||
|
||||
type Layer = 'common' | 'worker' | 'browser' | 'electron-sandbox' | 'node' | 'electron-browser' | 'electron-main';
|
||||
|
||||
interface ILayerRule {
|
||||
layer: Layer;
|
||||
deps: string;
|
||||
isBrowser?: boolean;
|
||||
isNode?: boolean;
|
||||
}
|
||||
|
||||
function orSegment(variants: Layer[]): string {
|
||||
return (variants.length === 1 ? variants[0] : `{${variants.join(',')}}`);
|
||||
}
|
||||
|
||||
const layerRules: ILayerRule[] = [
|
||||
{ layer: 'common', deps: orSegment(['common']) },
|
||||
{ layer: 'worker', deps: orSegment(['common', 'worker']) },
|
||||
{ layer: 'browser', deps: orSegment(['common', 'browser']), isBrowser: true },
|
||||
{ layer: 'electron-sandbox', deps: orSegment(['common', 'browser', 'electron-sandbox']), isBrowser: true },
|
||||
{ layer: 'node', deps: orSegment(['common', 'node']), isNode: true },
|
||||
{ layer: 'electron-browser', deps: orSegment(['common', 'browser', 'node', 'electron-sandbox', 'electron-browser']), isBrowser: true, isNode: true },
|
||||
{ layer: 'electron-main', deps: orSegment(['common', 'node', 'electron-main']), isNode: true },
|
||||
];
|
||||
|
||||
function findLayer(layer: Layer): ILayerRule | null {
|
||||
for (const layerRule of layerRules) {
|
||||
if (layerRule.layer === layer) {
|
||||
return layerRule;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function generateConfig(layerRule: ILayerRule, target: string, rawRestrictions: (string | ConditionalPattern)[]): [ImportPatternsConfig, ImportPatternsConfig] {
|
||||
const restrictions: string[] = [];
|
||||
const testRestrictions: string[] = ['assert', 'sinon', 'sinon-test'];
|
||||
|
||||
if (layerRule.isBrowser) {
|
||||
restrictions.push('vs/css!./**/*');
|
||||
}
|
||||
|
||||
if (layerRule.isNode) {
|
||||
restrictions.push('@microsoft/*', '@vscode/*', '@parcel/*', '*');
|
||||
}
|
||||
|
||||
for (const rawRestriction of rawRestrictions) {
|
||||
let importPattern: string;
|
||||
let when: 'hasBrowser' | 'hasNode' | 'test' | undefined = undefined;
|
||||
if (typeof rawRestriction === 'string') {
|
||||
importPattern = rawRestriction;
|
||||
} else {
|
||||
importPattern = rawRestriction.pattern;
|
||||
when = rawRestriction.when;
|
||||
}
|
||||
if (typeof when === 'undefined'
|
||||
|| (when === 'hasBrowser' && layerRule.isBrowser)
|
||||
|| (when === 'hasNode' && layerRule.isNode)
|
||||
) {
|
||||
restrictions.push(importPattern.replace(/\/\~$/, `/${layerRule.deps}/**`));
|
||||
testRestrictions.push(importPattern.replace(/\/\~$/, `/test/${layerRule.deps}/**`));
|
||||
} else if (when === 'test') {
|
||||
testRestrictions.push(importPattern.replace(/\/\~$/, `/${layerRule.deps}/**`));
|
||||
testRestrictions.push(importPattern.replace(/\/\~$/, `/test/${layerRule.deps}/**`));
|
||||
}
|
||||
}
|
||||
|
||||
testRestrictions.push(...restrictions);
|
||||
|
||||
return [
|
||||
{
|
||||
target: target.replace(/\/\~$/, `/${layerRule.layer}/**`),
|
||||
restrictions: restrictions
|
||||
},
|
||||
{
|
||||
target: target.replace(/\/\~$/, `/test/${layerRule.layer}/**`),
|
||||
restrictions: testRestrictions
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
const configs: ImportPatternsConfig[] = [];
|
||||
const warnings: string[] = [];
|
||||
for (const option of options) {
|
||||
const target = option.target;
|
||||
const restrictions = (typeof option.restrictions === 'string' ? [option.restrictions] : option.restrictions.slice(0));
|
||||
if (/^src\/vs\/.*\/\*\*/.test(target)) {
|
||||
const amdTarget = target.substring('src/'.length);
|
||||
// Allow importing itself
|
||||
if (restrictions.includes(amdTarget)) {
|
||||
warnings.push(`target ${target}: '${amdTarget}' is automatically included in restrictions.`);
|
||||
}
|
||||
restrictions.push(amdTarget);
|
||||
const targetIsVS = /^src\/vs\//.test(target);
|
||||
const restrictions = (typeof option.restrictions === 'string' ? [option.restrictions] : option.restrictions).slice(0);
|
||||
|
||||
if (targetIsVS) {
|
||||
// Always add "vs/nls"
|
||||
restrictions.push('vs/nls');
|
||||
}
|
||||
|
||||
if (targetIsVS && option.layer) {
|
||||
// single layer => simple substitution for /~
|
||||
const layerRule = findLayer(option.layer);
|
||||
if (layerRule) {
|
||||
const [config, testConfig] = generateConfig(layerRule, target, restrictions);
|
||||
if (option.test) {
|
||||
configs.push(testConfig);
|
||||
} else {
|
||||
configs.push(config);
|
||||
}
|
||||
}
|
||||
} else if (targetIsVS && /\/\~$/.test(target)) {
|
||||
// generate all layers
|
||||
for (const layerRule of layerRules) {
|
||||
const [config, testConfig] = generateConfig(layerRule, target, restrictions);
|
||||
configs.push(config);
|
||||
configs.push(testConfig);
|
||||
}
|
||||
} else {
|
||||
configs.push({ target, restrictions: <string[]>restrictions.filter(r => typeof r === 'string') });
|
||||
}
|
||||
configs.push({ target, restrictions });
|
||||
}
|
||||
const result = { configs, warnings };
|
||||
this._optionsCache.set(options, result);
|
||||
return result;
|
||||
this._optionsCache.set(options, configs);
|
||||
return configs;
|
||||
}
|
||||
|
||||
private _checkImport(context: eslint.Rule.RuleContext, config: ImportPatternsConfig, node: TSESTree.Node, importPath: string) {
|
||||
|
||||
@@ -16,6 +16,8 @@ import { createRandomIPCHandle, createStaticIPCHandle, NodeSocket, WebSocketNode
|
||||
import { flakySuite } from 'vs/base/test/common/testUtils';
|
||||
import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler';
|
||||
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import product from 'vs/platform/product/common/product';
|
||||
|
||||
class MessageStream extends Disposable {
|
||||
|
||||
@@ -8,6 +8,8 @@ import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/lis
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { QuickInputController } from 'vs/base/parts/quickinput/browser/quickInput';
|
||||
import { IQuickPick, IQuickPickItem } from 'vs/base/parts/quickinput/common/quickInput';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import { IWorkbenchListOptions } from 'vs/platform/list/browser/listService';
|
||||
|
||||
// Simple promisify of setTimeout
|
||||
@@ -7,7 +7,11 @@ import { flatten } from 'vs/base/common/arrays';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import { codeActionCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Extensions, IConfigurationNode, IConfigurationRegistry, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
|
||||
@@ -9,6 +9,8 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/languages';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
|
||||
@@ -29,6 +29,8 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
|
||||
import { isStringArray } from 'vs/base/common/types';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService';
|
||||
|
||||
namespace snippetExt {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestItemImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi';
|
||||
import { MainThreadTestCollection } from 'vs/workbench/contrib/testing/common/mainThreadTestCollection';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import { TestSingleUseCollection } from 'vs/workbench/contrib/testing/test/common/ownedTestCollection';
|
||||
|
||||
export * as Convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
// TODO@layers
|
||||
// eslint-disable-next-line code-import-patterns
|
||||
import type { IWorkbenchConstructionOptions as IWorkbenchOptions } from 'vs/workbench/workbench.web.api';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Readable, ReadableStream, newWriteableStream, listenStream } from 'vs/base/common/stream';
|
||||
import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer';
|
||||
import { IDisposable } from 'vs/workbench/workbench.web.api';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export const UTF8 = 'utf8';
|
||||
export const UTF8_with_bom = 'utf8bom';
|
||||
|
||||
Reference in New Issue
Block a user