Add noShadowRestrictedNames lint rule
MODIFY
packages/@romejs/js-compiler/__rtests__/lint.ts
packages/@romejs/js-compiler/__rtests__/lint.ts
*/
import test from '@romejs/test';
-import lint from '../api/lint';
+import lint, {LintResult} from '../api/lint';
import {parseJS} from '@romejs/js-parser';
import {createUnknownFilePath} from '@romejs/path';
import {DEFAULT_PROJECT_CONFIG, ProjectConfig} from '@romejs/project';
@@ -219,3 +219,44 @@ test('no duplicate keys', async t => {
},
]);
});
+
+test('no shadow restrcited names', async t => {
+ const getNoShadowDiagnostics = (result: LintResult) =>
+ result.diagnostics.filter(
+ d => d.category === 'lint/noShadowRestrictedNames',
+ );
+
+ const valid = await testLint(
+ `
+ function SomeFn(param) {
+ let someVar;
+ !function SomeOtherFn(otherParam) {
+ try {
+ } catch (e) {}
+ };
+ }
+ `,
+ LINT_ENABLED_FORMAT_DISABLED_CONFIG,
+ );
+
+ t.is(getNoShadowDiagnostics(valid).length, 0);
+
+ const invalid = await testLint(
+ `
+ function NaN(undefined) {
+ let eval;
+ !function Array(window) {
+ try {
+ } catch (Object) {}
+ };
+ }
+ `,
+ LINT_ENABLED_FORMAT_DISABLED_CONFIG,
+ );
+
+ const noShadowDiagnostics = getNoShadowDiagnostics(invalid);
+
+ t.is(noShadowDiagnostics.length, 6);
+
+ t.snapshot(noShadowDiagnostics);
+});

MODIFY
packages/@romejs/js-compiler/transforms/lint/index.ts
packages/@romejs/js-compiler/transforms/lint/index.ts
@@ -14,6 +14,7 @@ import unsafeNegation from './unsafeNegation';
import noAsyncPromiseExecutor from './noAsyncPromiseExecutor';
import noLabelVar from './noLabelVar';
import noDuplicateKeys from './noDuplicateKeys';
+import noShadowRestrictedNames from './noShadowRestrictedNames';
export const lintTransforms = [
undeclaredVariables,
@@ -25,4 +26,5 @@ export const lintTransforms = [
noAsyncPromiseExecutor,
noLabelVar,
noDuplicateKeys,
+ noShadowRestrictedNames,
];

ADD
packages/@romejs/js-compiler/transforms/lint/noShadowRestrictedNames.ts
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import {Path} from '@romejs/js-compiler';
+import {TransformExitResult} from '@romejs/js-compiler/types';
+import {
+ VariableDeclaration,
+ FunctionDeclaration,
+ CatchClause,
+ BindingIdentifier,
+ FunctionExpression,
+} from '@romejs/js-ast';
+import {getBindingIdentifiers} from '@romejs/js-ast-utils';
+import {markup} from '@romejs/string-markup';
+
+function extractBindingIdentifiers(
+ node:
+ | VariableDeclaration
+ | FunctionDeclaration
+ | FunctionExpression
+ | CatchClause,
+): BindingIdentifier[] {
+ if (
+ node.type === 'FunctionDeclaration' ||
+ node.type === 'FunctionExpression'
+ ) {
+ const bindings = getBindingIdentifiers(node.head);
+
+ if (node.id !== undefined) {
+ bindings.push(node.id);
+ }
+
+ return bindings;
+ }
+
+ if (node.type === 'VariableDeclaration' || node.param) {
+ return getBindingIdentifiers(node);
+ }
+
+ return [];
+}
+
+export default {
+ name: 'noShadowRestrictedNames',
+ enter(path: Path): TransformExitResult {
+ const {node, context} = path;
+
+ if (
+ node.type === 'VariableDeclaration' ||
+ node.type === 'FunctionDeclaration' ||
+ node.type === 'FunctionExpression' ||
+ node.type === 'CatchClause'
+ ) {
+ const bindings = extractBindingIdentifiers(node);
+
+ for (const binding of bindings) {
+ if (context.getRootScope().isGlobal(binding.name)) {
+ context.addNodeDiagnostic(binding, {
+ category: 'lint/noShadowRestrictedNames',
+ message: markup`Shadowing of global property <emphasis>${binding.name}</emphasis>`,
+ });
+ }
+ }
+ }
+
+ return node;
+ },
+};

Add noShadowRestrictedNames lint rule