This commit is contained in:
2021-04-19 20:16:55 +02:00
commit a0ff94dca2
839 changed files with 198976 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
ESLint
Copyright jQuery Foundation and other contributors, https://jquery.org/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,5 @@
This directory contains the Catapult eslint config, custom Catapult eslint rules,
and tests for those rules.
Some of our custom rules are modified versions of those included with eslint, as
suggested in https://goo.gl/uAxFHq.

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import os
import sys
_CATAPULT_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__),
os.path.pardir, os.path.pardir, os.path.pardir))
_ESLINT_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir))
DIRECTORIES_TO_LINT = [
os.path.join(_CATAPULT_PATH, 'dashboard', 'dashboard'),
os.path.join(_CATAPULT_PATH, 'tracing', 'tracing')
]
def _AddToPathIfNeeded(path):
if path not in sys.path:
sys.path.insert(0, path)
if __name__ == '__main__':
_AddToPathIfNeeded(_ESLINT_PATH)
import eslint
parser = argparse.ArgumentParser(
description='Wrapper script to run eslint on Catapult code')
parser.add_argument('--paths', '-p', default=None, nargs='+', metavar='PATH',
help='List of paths to lint')
parser.add_argument('--all', default=None, action='store_true',
help='Runs eslint on all applicable Catapult code')
parser.add_argument('--extra-args', default=None, type=str,
help='A string of extra arguments to pass to eslint')
args = parser.parse_args(sys.argv[1:])
if ((args.paths is not None and args.all is not None) or
(args.paths is None and args.all is None)):
print 'Either --paths or --all must be used, but not both.\n'
parser.print_help()
sys.exit(1)
paths = DIRECTORIES_TO_LINT if args.all else args.paths
success, output = eslint.RunEslint(paths, extra_args=args.extra_args)
print output
sys.exit(not success)

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import sys
_CATAPULT_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__),
os.path.pardir, os.path.pardir, os.path.pardir))
_ESLINT_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir))
def _RunTestsOrDie(top_level_dir):
exit_code = run_with_typ.Run(top_level_dir, path=[_ESLINT_PATH])
if exit_code:
sys.exit(exit_code)
def _AddToPathIfNeeded(path):
if path not in sys.path:
sys.path.insert(0, path)
if __name__ == '__main__':
_AddToPathIfNeeded(_CATAPULT_PATH)
from catapult_build import run_with_typ
_RunTestsOrDie(os.path.join(_ESLINT_PATH, 'eslint'))

View File

@@ -0,0 +1,68 @@
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import subprocess
import sys
_CATAPULT_PATH = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
os.path.pardir, os.path.pardir, os.path.pardir)
def _AddToPathIfNeeded(path):
if path not in sys.path:
sys.path.insert(0, path)
def _UpdateSysPathIfNeeded():
_AddToPathIfNeeded(os.path.join(_CATAPULT_PATH, 'common', 'node_runner'))
_AddToPathIfNeeded(os.path.join(_CATAPULT_PATH, 'common', 'py_utils'))
_UpdateSysPathIfNeeded()
import py_utils
from node_runner import node_util
BASE_ESLINT_CMD = [
node_util.GetNodePath(),
os.path.join(node_util.GetNodeModulesPath(), 'eslint', 'bin', 'eslint.js'),
'--color'
]
DEFAULT_ESLINT_RULES_DIR = os.path.join(
py_utils.GetCatapultDir(), 'common', 'eslint', 'rules')
def _CreateEslintCommand(rulesdir, extra_args):
eslint_cmd = BASE_ESLINT_CMD + [
'--rulesdir', rulesdir, '--ext', '.js,.html'
]
if extra_args:
eslint_cmd.extend(extra_args.strip().split(' '))
return eslint_cmd
def RunEslint(paths, rules_dir=DEFAULT_ESLINT_RULES_DIR, extra_args=None):
"""Runs eslint on a list of paths.
Args:
paths: A list of paths to run eslint on.
rules_dir: A directory of custom eslint rules.
extra_args: A string to append to the end of the eslint command.
"""
if type(paths) is not list or len(paths) == 0:
raise ValueError('Must specify a non-empty list of paths to lint.')
try:
eslint_cmd = _CreateEslintCommand(rules_dir, extra_args)
return True, subprocess.check_output(eslint_cmd + paths,
stderr=subprocess.STDOUT).rstrip()
except subprocess.CalledProcessError as e:
return False, e.output.rstrip()

