diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55415410f7c..e9a2a3e71bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,8 @@ jobs: name: Run TSLint Checks - run: yarn monaco-compile-check name: Run Monaco Editor Checks + - run: yarn valid-globals-check + name: Run Valid Globals Checks - run: yarn compile name: Compile Sources - run: yarn download-builtin-extensions @@ -73,6 +75,8 @@ jobs: name: Run TSLint Checks - run: yarn monaco-compile-check name: Run Monaco Editor Checks + - run: yarn valid-globals-check + name: Run Valid Globals Checks - run: yarn compile name: Compile Sources - run: yarn download-builtin-extensions @@ -102,6 +106,8 @@ jobs: name: Run TSLint Checks - run: yarn monaco-compile-check name: Run Monaco Editor Checks + - run: yarn valid-globals-check + name: Run Valid Globals Checks - run: yarn compile name: Compile Sources - run: yarn download-builtin-extensions diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index c98aa3770de..1609e4a0027 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -32,6 +32,9 @@ steps: - script: | yarn monaco-compile-check displayName: Run Monaco Editor Checks +- script: | + yarn valid-globals-check + displayName: Run Valid Globals Checks - script: | yarn compile displayName: Compile Sources diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index 0f611bd439d..649c12593da 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -40,6 +40,9 @@ steps: - script: | yarn monaco-compile-check displayName: Run Monaco Editor Checks +- script: | + yarn valid-globals-check + displayName: Run Valid Globals Checks - script: | yarn compile displayName: Compile Sources diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 8029f8a5661..9ec01fd5db1 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -91,7 +91,8 @@ steps: yarn gulp hygiene --skip-tslint yarn gulp tslint yarn monaco-compile-check - displayName: Run hygiene, tslint and monaco compile checks + yarn valid-globals-check + displayName: Run hygiene, tslint, monaco compile & valid globals checks condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index 9351bafa0bd..050a967629b 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -37,6 +37,9 @@ steps: - powershell: | yarn monaco-compile-check displayName: Run Monaco Editor Checks +- script: | + yarn valid-globals-check + displayName: Run Valid Globals Checks - powershell: | yarn compile displayName: Compile Sources diff --git a/build/lib/globalsLinter.js b/build/lib/globalsLinter.js new file mode 100644 index 00000000000..cfcb05c2689 --- /dev/null +++ b/build/lib/globalsLinter.js @@ -0,0 +1,176 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +const ts = require("typescript"); +const fs_1 = require("fs"); +const path_1 = require("path"); +const minimatch_1 = require("minimatch"); +// +// ############################################################################################# +// +// A custom typescript linter for the specific task of detecting the use of certain globals in a +// layer that does not allow the use. For example: +// - using DOM globals in common/node/electron-main layer (e.g. HTMLElement) +// - using node.js globals in common/browser layer (e.g. process) +// +// Make changes to below RULES to lift certain files from these checks only if absolutely needed +// +// ############################################################################################# +// +const RULES = { + "no-nodejs-globals": [ + { + "target": "**/vs/**/test/{common,browser}/**", + "allowed": [ + "process", + "Buffer", + "__filename", + "__dirname" + ] + }, + { + "target": "**/vs/workbench/api/common/extHostExtensionService.ts", + "allowed": [ + "global" // -> safe access to 'global' + ] + }, + { + "target": "**/vs/**/{common,browser}/**", + "allowed": [ /* none */] + } + ], + "no-dom-globals": [ + { + "target": "**/vs/base/parts/quickopen/common/quickOpen.ts", + "allowed": [ + "HTMLElement" // quick open will be replaced with a different widget soon + ] + }, + { + "target": "**/vs/**/test/{common,node,electron-main}/**", + "allowed": [ + "document", + "HTMLElement", + "createElement" + ] + }, + { + "target": "**/vs/**/{common,node,electron-main}/**", + "allowed": [ /* none */] + } + ] +}; +const TS_CONFIG_PATH = path_1.join(__dirname, '../../', 'src', 'tsconfig.json'); +const DOM_GLOBALS_DEFINITION = 'lib.dom.d.ts'; +const DISALLOWED_DOM_GLOBALS = [ + "window", + "document", + "HTMLElement", + "createElement" +]; +const NODE_GLOBALS_DEFINITION = '@types/node'; +const DISALLOWED_NODE_GLOBALS = [ + // https://nodejs.org/api/globals.html#globals_global_objects + "NodeJS", + "Buffer", + "__dirname", + "__filename", + "clearImmediate", + "exports", + "global", + "module", + "process", + "setImmediate" +]; +let hasErrors = false; +function checkFile(program, sourceFile, rule) { + checkNode(sourceFile); + function checkNode(node) { + if (node.kind !== ts.SyntaxKind.Identifier) { + return ts.forEachChild(node, checkNode); // recurse down + } + const text = node.getText(sourceFile); + if (!rule.disallowedGlobals.some(disallowedGlobal => disallowedGlobal === text)) { + return; // only if disallowed + } + if (rule.allowedGlobals.some(allowed => allowed === text)) { + return; // override + } + const checker = program.getTypeChecker(); + const symbol = checker.getSymbolAtLocation(node); + if (symbol) { + const declarations = symbol.declarations; + if (Array.isArray(declarations) && symbol.declarations.some(declaration => { + if (declaration) { + const parent = declaration.parent; + if (parent) { + const sourceFile = parent.getSourceFile(); + if (sourceFile) { + const fileName = sourceFile.fileName; + if (fileName && fileName.indexOf(rule.definition) >= 0) { + return true; + } + } + } + } + return false; + })) { + const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + console.log(`build/lib/globalsLinter.ts: Cannot use global '${text}' in ${sourceFile.fileName} (${line + 1},${character + 1})`); + hasErrors = true; + } + } + } +} +function createProgram(tsconfigPath) { + const tsConfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile); + const configHostParser = { fileExists: fs_1.existsSync, readDirectory: ts.sys.readDirectory, readFile: file => fs_1.readFileSync(file, "utf8"), useCaseSensitiveFileNames: process.platform === 'linux' }; + const tsConfigParsed = ts.parseJsonConfigFileContent(tsConfig.config, configHostParser, path_1.resolve(path_1.dirname(tsconfigPath)), { noEmit: true }); + const compilerHost = ts.createCompilerHost(tsConfigParsed.options, true); + return ts.createProgram(tsConfigParsed.fileNames, tsConfigParsed.options, compilerHost); +} +// +// Create program and start checking +// +const program = createProgram(TS_CONFIG_PATH); +for (const sourceFile of program.getSourceFiles()) { + let noDomGlobalsLinter = undefined; + let noNodeJSGlobalsLinter = undefined; + for (const rules of RULES["no-dom-globals"]) { + if (minimatch_1.match([sourceFile.fileName], rules.target).length > 0) { + noDomGlobalsLinter = { allowed: rules.allowed }; + break; + } + } + for (const rules of RULES["no-nodejs-globals"]) { + if (minimatch_1.match([sourceFile.fileName], rules.target).length > 0) { + noNodeJSGlobalsLinter = { allowed: rules.allowed }; + break; + } + } + if (!noDomGlobalsLinter && !noNodeJSGlobalsLinter) { + continue; // no rule to run + } + // No DOM Globals + if (noDomGlobalsLinter) { + checkFile(program, sourceFile, { + definition: DOM_GLOBALS_DEFINITION, + disallowedGlobals: DISALLOWED_DOM_GLOBALS, + allowedGlobals: noDomGlobalsLinter.allowed + }); + } + // No node.js Globals + if (noNodeJSGlobalsLinter) { + checkFile(program, sourceFile, { + definition: NODE_GLOBALS_DEFINITION, + disallowedGlobals: DISALLOWED_NODE_GLOBALS, + allowedGlobals: noNodeJSGlobalsLinter.allowed + }); + } +} +if (hasErrors) { + process.exit(1); +} diff --git a/build/lib/globalsLinter.ts b/build/lib/globalsLinter.ts new file mode 100644 index 00000000000..1f931ec6e0e --- /dev/null +++ b/build/lib/globalsLinter.ts @@ -0,0 +1,209 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as ts from "typescript"; +import { readFileSync, existsSync } from "fs"; +import { resolve, dirname, join } from "path"; +import { match } from 'minimatch'; + +// +// ############################################################################################# +// +// A custom typescript linter for the specific task of detecting the use of certain globals in a +// layer that does not allow the use. For example: +// - using DOM globals in common/node/electron-main layer (e.g. HTMLElement) +// - using node.js globals in common/browser layer (e.g. process) +// +// Make changes to below RULES to lift certain files from these checks only if absolutely needed +// +// ############################################################################################# +// + +const RULES = { + "no-nodejs-globals": [ + { + "target": "**/vs/**/test/{common,browser}/**", + "allowed": [ // -> less strict for test files + "process", + "Buffer", + "__filename", + "__dirname" + ] + }, + { + "target": "**/vs/workbench/api/common/extHostExtensionService.ts", + "allowed": [ + "global" // -> safe access to 'global' + ] + }, + { + "target": "**/vs/**/{common,browser}/**", + "allowed": [ /* none */] + } + ], + "no-dom-globals": [ + { + "target": "**/vs/base/parts/quickopen/common/quickOpen.ts", + "allowed": [ + "HTMLElement" // quick open will be replaced with a different widget soon + ] + }, + { + "target": "**/vs/**/test/{common,node,electron-main}/**", + "allowed": [ // -> less strict for test files + "document", + "HTMLElement", + "createElement" + ] + }, + { + "target": "**/vs/**/{common,node,electron-main}/**", + "allowed": [ /* none */] + } + ] +}; + +const TS_CONFIG_PATH = join(__dirname, '../../', 'src', 'tsconfig.json'); + +const DOM_GLOBALS_DEFINITION = 'lib.dom.d.ts'; + +const DISALLOWED_DOM_GLOBALS = [ + "window", + "document", + "HTMLElement", + "createElement" +]; + +const NODE_GLOBALS_DEFINITION = '@types/node'; + +const DISALLOWED_NODE_GLOBALS = [ + // https://nodejs.org/api/globals.html#globals_global_objects + "NodeJS", + "Buffer", + "__dirname", + "__filename", + "clearImmediate", + "exports", + "global", + "module", + "process", + "setImmediate" +]; + +interface IRule { + definition: string; + disallowedGlobals: string[]; + allowedGlobals: string[]; +} + +let hasErrors = false; + +function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) { + checkNode(sourceFile); + + function checkNode(node: ts.Node): void { + if (node.kind !== ts.SyntaxKind.Identifier) { + return ts.forEachChild(node, checkNode); // recurse down + } + + const text = node.getText(sourceFile); + + if (!rule.disallowedGlobals.some(disallowedGlobal => disallowedGlobal === text)) { + return; // only if disallowed + } + + if (rule.allowedGlobals.some(allowed => allowed === text)) { + return; // override + } + + const checker = program.getTypeChecker(); + const symbol = checker.getSymbolAtLocation(node); + if (symbol) { + const declarations = symbol.declarations; + if (Array.isArray(declarations) && symbol.declarations.some(declaration => { + if (declaration) { + const parent = declaration.parent; + if (parent) { + const sourceFile = parent.getSourceFile(); + if (sourceFile) { + const fileName = sourceFile.fileName; + if (fileName && fileName.indexOf(rule.definition) >= 0) { + return true; + } + } + } + } + + return false; + })) { + const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); + console.log(`build/lib/globalsLinter.ts: Cannot use global '${text}' in ${sourceFile.fileName} (${line + 1},${character + 1})`); + + hasErrors = true; + } + } + } +} + +function createProgram(tsconfigPath: string): ts.Program { + const tsConfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile); + + const configHostParser: ts.ParseConfigHost = { fileExists: existsSync, readDirectory: ts.sys.readDirectory, readFile: file => readFileSync(file, "utf8"), useCaseSensitiveFileNames: process.platform === 'linux' }; + const tsConfigParsed = ts.parseJsonConfigFileContent(tsConfig.config, configHostParser, resolve(dirname(tsconfigPath)), { noEmit: true }); + + const compilerHost = ts.createCompilerHost(tsConfigParsed.options, true); + + return ts.createProgram(tsConfigParsed.fileNames, tsConfigParsed.options, compilerHost); +} + +// +// Create program and start checking +// +const program = createProgram(TS_CONFIG_PATH); + +for (const sourceFile of program.getSourceFiles()) { + let noDomGlobalsLinter: { allowed: string[] } | undefined = undefined; + let noNodeJSGlobalsLinter: { allowed: string[] } | undefined = undefined; + + for (const rules of RULES["no-dom-globals"]) { + if (match([sourceFile.fileName], rules.target).length > 0) { + noDomGlobalsLinter = { allowed: rules.allowed }; + break; + } + } + + for (const rules of RULES["no-nodejs-globals"]) { + if (match([sourceFile.fileName], rules.target).length > 0) { + noNodeJSGlobalsLinter = { allowed: rules.allowed }; + break; + } + } + + if (!noDomGlobalsLinter && !noNodeJSGlobalsLinter) { + continue; // no rule to run + } + + // No DOM Globals + if (noDomGlobalsLinter) { + checkFile(program, sourceFile, { + definition: DOM_GLOBALS_DEFINITION, + disallowedGlobals: DISALLOWED_DOM_GLOBALS, + allowedGlobals: noDomGlobalsLinter.allowed + }); + } + + // No node.js Globals + if (noNodeJSGlobalsLinter) { + checkFile(program, sourceFile, { + definition: NODE_GLOBALS_DEFINITION, + disallowedGlobals: DISALLOWED_NODE_GLOBALS, + allowedGlobals: noNodeJSGlobalsLinter.allowed + }); + } +} + +if (hasErrors) { + process.exit(1); +} diff --git a/build/lib/tslint/abstractGlobalsRule.js b/build/lib/tslint/abstractGlobalsRule.js deleted file mode 100644 index 1566c0aa576..00000000000 --- a/build/lib/tslint/abstractGlobalsRule.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -const Lint = require("tslint"); -class AbstractGlobalsRuleWalker extends Lint.RuleWalker { - constructor(file, program, opts, _config) { - super(file, opts); - this.program = program; - this._config = _config; - } - visitIdentifier(node) { - if (this.getDisallowedGlobals().some(disallowedGlobal => disallowedGlobal === node.text)) { - if (this._config.allowed && this._config.allowed.some(allowed => allowed === node.text)) { - return; // override - } - const checker = this.program.getTypeChecker(); - const symbol = checker.getSymbolAtLocation(node); - if (symbol) { - const declarations = symbol.declarations; - if (Array.isArray(declarations) && symbol.declarations.some(declaration => { - if (declaration) { - const parent = declaration.parent; - if (parent) { - const sourceFile = parent.getSourceFile(); - if (sourceFile) { - const fileName = sourceFile.fileName; - if (fileName && fileName.indexOf(this.getDefinitionPattern()) >= 0) { - return true; - } - } - } - } - return false; - })) { - this.addFailureAtNode(node, `Cannot use global '${node.text}' in '${this._config.target}'`); - } - } - } - super.visitIdentifier(node); - } -} -exports.AbstractGlobalsRuleWalker = AbstractGlobalsRuleWalker; diff --git a/build/lib/tslint/abstractGlobalsRule.ts b/build/lib/tslint/abstractGlobalsRule.ts deleted file mode 100644 index 543720455c3..00000000000 --- a/build/lib/tslint/abstractGlobalsRule.ts +++ /dev/null @@ -1,57 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as ts from 'typescript'; -import * as Lint from 'tslint'; - -interface AbstractGlobalsRuleConfig { - target: string; - allowed: string[]; -} - -export abstract class AbstractGlobalsRuleWalker extends Lint.RuleWalker { - - constructor(file: ts.SourceFile, private program: ts.Program, opts: Lint.IOptions, private _config: AbstractGlobalsRuleConfig) { - super(file, opts); - } - - protected abstract getDisallowedGlobals(): string[]; - - protected abstract getDefinitionPattern(): string; - - visitIdentifier(node: ts.Identifier) { - if (this.getDisallowedGlobals().some(disallowedGlobal => disallowedGlobal === node.text)) { - if (this._config.allowed && this._config.allowed.some(allowed => allowed === node.text)) { - return; // override - } - - const checker = this.program.getTypeChecker(); - const symbol = checker.getSymbolAtLocation(node); - if (symbol) { - const declarations = symbol.declarations; - if (Array.isArray(declarations) && symbol.declarations.some(declaration => { - if (declaration) { - const parent = declaration.parent; - if (parent) { - const sourceFile = parent.getSourceFile(); - if (sourceFile) { - const fileName = sourceFile.fileName; - if (fileName && fileName.indexOf(this.getDefinitionPattern()) >= 0) { - return true; - } - } - } - } - - return false; - })) { - this.addFailureAtNode(node, `Cannot use global '${node.text}' in '${this._config.target}'`); - } - } - } - - super.visitIdentifier(node); - } -} diff --git a/build/lib/tslint/noDomGlobalsRule.js b/build/lib/tslint/noDomGlobalsRule.js deleted file mode 100644 index a83ac8f7f59..00000000000 --- a/build/lib/tslint/noDomGlobalsRule.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -const Lint = require("tslint"); -const minimatch = require("minimatch"); -const abstractGlobalsRule_1 = require("./abstractGlobalsRule"); -class Rule extends Lint.Rules.TypedRule { - applyWithProgram(sourceFile, program) { - const configs = this.getOptions().ruleArguments; - for (const config of configs) { - if (minimatch(sourceFile.fileName, config.target)) { - return this.applyWithWalker(new NoDOMGlobalsRuleWalker(sourceFile, program, this.getOptions(), config)); - } - } - return []; - } -} -exports.Rule = Rule; -class NoDOMGlobalsRuleWalker extends abstractGlobalsRule_1.AbstractGlobalsRuleWalker { - getDefinitionPattern() { - return 'lib.dom.d.ts'; - } - getDisallowedGlobals() { - // intentionally not complete - return [ - "window", - "document", - "HTMLElement" - ]; - } -} diff --git a/build/lib/tslint/noDomGlobalsRule.ts b/build/lib/tslint/noDomGlobalsRule.ts deleted file mode 100644 index df9e67bf78b..00000000000 --- a/build/lib/tslint/noDomGlobalsRule.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as ts from 'typescript'; -import * as Lint from 'tslint'; -import * as minimatch from 'minimatch'; -import { AbstractGlobalsRuleWalker } from './abstractGlobalsRule'; - -interface NoDOMGlobalsRuleConfig { - target: string; - allowed: string[]; -} - -export class Rule extends Lint.Rules.TypedRule { - - applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { - const configs = this.getOptions().ruleArguments; - - for (const config of configs) { - if (minimatch(sourceFile.fileName, config.target)) { - return this.applyWithWalker(new NoDOMGlobalsRuleWalker(sourceFile, program, this.getOptions(), config)); - } - } - - return []; - } -} - -class NoDOMGlobalsRuleWalker extends AbstractGlobalsRuleWalker { - - getDefinitionPattern(): string { - return 'lib.dom.d.ts'; - } - - getDisallowedGlobals(): string[] { - // intentionally not complete - return [ - "window", - "document", - "HTMLElement" - ]; - } -} diff --git a/build/lib/tslint/noNodejsGlobalsRule.js b/build/lib/tslint/noNodejsGlobalsRule.js deleted file mode 100644 index 8c36fa342c2..00000000000 --- a/build/lib/tslint/noNodejsGlobalsRule.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -const Lint = require("tslint"); -const minimatch = require("minimatch"); -const abstractGlobalsRule_1 = require("./abstractGlobalsRule"); -class Rule extends Lint.Rules.TypedRule { - applyWithProgram(sourceFile, program) { - const configs = this.getOptions().ruleArguments; - for (const config of configs) { - if (minimatch(sourceFile.fileName, config.target)) { - return this.applyWithWalker(new NoNodejsGlobalsRuleWalker(sourceFile, program, this.getOptions(), config)); - } - } - return []; - } -} -exports.Rule = Rule; -class NoNodejsGlobalsRuleWalker extends abstractGlobalsRule_1.AbstractGlobalsRuleWalker { - getDefinitionPattern() { - return '@types/node'; - } - getDisallowedGlobals() { - // https://nodejs.org/api/globals.html#globals_global_objects - return [ - "NodeJS", - "Buffer", - "__dirname", - "__filename", - "clearImmediate", - "exports", - "global", - "module", - "process", - "setImmediate" - ]; - } -} diff --git a/build/lib/tslint/noNodejsGlobalsRule.ts b/build/lib/tslint/noNodejsGlobalsRule.ts deleted file mode 100644 index 7e5767d8570..00000000000 --- a/build/lib/tslint/noNodejsGlobalsRule.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as ts from 'typescript'; -import * as Lint from 'tslint'; -import * as minimatch from 'minimatch'; -import { AbstractGlobalsRuleWalker } from './abstractGlobalsRule'; - -interface NoNodejsGlobalsConfig { - target: string; - allowed: string[]; -} - -export class Rule extends Lint.Rules.TypedRule { - - applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { - const configs = this.getOptions().ruleArguments; - - for (const config of configs) { - if (minimatch(sourceFile.fileName, config.target)) { - return this.applyWithWalker(new NoNodejsGlobalsRuleWalker(sourceFile, program, this.getOptions(), config)); - } - } - - return []; - } -} - -class NoNodejsGlobalsRuleWalker extends AbstractGlobalsRuleWalker { - - getDefinitionPattern(): string { - return '@types/node'; - } - - getDisallowedGlobals(): string[] { - // https://nodejs.org/api/globals.html#globals_global_objects - return [ - "NodeJS", - "Buffer", - "__dirname", - "__filename", - "clearImmediate", - "exports", - "global", - "module", - "process", - "setImmediate" - ]; - } -} diff --git a/build/package.json b/build/package.json index bafb409c97b..7d72317ff5e 100644 --- a/build/package.json +++ b/build/package.json @@ -36,6 +36,7 @@ "gulp-uglify": "^3.0.0", "iconv-lite": "0.4.23", "mime": "^1.3.4", + "minimatch": "3.0.4", "minimist": "^1.2.0", "request": "^2.85.0", "terser": "4.3.8", diff --git a/package.json b/package.json index fa917351db5..6645783674b 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "smoketest": "cd test/smoke && node test/index.js", "download-builtin-extensions": "node build/lib/builtInExtensions.js", "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", + "valid-globals-check": "node build/lib/globalsLinter.js", "strict-function-types-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictFunctionTypes", "update-distro": "node build/npm/update-distro.js", "web": "node scripts/code-web.js" diff --git a/tslint.json b/tslint.json index 820aa3103db..9b5b07a5dd7 100644 --- a/tslint.json +++ b/tslint.json @@ -609,48 +609,6 @@ "restrictions": "**/vs/**" } ], - "no-nodejs-globals": [ - true, - { - "target": "**/vs/base/common/{path,process,platform}.ts", - "allowed": [ - "process" // -> defines safe access to process - ] - }, - { - "target": "**/vs/**/test/{common,browser}/**", - "allowed": [ - "process", - "Buffer", - "__filename", - "__dirname" - ] - }, - { - "target": "**/vs/workbench/api/common/extHostExtensionService.ts", - "allowed": [ - "global" // -> safe access to 'global' - ] - }, - { - "target": "**/vs/**/{common,browser}/**", - "allowed": [ /* none */] - } - ], - "no-dom-globals": [ - true, - { - "target": "**/vs/**/test/{common,node,electron-main}/**", - "allowed": [ - "document", - "HTMLElement" - ] - }, - { - "target": "**/vs/**/{common,node,electron-main}/**", - "allowed": [ /* none */] - } - ], "duplicate-imports": true, "no-new-buffer": true, "translation-remind": true,