Merge vscode 1.67 (#20883)

* Fix initial build breaks from 1.67 merge (#2514)

* Update yarn lock files

* Update build scripts

* Fix tsconfig

* Build breaks

* WIP

* Update yarn lock files

* Misc breaks

* Updates to package.json

* Breaks

* Update yarn

* Fix breaks

* Breaks

* Build breaks

* Breaks

* Breaks

* Breaks

* Breaks

* Breaks

* Missing file

* Breaks

* Breaks

* Breaks

* Breaks

* Breaks

* Fix several runtime breaks (#2515)

* Missing files

* Runtime breaks

* Fix proxy ordering issue

* Remove commented code

* Fix breaks with opening query editor

* Fix post merge break

* Updates related to setup build and other breaks (#2516)

* Fix bundle build issues

* Update distro

* Fix distro merge and update build JS files

* Disable pipeline steps

* Remove stats call

* Update license name

* Make new RPM dependencies a warning

* Fix extension manager version checks

* Update JS file

* Fix a few runtime breaks

* Fixes

* Fix runtime issues

* Fix build breaks

* Update notebook tests (part 1)

* Fix broken tests

* Linting errors

* Fix hygiene

* Disable lint rules

* Bump distro

* Turn off smoke tests

* Disable integration tests

* Remove failing "activate" test

* Remove failed test assertion

* Disable other broken test

* Disable query history tests

* Disable extension unit tests

* Disable failing tasks
This commit is contained in:
Karl Burtram
2022-10-19 19:13:18 -07:00
committed by GitHub
parent 33c6daaea1
commit 8a3d08f0de
3738 changed files with 192313 additions and 107208 deletions

View File

@@ -3,44 +3,184 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path_1 = require("path");
const path = require("path");
const minimatch = require("minimatch");
const utils_1 = require("./utils");
const REPO_ROOT = path.normalize(path.join(__dirname, '../../../'));
function isLayerAllowRule(option) {
return !!(option.when && option.allow);
}
/**
* Returns the filename relative to the project root and using `/` as separators
*/
function getRelativeFilename(context) {
const filename = path.normalize(context.getFilename());
return filename.substring(REPO_ROOT.length).replace(/\\/g, '/');
}
module.exports = new class {
constructor() {
this.meta = {
messages: {
badImport: 'Imports violates \'{{restrictions}}\' restrictions. See https://github.com/microsoft/vscode/wiki/Source-Code-Organization'
badImport: 'Imports violates \'{{restrictions}}\' restrictions. See https://github.com/microsoft/vscode/wiki/Source-Code-Organization',
badFilename: 'Missing definition in `code-import-patterns` for this file. Define rules at https://github.com/microsoft/vscode/blob/main/.eslintrc.json'
},
docs: {
url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization'
}
};
this._optionsCache = new WeakMap();
}
create(context) {
const configs = context.options;
const options = context.options;
const configs = this._processOptions(options);
const relativeFilename = getRelativeFilename(context);
for (const config of configs) {
if (minimatch(context.getFilename(), config.target)) {
if (minimatch(relativeFilename, config.target)) {
return (0, utils_1.createImportRuleListener)((node, value) => this._checkImport(context, config, node, value));
}
}
context.report({
loc: { line: 1, column: 0 },
messageId: 'badFilename'
});
return {};
}
_checkImport(context, config, node, path) {
_processOptions(options) {
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 },
];
let browserAllow = [];
let nodeAllow = [];
let testAllow = [];
for (const option of options) {
if (isLayerAllowRule(option)) {
if (option.when === 'hasBrowser') {
browserAllow = option.allow.slice(0);
}
else if (option.when === 'hasNode') {
nodeAllow = option.allow.slice(0);
}
else if (option.when === 'test') {
testAllow = option.allow.slice(0);
}
}
}
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 = [...testAllow];
if (layerRule.isBrowser) {
restrictions.push(...browserAllow);
}
if (layerRule.isNode) {
restrictions.push(...nodeAllow);
}
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 = [];
for (const option of options) {
if (isLayerAllowRule(option)) {
continue;
}
const target = option.target;
const targetIsVS = /^src\/{vs,sql}\//.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') });
}
}
this._optionsCache.set(options, configs);
return configs;
}
_checkImport(context, config, node, importPath) {
// resolve relative paths
if (path[0] === '.') {
path = (0, path_1.join)(context.getFilename(), path);
}
let restrictions;
if (typeof config.restrictions === 'string') {
restrictions = [config.restrictions];
}
else {
restrictions = config.restrictions;
if (importPath[0] === '.') {
const relativeFilename = getRelativeFilename(context);
importPath = path.posix.join(path.posix.dirname(relativeFilename), importPath);
if (/^src\/{vs,sql}\//.test(importPath)) {
// resolve using AMD base url
importPath = importPath.substring('src/'.length);
}
}
const restrictions = config.restrictions;
let matched = false;
for (const pattern of restrictions) {
if (minimatch(path, pattern)) {
if (minimatch(importPath, pattern)) {
matched = true;
break;
}

View File

@@ -5,20 +5,46 @@
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/experimental-utils';
import { join } from 'path';
import * as path from 'path';
import * as minimatch from 'minimatch';
import { createImportRuleListener } from './utils';
const REPO_ROOT = path.normalize(path.join(__dirname, '../../../'));
interface ConditionalPattern {
when?: 'hasBrowser' | 'hasNode' | 'test';
pattern: string;
}
interface RawImportPatternsConfig {
target: string;
layer?: 'common' | 'worker' | 'browser' | 'electron-sandbox' | 'node' | 'electron-browser' | 'electron-main';
test?: boolean;
restrictions: string | (string | ConditionalPattern)[];
}
interface LayerAllowRule {
when: 'hasBrowser' | 'hasNode' | 'test';
allow: string[];
}
type RawOption = RawImportPatternsConfig | LayerAllowRule;
function isLayerAllowRule(option: RawOption): option is LayerAllowRule {
return !!((<LayerAllowRule>option).when && (<LayerAllowRule>option).allow);
}
interface ImportPatternsConfig {
target: string;
restrictions: string | string[];
restrictions: string[];
}
export = new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
badImport: 'Imports violates \'{{restrictions}}\' restrictions. See https://github.com/microsoft/vscode/wiki/Source-Code-Organization'
badImport: 'Imports violates \'{{restrictions}}\' restrictions. See https://github.com/microsoft/vscode/wiki/Source-Code-Organization',
badFilename: 'Missing definition in `code-import-patterns` for this file. Define rules at https://github.com/microsoft/vscode/blob/main/.eslintrc.json'
},
docs: {
url: 'https://github.com/microsoft/vscode/wiki/Source-Code-Organization'
@@ -26,35 +52,182 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const configs = <ImportPatternsConfig[]>context.options;
const options = <RawOption[]>context.options;
const configs = this._processOptions(options);
const relativeFilename = getRelativeFilename(context);
for (const config of configs) {
if (minimatch(context.getFilename(), config.target)) {
if (minimatch(relativeFilename, config.target)) {
return createImportRuleListener((node, value) => this._checkImport(context, config, node, value));
}
}
context.report({
loc: { line: 1, column: 0 },
messageId: 'badFilename'
});
return {};
}
private _checkImport(context: eslint.Rule.RuleContext, config: ImportPatternsConfig, node: TSESTree.Node, path: string) {
private _optionsCache = new WeakMap<RawOption[], ImportPatternsConfig[]>();
private _processOptions(options: RawOption[]): 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 },
];
let browserAllow: string[] = [];
let nodeAllow: string[] = [];
let testAllow: string[] = [];
for (const option of options) {
if (isLayerAllowRule(option)) {
if (option.when === 'hasBrowser') {
browserAllow = option.allow.slice(0);
} else if (option.when === 'hasNode') {
nodeAllow = option.allow.slice(0);
} else if (option.when === 'test') {
testAllow = option.allow.slice(0);
}
}
}
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[] = [...testAllow];
if (layerRule.isBrowser) {
restrictions.push(...browserAllow);
}
if (layerRule.isNode) {
restrictions.push(...nodeAllow);
}
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[] = [];
for (const option of options) {
if (isLayerAllowRule(option)) {
continue;
}
const target = option.target;
const targetIsVS = /^src\/{vs,sql}\//.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') });
}
}
this._optionsCache.set(options, configs);
return configs;
}
private _checkImport(context: eslint.Rule.RuleContext, config: ImportPatternsConfig, node: TSESTree.Node, importPath: string) {
// resolve relative paths
if (path[0] === '.') {
path = join(context.getFilename(), path);
if (importPath[0] === '.') {
const relativeFilename = getRelativeFilename(context);
importPath = path.posix.join(path.posix.dirname(relativeFilename), importPath);
if (/^src\/{vs,sql}\//.test(importPath)) {
// resolve using AMD base url
importPath = importPath.substring('src/'.length);
}
}
let restrictions: string[];
if (typeof config.restrictions === 'string') {
restrictions = [config.restrictions];
} else {
restrictions = config.restrictions;
}
const restrictions = config.restrictions;
let matched = false;
for (const pattern of restrictions) {
if (minimatch(path, pattern)) {
if (minimatch(importPath, pattern)) {
matched = true;
break;
}
@@ -73,3 +246,10 @@ export = new class implements eslint.Rule.RuleModule {
}
};
/**
* Returns the filename relative to the project root and using `/` as separators
*/
function getRelativeFilename(context: eslint.Rule.RuleContext): string {
const filename = path.normalize(context.getFilename());
return filename.substring(REPO_ROOT.length).replace(/\\/g, '/');
}

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const _positiveLookBehind = /\(\?<=.+/;
const _negativeLookBehind = /\(\?<!.+/;
function _containsLookBehind(pattern) {
if (typeof pattern !== 'string') {
return false;
}
return _positiveLookBehind.test(pattern) || _negativeLookBehind.test(pattern);
}
module.exports = {
create(context) {
return {
// /.../
['Literal[regex]']: (node) => {
var _a;
const pattern = (_a = node.regex) === null || _a === void 0 ? void 0 : _a.pattern;
if (_containsLookBehind(pattern)) {
context.report({
node,
message: 'Look behind assertions are not yet supported in all browsers'
});
}
},
// new Regex("...")
['NewExpression[callee.name="RegExp"] Literal']: (node) => {
if (_containsLookBehind(node.value)) {
context.report({
node,
message: 'Look behind assertions are not yet supported in all browsers'
});
}
}
};
}
};

View File

@@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/experimental-utils';
import * as ESTree from 'estree';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const _positiveLookBehind = /\(\?<=.+/;
const _negativeLookBehind = /\(\?<!.+/;
function _containsLookBehind(pattern: string | unknown): boolean {
if (typeof pattern !== 'string') {
return false;
}
return _positiveLookBehind.test(pattern) || _negativeLookBehind.test(pattern);
}
module.exports = {
create(context: eslint.Rule.RuleContext) {
return {
// /.../
['Literal[regex]']: (node: any) => {
type RegexLiteral = TSESTree.Literal & { regex: { pattern: string; flags: string } };
const pattern = (<RegexLiteral>node).regex?.pattern;
if (_containsLookBehind(pattern)) {
context.report({
node,
message: 'Look behind assertions are not yet supported in all browsers'
});
}
},
// new Regex("...")
['NewExpression[callee.name="RegExp"] Literal']: (node: ESTree.Literal) => {
if (_containsLookBehind(node.value)) {
context.report({
node,
message: 'Look behind assertions are not yet supported in all browsers'
});
}
}
};
}
};

View File

@@ -0,0 +1,17 @@
"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 NoTestOnly {
create(context) {
return {
['MemberExpression[object.name="test"][property.name="only"]']: (node) => {
return context.report({
node,
message: 'test.only is a dev-time tool and CANNOT be pushed'
});
}
};
}
};

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* 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 NoTestOnly implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['MemberExpression[object.name="test"][property.name="only"]']: (node: any) => {
return context.report({
node,
message: 'test.only is a dev-time tool and CANNOT be pushed'
});
}
};
}
};

View File

@@ -29,7 +29,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const externalizedStringLiterals = new Map<string, { call: TSESTree.CallExpression, message: TSESTree.Node }[]>();
const externalizedStringLiterals = new Map<string, { call: TSESTree.CallExpression; message: TSESTree.Node }[]>();
const doubleQuotedStringLiterals = new Set<TSESTree.Node>();
function collectDoubleQuotedStrings(node: TSESTree.Literal) {

View File

@@ -44,10 +44,7 @@ module.exports = {
]
},
create(context) {
const config = context.options[0] || {},
allowShortCircuit = config.allowShortCircuit || false,
allowTernary = config.allowTernary || false,
allowTaggedTemplates = config.allowTaggedTemplates || false;
const config = context.options[0] || {}, allowShortCircuit = config.allowShortCircuit || false, allowTernary = config.allowTernary || false, allowTaggedTemplates = config.allowTaggedTemplates || false;
// eslint-disable-next-line jsdoc/require-description
/**
* @param node any node
@@ -111,13 +108,16 @@ module.exports = {
if (allowTaggedTemplates && node.type === 'TaggedTemplateExpression') {
return true;
}
return /^(?:Assignment|OptionalCall|Call|New|Update|Yield|Await)Expression$/u.test(node.type) ||
if (node.type === 'ExpressionStatement') {
return isValidExpression(node.expression);
}
return /^(?:Assignment|OptionalCall|Call|New|Update|Yield|Await|Chain)Expression$/u.test(node.type) ||
(node.type === 'UnaryExpression' && ['delete', 'void'].indexOf(node.operator) >= 0);
}
return {
ExpressionStatement(node) {
if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) {
context.report({ node: node, message: 'Expected an assignment or function call and instead saw an expression.' });
context.report({ node: node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` });
}
}
};

View File

@@ -0,0 +1,153 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// FORKED FROM https://github.com/eslint/eslint/blob/b23ad0d789a909baf8d7c41a35bc53df932eaf30/lib/rules/no-unused-expressions.js
// and added support for `OptionalCallExpression`, see https://github.com/facebook/create-react-app/issues/8107 and https://github.com/eslint/eslint/issues/12642
/**
* @fileoverview Flag expressions in statement position that do not side effect
* @author Michael Ficarra
*/
'use strict';
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/experimental-utils';
import * as ESTree from 'estree';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow unused expressions',
category: 'Best Practices',
recommended: false,
url: 'https://eslint.org/docs/rules/no-unused-expressions'
},
schema: [
{
type: 'object',
properties: {
allowShortCircuit: {
type: 'boolean',
default: false
},
allowTernary: {
type: 'boolean',
default: false
},
allowTaggedTemplates: {
type: 'boolean',
default: false
}
},
additionalProperties: false
}
]
},
create(context: eslint.Rule.RuleContext) {
const config = context.options[0] || {},
allowShortCircuit = config.allowShortCircuit || false,
allowTernary = config.allowTernary || false,
allowTaggedTemplates = config.allowTaggedTemplates || false;
// eslint-disable-next-line jsdoc/require-description
/**
* @param node any node
* @returns whether the given node structurally represents a directive
*/
function looksLikeDirective(node: TSESTree.Node): boolean {
return node.type === 'ExpressionStatement' &&
node.expression.type === 'Literal' && typeof node.expression.value === 'string';
}
// eslint-disable-next-line jsdoc/require-description
/**
* @param predicate ([a] -> Boolean) the function used to make the determination
* @param list the input list
* @returns the leading sequence of members in the given list that pass the given predicate
*/
function takeWhile<T>(predicate: (item: T) => boolean, list: T[]): T[] {
for (let i = 0; i < list.length; ++i) {
if (!predicate(list[i])) {
return list.slice(0, i);
}
}
return list.slice();
}
// eslint-disable-next-line jsdoc/require-description
/**
* @param node a Program or BlockStatement node
* @returns the leading sequence of directive nodes in the given node's body
*/
function directives(node: TSESTree.Program | TSESTree.BlockStatement): TSESTree.Node[] {
return takeWhile(looksLikeDirective, node.body);
}
// eslint-disable-next-line jsdoc/require-description
/**
* @param node any node
* @param ancestors the given node's ancestors
* @returns whether the given node is considered a directive in its current position
*/
function isDirective(node: TSESTree.Node, ancestors: TSESTree.Node[]): boolean {
const parent = ancestors[ancestors.length - 1],
grandparent = ancestors[ancestors.length - 2];
return (parent.type === 'Program' || parent.type === 'BlockStatement' &&
(/Function/u.test(grandparent.type))) &&
directives(parent).indexOf(node) >= 0;
}
/**
* Determines whether or not a given node is a valid expression. Recurses on short circuit eval and ternary nodes if enabled by flags.
* @param node any node
* @returns whether the given node is a valid expression
*/
function isValidExpression(node: TSESTree.Node): boolean {
if (allowTernary) {
// Recursive check for ternary and logical expressions
if (node.type === 'ConditionalExpression') {
return isValidExpression(node.consequent) && isValidExpression(node.alternate);
}
}
if (allowShortCircuit) {
if (node.type === 'LogicalExpression') {
return isValidExpression(node.right);
}
}
if (allowTaggedTemplates && node.type === 'TaggedTemplateExpression') {
return true;
}
if (node.type === 'ExpressionStatement') {
return isValidExpression(node.expression);
}
return /^(?:Assignment|OptionalCall|Call|New|Update|Yield|Await|Chain)Expression$/u.test(node.type) ||
(node.type === 'UnaryExpression' && ['delete', 'void'].indexOf(node.operator) >= 0);
}
return {
ExpressionStatement(node: TSESTree.ExpressionStatement) {
if (!isValidExpression(node.expression) && !isDirective(node, <TSESTree.Node[]>context.getAncestors())) {
context.report({ node: <ESTree.Node>node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` });
}
}
};
}
};

View File

@@ -77,7 +77,7 @@ module.exports = new (_a = class ApiEventNaming {
if (def.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
return def;
}
else if ((def.type === experimental_utils_1.AST_NODE_TYPES.TSPropertySignature || def.type === experimental_utils_1.AST_NODE_TYPES.ClassProperty) && def.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
else if ((def.type === experimental_utils_1.AST_NODE_TYPES.TSPropertySignature || def.type === experimental_utils_1.AST_NODE_TYPES.Property) && def.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
return def.key;
}
return this.getIdent(def.parent);

View File

@@ -24,7 +24,7 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ allowed: string[], verbs: string[] }>context.options[0];
const config = <{ allowed: string[]; verbs: string[] }>context.options[0];
const allowed = new Set(config.allowed);
const verbs = new Set(config.verbs);
@@ -88,7 +88,7 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
if (def.type === AST_NODE_TYPES.Identifier) {
return def;
} else if ((def.type === AST_NODE_TYPES.TSPropertySignature || def.type === AST_NODE_TYPES.ClassProperty) && def.key.type === AST_NODE_TYPES.Identifier) {
} else if ((def.type === AST_NODE_TYPES.TSPropertySignature || def.type === AST_NODE_TYPES.Property) && def.key.type === AST_NODE_TYPES.Identifier) {
return def.key;
}

View File

@@ -7,7 +7,7 @@ module.exports = new class ApiEventNaming {
constructor() {
this.meta = {
messages: {
comment: 'region comments should start with the GH issue link, e.g #region https://github.com/microsoft/vscode/issues/<number>',
comment: 'region comments should start with a camel case identifier, `:`, then either a GH issue link or owner, e.g #region myProposalName: https://github.com/microsoft/vscode/issues/<number>',
}
};
}
@@ -15,14 +15,14 @@ module.exports = new class ApiEventNaming {
const sourceCode = context.getSourceCode();
return {
['Program']: (_node) => {
for (let comment of sourceCode.getAllComments()) {
for (const comment of sourceCode.getAllComments()) {
if (comment.type !== 'Line') {
continue;
}
if (!comment.value.match(/^\s*#region /)) {
if (!/^\s*#region /.test(comment.value)) {
continue;
}
if (!comment.value.match(/https:\/\/github.com\/microsoft\/vscode\/issues\/\d+/i)) {
if (!/^\s*#region ([a-z]+): (@[a-z]+|https:\/\/github.com\/microsoft\/vscode\/issues\/\d+)/i.test(comment.value)) {
context.report({
node: comment,
messageId: 'comment',

View File

@@ -9,7 +9,7 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
comment: 'region comments should start with the GH issue link, e.g #region https://github.com/microsoft/vscode/issues/<number>',
comment: 'region comments should start with a camel case identifier, `:`, then either a GH issue link or owner, e.g #region myProposalName: https://github.com/microsoft/vscode/issues/<number>',
}
};
@@ -17,18 +17,16 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
const sourceCode = context.getSourceCode();
return {
['Program']: (_node: any) => {
for (let comment of sourceCode.getAllComments()) {
for (const comment of sourceCode.getAllComments()) {
if (comment.type !== 'Line') {
continue;
}
if (!comment.value.match(/^\s*#region /)) {
if (!/^\s*#region /.test(comment.value)) {
continue;
}
if (!comment.value.match(/https:\/\/github.com\/microsoft\/vscode\/issues\/\d+/i)) {
if (!/^\s*#region ([a-z]+): (@[a-z]+|https:\/\/github.com\/microsoft\/vscode\/issues\/\d+)/i.test(comment.value)) {
context.report({
node: <any>comment,
messageId: 'comment',