View File

@@ -0,0 +1,36 @@
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import eslint
import os
import tempfile
import unittest
_TEMP_FILE_CONTENTS = '''<!DOCTYPE html>
<!--
Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<script>
// This should cause a linter error because we require camelCase.
var non_camel_case = 0;
</script>
'''
class SmokeTest(unittest.TestCase):
def testEslintFindsError(self):
try:
tmp_file = tempfile.NamedTemporaryFile(
delete=False, dir=os.path.dirname(__file__), suffix=".html")
tmp_file.write(_TEMP_FILE_CONTENTS)
tmp_file.close()
success, output = eslint.RunEslint([tmp_file.name])
self.assertFalse(success)
self.assertTrue('is not in camel case' in output)
finally:
os.remove(tmp_file.name)

View File

@@ -0,0 +1,154 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable */
/**
* @fileoverview Rule to flag non-camelcased identifiers
* @author Nicholas C. Zakas
*/
'use strict';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "enforce Catapult camelcase naming convention",
category: "Stylistic Issues",
recommended: false
},
schema: [
{
type: "object",
properties: {
properties: {
enum: ["always", "never"]
}
},
additionalProperties: false
}
]
},
create(context) {
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation
var reported = [];
/**
* Checks if a string contains an underscore and isn't all upper-case
* @param {string} name The string to check.
* @returns {boolean} if the string is underscored
* @private
*/
function isUnderscored(name) {
// if there's an underscore, it might be A_VARANT, which is okay
return name.indexOf("_") > -1 && name !== name.toUpperCase();
}
/**
* Reports an AST node as a rule violation.
* @param {ASTNode} node The node to report.
* @returns {void}
* @private
*/
function report(node) {
if (reported.indexOf(node) < 0) {
reported.push(node);
context.report(node, "Identifier '{{name}}' is not in camel case.", { name: node.name });
}
}
var options = context.options[0] || {};
let properties = options.properties || "";
if (properties !== "always" && properties !== "never") {
properties = "always";
}
return {
Identifier(node) {
/*
* Leading and trailing underscores are commonly used to flag
* private/protected identifiers, strip them.
*
* NOTE: This has four Catapult-specific style exceptions:
*
* - The prefix opt_
* - The prefix g_
* - The suffix _smallerIsBetter
* - The suffix _biggerIsBetter
*/
var name = node.name.replace(/(?:^opt_)|^(?:^g_)|^_+|_+$|(?:_smallerIsBetter)$|(?:_biggerIsBetter)$/g, ""),
effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
// MemberExpressions get special rules
if (node.parent.type === "MemberExpression") {
// "never" check properties
if (properties === "never") {
return;
}
// Always report underscored object names
if (node.parent.object.type === "Identifier" &&
node.parent.object.name === node.name &&
isUnderscored(name)) {
report(node);
// Report AssignmentExpressions only if they are the left side of the assignment
} else if (effectiveParent.type === "AssignmentExpression" &&
isUnderscored(name) &&
(effectiveParent.right.type !== "MemberExpression" ||
effectiveParent.left.type === "MemberExpression" &&
effectiveParent.left.property.name === node.name)) {
report(node);
}
// Properties have their own rules
} else if (node.parent.type === "Property") {
// "never" check properties
if (properties === "never") {
return;
}
if (node.parent.parent && node.parent.parent.type === "ObjectPattern" &&
node.parent.key === node && node.parent.value !== node) {
return;
}
if (isUnderscored(name) && effectiveParent.type !== "CallExpression") {
report(node);
}
// Check if it's an import specifier
} else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) {
// Report only if the local imported identifier is underscored
if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) {
report(node);
}
// Report anything that is underscored that isn't a CallExpression
} else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") {
report(node);
}
}
};
}
};

View File

