Merge from vscode 718331d6f3ebd1b571530ab499edb266ddd493d5

This commit is contained in:
ADS Merger
2020-02-08 04:50:58 +00:00
parent 8c61538a27
commit 2af13c18d2
752 changed files with 16458 additions and 10063 deletions

View File

@@ -0,0 +1,35 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
module.exports = new class ApiLiteralOrTypes {
constructor() {
this.meta = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#creating-objects' },
messages: { sync: '`createXYZ`-functions are constructor-replacements and therefore must return sync', }
};
}
create(context) {
return {
['TSDeclareFunction Identifier[name=/create.*/]']: (node) => {
var _a;
const decl = node.parent;
if (((_a = decl.returnType) === null || _a === void 0 ? void 0 : _a.typeAnnotation.type) !== experimental_utils_1.AST_NODE_TYPES.TSTypeReference) {
return;
}
if (decl.returnType.typeAnnotation.typeName.type !== experimental_utils_1.AST_NODE_TYPES.Identifier) {
return;
}
const ident = decl.returnType.typeAnnotation.typeName.name;
if (ident === 'Promise' || ident === 'Thenable') {
context.report({
node,
messageId: 'sync'
});
}
}
};
}
};

View File

@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#creating-objects' },
messages: { sync: '`createXYZ`-functions are constructor-replacements and therefore must return sync', }
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSDeclareFunction Identifier[name=/create.*/]']: (node: any) => {
const decl = <TSESTree.FunctionDeclaration>(<TSESTree.Identifier>node).parent;
if (decl.returnType?.typeAnnotation.type !== AST_NODE_TYPES.TSTypeReference) {
return;
}
if (decl.returnType.typeAnnotation.typeName.type !== AST_NODE_TYPES.Identifier) {
return;
}
const ident = decl.returnType.typeAnnotation.typeName.name;
if (ident === 'Promise' || ident === 'Thenable') {
context.report({
node,
messageId: 'sync'
});
}
}
};
}
};

View File

@@ -0,0 +1,81 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var _a;
const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
module.exports = new (_a = class ApiEventNaming {
constructor() {
this.meta = {
docs: {
url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#event-naming'
},
messages: {
naming: 'Event names must follow this patten: `on[Did|Will]<Verb><Subject>`',
verb: 'Unknown verb \'{{verb}}\' - is this really a verb? Iff so, then add this verb to the configuration',
subject: 'Unknown subject \'{{subject}}\' - This subject has not been used before but it should refer to something in the API',
unknown: 'UNKNOWN event declaration, lint-rule needs tweaking'
}
};
}
create(context) {
const config = context.options[0];
const allowed = new Set(config.allowed);
const verbs = new Set(config.verbs);
return {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node) => {
var _a, _b;
const def = (_b = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.parent;
let ident;
if ((def === null || def === void 0 ? void 0 : def.type) === experimental_utils_1.AST_NODE_TYPES.Identifier) {
ident = def;
}
else if (((def === null || def === void 0 ? void 0 : def.type) === experimental_utils_1.AST_NODE_TYPES.TSPropertySignature || (def === null || def === void 0 ? void 0 : def.type) === experimental_utils_1.AST_NODE_TYPES.ClassProperty) && def.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
ident = def.key;
}
if (!ident) {
// event on unknown structure...
return context.report({
node,
message: 'unknown'
});
}
if (allowed.has(ident.name)) {
// configured exception
return;
}
const match = ApiEventNaming._nameRegExp.exec(ident.name);
if (!match) {
context.report({
node: ident,
messageId: 'naming'
});
return;
}
// check that <verb> is spelled out (configured) as verb
if (!verbs.has(match[2].toLowerCase())) {
context.report({
node: ident,
messageId: 'verb',
data: { verb: match[2] }
});
}
// check that a subject (if present) has occurred
if (match[3]) {
const regex = new RegExp(match[3], 'ig');
const parts = context.getSourceCode().getText().split(regex);
if (parts.length < 3) {
context.report({
node: ident,
messageId: 'subject',
data: { subject: match[3] }
});
}
}
}
};
}
},
_a._nameRegExp = /on(Did|Will)([A-Z][a-z]+)([A-Z][a-z]+)?/,
_a);

View File