@@ -0,0 +1,324 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable */
/**
* @fileoverview Tests for camelcase rule.
* @author Nicholas C. Zakas
*/
'use strict';
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
var rule = require("../rules/catapult-camelcase"),
RuleTester = require("../../node_runner/node_runner/node_modules/eslint/lib/testers/rule-tester");
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
var ruleTester = new RuleTester();
ruleTester.run("camelcase", rule, {
valid: [
"firstName = \"Nicholas\"",
"FIRST_NAME = \"Nicholas\"",
"__myPrivateVariable = \"Patrick\"",
"myPrivateVariable_ = \"Patrick\"",
"function doSomething(){}",
"do_something()",
"foo.do_something()",
"var foo = bar.baz_boom;",
"var foo = bar.baz_boom.something;",
"foo.boom_pow.qux = bar.baz_boom.something;",
"if (bar.baz_boom) {}",
"var obj = { key: foo.bar_baz };",
"var arr = [foo.bar_baz];",
"[foo.bar_baz]",
"var arr = [foo.bar_baz.qux];",
"[foo.bar_baz.nesting]",
"if (foo.bar_baz === boom.bam_pow) { [foo.baz_boom] }",
// These tests are for Catapult-specific exceptions.
"opt_firstName = \"Nicholas\"",
"g_firstName = \"Nicholas\"",
"sizeInBytes_smallerIsBetter = \"Nicholas\"",
"sizeInBytes_biggerIsBetter = \"Nicholas\"",
{
code: "var o = {key: 1}",
options: [{properties: "always"}]
},
{
code: "var o = {bar_baz: 1}",
options: [{properties: "never"}]
},
{
code: "obj.a_b = 2;",
options: [{properties: "never"}]
},
{
code: "var obj = {\n a_a: 1 \n};\n obj.a_b = 2;",
options: [{properties: "never"}]
},
{
code: "obj.foo_bar = function(){};",
options: [{properties: "never"}]
},
{
code: "var { category_id: category } = query;",
parserOptions: { ecmaVersion: 6 }
},
{
code: "var { category_id: category } = query;",
parserOptions: { ecmaVersion: 6 },
options: [{properties: "never"}]
},
{
code: "import { camelCased } from \"external module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" }
},
{
code: "import { no_camelcased as camelCased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" }
},
{
code: "import { no_camelcased as camelCased, anoterCamelCased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" }
}
],
invalid: [
{
code: "first_name = \"Nicholas\"",
errors: [
{
message: "Identifier 'first_name' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "__private_first_name = \"Patrick\"",
errors: [
{
message: "Identifier '__private_first_name' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "function foo_bar(){}",
errors: [
{
message: "Identifier 'foo_bar' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "obj.foo_bar = function(){};",
errors: [
{
message: "Identifier 'foo_bar' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "bar_baz.foo = function(){};",
errors: [
{
message: "Identifier 'bar_baz' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "[foo_bar.baz]",
errors: [
{
message: "Identifier 'foo_bar' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "if (foo.bar_baz === boom.bam_pow) { [foo_bar.baz] }",
errors: [
{
message: "Identifier 'foo_bar' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "foo.bar_baz = boom.bam_pow",
errors: [
{
message: "Identifier 'bar_baz' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "var foo = { bar_baz: boom.bam_pow }",
errors: [
{
message: "Identifier 'bar_baz' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "foo.qux.boom_pow = { bar: boom.bam_pow }",
errors: [
{
message: "Identifier 'boom_pow' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "var o = {bar_baz: 1}",
options: [{properties: "always"}],
errors: [
{
message: "Identifier 'bar_baz' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "obj.a_b = 2;",
options: [{properties: "always"}],
errors: [
{
message: "Identifier 'a_b' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "obj.a_b = 2;",
options: [{properties: "always"}],
errors: [
{
message: "Identifier 'a_b' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "var { category_id: category_id } = query;",
parserOptions: { ecmaVersion: 6 },
errors: [
{
message: "Identifier 'category_id' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "var { category_id } = query;",
parserOptions: { ecmaVersion: 6 },
errors: [
{
message: "Identifier 'category_id' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import no_camelcased from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camelcased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import * as no_camelcased from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camelcased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import { no_camelcased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camelcased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import { no_camelcased as no_camel_cased } from \"external module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camel_cased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import { camelCased as no_camel_cased } from \"external module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camel_cased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import { camelCased, no_camelcased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camelcased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import { no_camelcased as camelCased, another_no_camelcased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'another_no_camelcased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import camelCased, { no_camelcased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camelcased' is not in camel case.",
type: "Identifier"
}
]
},
{
code: "import no_camelcased, { another_no_camelcased as camelCased } from \"external-module\";",
parserOptions: { ecmaVersion: 6, sourceType: "module" },
errors: [
{
message: "Identifier 'no_camelcased' is not in camel case.",
type: "Identifier"
}
]
}
]
});