@@ -0,0 +1,91 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
export = new class ApiEventNaming implements eslint.Rule.RuleModule {
private static _nameRegExp = /on(Did|Will)([A-Z][a-z]+)([A-Z][a-z]+)?/;
readonly meta: eslint.Rule.RuleMetaData = {
docs: {
url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#event-naming'
},
messages: {
naming: 'Event names must follow this patten: `on[Did|Will]<Verb><Subject>`',
verb: 'Unknown verb \'{{verb}}\' - is this really a verb? Iff so, then add this verb to the configuration',
subject: 'Unknown subject \'{{subject}}\' - This subject has not been used before but it should refer to something in the API',
unknown: 'UNKNOWN event declaration, lint-rule needs tweaking'
}
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ allowed: string[], verbs: string[] }>context.options[0];
const allowed = new Set(config.allowed);
const verbs = new Set(config.verbs);
return {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node: any) => {
const def = (<TSESTree.Identifier>node).parent?.parent?.parent;
let ident: TSESTree.Identifier | undefined;
if (def?.type === AST_NODE_TYPES.Identifier) {
ident = def;
} else if ((def?.type === AST_NODE_TYPES.TSPropertySignature || def?.type === AST_NODE_TYPES.ClassProperty) && def.key.type === AST_NODE_TYPES.Identifier) {
ident = def.key;
}
if (!ident) {
// event on unknown structure...
return context.report({
node,
message: 'unknown'
});
}
if (allowed.has(ident.name)) {
// configured exception
return;
}
const match = ApiEventNaming._nameRegExp.exec(ident.name);
if (!match) {
context.report({
node: ident,
messageId: 'naming'
});
return;
}
// check that <verb> is spelled out (configured) as verb
if (!verbs.has(match[2].toLowerCase())) {
context.report({
node: ident,
messageId: 'verb',
data: { verb: match[2] }
});
}
// check that a subject (if present) has occurred
if (match[3]) {
const regex = new RegExp(match[3], 'ig');
const parts = context.getSourceCode().getText().split(regex);
if (parts.length < 3) {
context.report({
node: ident,
messageId: 'subject',
data: { subject: match[3] }
});
}
}
}
};
}
};

View File

@@ -0,0 +1,30 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var _a;
module.exports = new (_a = class ApiInterfaceNaming {
constructor() {
this.meta = {
messages: {
naming: 'Interfaces must not be prefixed with uppercase `I`',
}
};
}
create(context) {
return {
['TSInterfaceDeclaration Identifier']: (node) => {
const name = node.name;
if (ApiInterfaceNaming._nameRegExp.test(name)) {
context.report({
node,
messageId: 'naming'
});
}
}
};
}
},
_a._nameRegExp = /I[A-Z]/,
_a);

View File

@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/experimental-utils';
export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
private static _nameRegExp = /I[A-Z]/;
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
naming: 'Interfaces must not be prefixed with uppercase `I`',
}
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSInterfaceDeclaration Identifier']: (node: any) => {
const name = (<TSESTree.Identifier>node).name;
if (ApiInterfaceNaming._nameRegExp.test(name)) {
context.report({
node,
messageId: 'naming'
});
}
}
};
}
};

View File

@@ -0,0 +1,23 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
module.exports = new class ApiLiteralOrTypes {
constructor() {
this.meta = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#enums' },
messages: { useEnum: 'Use enums, not literal-or-types', }
};
}
create(context) {
return {
['TSTypeAnnotation TSUnionType TSLiteralType']: (node) => {
context.report({
node: node,
messageId: 'useEnum'
});
}
};
}
};

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#enums' },
messages: { useEnum: 'Use enums, not literal-or-types', }
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['TSTypeAnnotation TSUnionType TSLiteralType']: (node: any) => {
context.report({
node: node,
messageId: 'useEnum'
});
}
};
}
};

View File

@@ -142,6 +142,10 @@
"name": "vs/workbench/contrib/search",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/searchEditor",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/snippets",
"project": "vscode-workbench"
@@ -321,6 +325,10 @@
{
"name": "vs/workbench/services/userDataSync",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/timeline",
"project": "vscode-workbench"
}
]
}

View File

@@ -38,6 +38,7 @@ const CORE_TYPES = [
'group',
'groupEnd',
'table',
'assert',
'Error',
'String',
'throws',
@@ -60,7 +61,7 @@ const RULES = [
},
// Common: vs/base/common/platform.ts
{
target: '**/vs/base/common/platform.ts',
target: '**/{vs,sql}/base/common/platform.ts',
allowedTypes: [
...CORE_TYPES,
// Safe access to postMessage() and friends
@@ -74,7 +75,7 @@ const RULES = [
},
// Common: vs/workbench/api/common/extHostExtensionService.ts
{
target: '**/vs/workbench/api/common/extHostExtensionService.ts',
target: '**/{vs,sql}/workbench/api/common/extHostExtensionService.ts',
allowedTypes: [
...CORE_TYPES,
// Safe access to global
@@ -102,6 +103,14 @@ const RULES = [
'@types/node' // no node.js
]
},
// Browser (editor contrib)
{
target: '**/src/{vs,sql}/editor/contrib/**',
allowedTypes: CORE_TYPES,
disallowedDefinitions: [
'@types/node' // no node.js
]
},
// node.js
{
target: '**/{vs,sql}/**/node/**',

View File

@@ -39,6 +39,7 @@ const CORE_TYPES = [
'group',
'groupEnd',
'table',
'assert',
'Error',
'String',
'throws',
@@ -64,7 +65,7 @@ const RULES = [
// Common: vs/base/common/platform.ts
{
target: '**/vs/base/common/platform.ts',
target: '**/{vs,sql}/base/common/platform.ts',
allowedTypes: [
...CORE_TYPES,
@@ -80,7 +81,7 @@ const RULES = [
// Common: vs/workbench/api/common/extHostExtensionService.ts
{
target: '**/vs/workbench/api/common/extHostExtensionService.ts',
target: '**/{vs,sql}/workbench/api/common/extHostExtensionService.ts',
allowedTypes: [
...CORE_TYPES,
@@ -112,6 +113,15 @@ const RULES = [
]
},
// Browser (editor contrib)
{
target: '**/src/{vs,sql}/editor/contrib/**',
allowedTypes: CORE_TYPES,
disallowedDefinitions: [
'@types/node' // no node.js
]
},
// node.js
{
target: '**/{vs,sql}/**/node/**',

57
build/lib/testSetup.js Normal file
View File

@@ -0,0 +1,57 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const fs = require('fs').promises;
const path = require('path');
const readConfiguration = (async () => {
const parseConfigString = ((content) => {
try {
const result = JSON.parse(content);
return result;
}
catch (ex) {
console.log('Could NOT parse TEST_RUN_LIST:', content);
}
});
// Attempt to read from an enviornment variable
const testRunlist = process.env['TEST_RUN_LIST'];
if (testRunlist && testRunlist !== '') {
const result = parseConfigString(testRunlist);
if (result) {
console.log('Using the environment test run list:', result);
return result;
}
}
// Attempt to read from a config file
let testRunPath = process.env['TEST_RUN_LIST_FILE'];
if (!testRunPath || testRunPath === '') {
testRunPath = path.resolve(__dirname, '..', 'runlist.json');
}
try {
const contents = await fs.readFile(testRunPath);
return parseConfigString(contents);
}
catch (ex) {
console.log(`error reading file ${testRunPath}:`, ex);
}
});
(async () => {
const keys = process.argv.slice(2);
const configuration = await readConfiguration();
if (!configuration) {
console.log('no configuration was setup');
return;
}
const testList = [];
keys.forEach((key) => {
const arr = configuration[key];
if (arr) {
testList.push(...arr);
}
});
const result = `(${testList.join('|')})`;
console.log(result);
process.env['TEST_GREP'] = result;
})();

67
build/lib/testSetup.ts Normal file
View File

@@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const fs = require('fs').promises;
const path = require('path');
interface IntegrationTestConfig {
[key: string]: string[];
}
const readConfiguration = (async (): Promise<IntegrationTestConfig | void> => {
const parseConfigString = ((content: string): (IntegrationTestConfig | void) => {
try {
const result = JSON.parse(content);
return result as IntegrationTestConfig;
} catch (ex) {
console.log('Could NOT parse TEST_RUN_LIST:', content);
}
});
// Attempt to read from an enviornment variable
const testRunlist = process.env['TEST_RUN_LIST'];
if (testRunlist && testRunlist !== '') {
const result = parseConfigString(testRunlist);
if (result) {
console.log('Using the environment test run list:', result);
return result;
}
}
// Attempt to read from a config file
let testRunPath = process.env['TEST_RUN_LIST_FILE'];
if (!testRunPath || testRunPath === '') {
testRunPath = path.resolve(__dirname, '..', 'runlist.json');
}
try {
const contents = await fs.readFile(testRunPath);
return parseConfigString(contents);
} catch (ex) {
console.log(`error reading file ${testRunPath}:`, ex);
}
});
(async (): Promise<string | void> => {
const keys = process.argv.slice(2);
const configuration = await readConfiguration();
if (!configuration) {
console.log('no configuration was setup');
return;
}
const testList: string[] = [];
keys.forEach((key) => {
const arr = configuration[key];
if (arr) {
testList.push(...arr);
}
});
const result = `(${testList.join('|')})`;
console.log(result);
process.env['TEST_GREP'] = result;
})();