js-compiler: add lint no-async-promise-executor
MODIFY
packages/@romejs/js-compiler/__rtests__/__rsnapshots__/lint.ts.rsnap
packages/@romejs/js-compiler/__rtests__/__rsnapshots__/lint.ts.rsnap
{
"empty file": "Object {\n diagnostics: Array []\n src: ''\n ast: Program {\n body: Array []\n comments: Array []\n diagnostics: Array []\n directives: Array []\n filename: 'unknown'\n hasHoistedVars: false\n interpreter: undefined\n mtime: undefined\n sourceType: 'module'\n syntax: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 0\n index: 0\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n }\n}",
- "undeclared variable": "Object {\n src: 'foobar;'\n diagnostics: Array [\n Object {\n category: 'lint/undeclaredVariables'\n filename: 'unknown'\n language: 'js'\n message: 'Undeclared variable <emphasis>foobar</emphasis>'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 6\n index: 6\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n ]\n ast: Program {\n comments: Array []\n diagnostics: Array []\n directives: Array []\n filename: 'unknown'\n hasHoistedVars: false\n interpreter: undefined\n mtime: undefined\n sourceType: 'module'\n syntax: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 7\n index: 7\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n body: Array [\n ExpressionStatement {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 7\n index: 7\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n expression: ReferenceIdentifier {\n name: 'foobar'\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 6\n index: 6\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n }\n }\n ]\n }\n}"
+ "undeclared variable": "Object {\n src: 'foobar;'\n diagnostics: Array [\n Object {\n category: 'lint/undeclaredVariables'\n filename: 'unknown'\n language: 'js'\n message: 'Undeclared variable <emphasis>foobar</emphasis>'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 6\n index: 6\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n ]\n ast: Program {\n comments: Array []\n diagnostics: Array []\n directives: Array []\n filename: 'unknown'\n hasHoistedVars: false\n interpreter: undefined\n mtime: undefined\n sourceType: 'module'\n syntax: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 7\n index: 7\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n body: Array [\n ExpressionStatement {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 7\n index: 7\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n expression: ReferenceIdentifier {\n name: 'foobar'\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 6\n index: 6\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n }\n }\n ]\n }\n}",
+ "no async promise executor": "Object {\n src: 'new Promise(async function foo() {})'\n diagnostics: Array [\n Object {\n category: 'lint/noAsyncPromiseExecutor'\n filename: 'unknown'\n language: 'js'\n message: 'Promise executor functions should not be async.'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 35\n index: 35\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\n }\n }\n ]\n ast: Program {\n comments: Array []\n diagnostics: Array []\n directives: Array []\n filename: 'unknown'\n hasHoistedVars: false\n interpreter: undefined\n mtime: undefined\n sourceType: 'module'\n syntax: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 36\n index: 36\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n body: Array [\n ExpressionStatement {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 36\n index: 36\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n expression: NewExpression {\n optional: undefined\n typeArguments: undefined\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 36\n index: 36\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n callee: ReferenceIdentifier {\n name: 'Promise'\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 11\n index: 11\n line: 1\n }\n start: Object {\n column: 4\n index: 4\n line: 1\n }\n }\n }\n arguments: Array [\n FunctionExpression {\n id: BindingIdentifier {\n name: 'foo'\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 30\n index: 30\n line: 1\n }\n start: Object {\n column: 27\n index: 27\n line: 1\n }\n }\n }\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 35\n index: 35\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\n }\n }\n body: BlockStatement {\n body: Array []\n directives: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 35\n index: 35\n line: 1\n }\n start: Object {\n column: 33\n index: 33\n line: 1\n }\n }\n }\n head: FunctionHead {\n async: true\n generator: false\n hasHoistedVars: false\n params: Array []\n predicate: undefined\n rest: undefined\n returnType: undefined\n thisType: undefined\n typeParameters: undefined\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 33\n index: 33\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\n }\n }\n }\n }\n ]\n }\n }\n ]\n }\n}",
+ "no async promise executor: 1": "Object {\n src: 'new Promise(async () => {})'\n diagnostics: Array [\n Object {\n category: 'lint/noAsyncPromiseExecutor'\n filename: 'unknown'\n language: 'js'\n message: 'Promise executor functions should not be async.'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 26\n index: 26\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\n }\n }\n ]\n ast: Program {\n comments: Array []\n diagnostics: Array []\n directives: Array []\n filename: 'unknown'\n hasHoistedVars: false\n interpreter: undefined\n mtime: undefined\n sourceType: 'module'\n syntax: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 27\n index: 27\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n body: Array [\n ExpressionStatement {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 27\n index: 27\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n expression: NewExpression {\n optional: undefined\n typeArguments: undefined\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 27\n index: 27\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n callee: ReferenceIdentifier {\n name: 'Promise'\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 11\n index: 11\n line: 1\n }\n start: Object {\n column: 4\n index: 4\n line: 1\n }\n }\n }\n arguments: Array [\n ArrowFunctionExpression {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 26\n index: 26\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\n }\n }\n body: BlockStatement {\n body: Array []\n directives: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 26\n index: 26\n line: 1\n }\n start: Object {\n column: 24\n index: 24\n line: 1\n }\n }\n }\n head: FunctionHead {\n async: true\n hasHoistedVars: false\n params: Array []\n rest: undefined\n returnType: undefined\n thisType: undefined\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 24\n index: 24\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\n }\n }\n }\n }\n ]\n }\n }\n ]\n }\n}",
+ "no async promise executor: 2": "Object {\n src: 'new Promise(((((async () => {})))))'\n diagnostics: Array [\n Object {\n category: 'lint/noAsyncPromiseExecutor'\n filename: 'unknown'\n language: 'js'\n message: 'Promise executor functions should not be async.'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 30\n index: 30\n line: 1\n }\n start: Object {\n column: 16\n index: 16\n line: 1\n }\n }\n ]\n ast: Program {\n comments: Array []\n diagnostics: Array []\n directives: Array []\n filename: 'unknown'\n hasHoistedVars: false\n interpreter: undefined\n mtime: undefined\n sourceType: 'module'\n syntax: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 35\n index: 35\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n body: Array [\n ExpressionStatement {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 35\n index: 35\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n expression: NewExpression {\n optional: undefined\n typeArguments: undefined\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 35\n index: 35\n line: 1\n }\n start: Object {\n column: 0\n index: 0\n line: 1\n }\n }\n callee: ReferenceIdentifier {\n name: 'Promise'\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 11\n index: 11\n line: 1\n }\n start: Object {\n column: 4\n index: 4\n line: 1\n }\n }\n }\n arguments: Array [\n ArrowFunctionExpression {\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 30\n index: 30\n line: 1\n }\n start: Object {\n column: 16\n index: 16\n line: 1\n }\n }\n body: BlockStatement {\n body: Array []\n directives: Array []\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 30\n index: 30\n line: 1\n }\n start: Object {\n column: 28\n index: 28\n line: 1\n }\n }\n }\n head: FunctionHead {\n async: true\n hasHoistedVars: false\n params: Array []\n rest: undefined\n returnType: undefined\n thisType: undefined\n loc: Object {\n filename: 'unknown'\n end: Object {\n column: 28\n index: 28\n line: 1\n }\n start: Object {\n column: 16\n index: 16\n line: 1\n }\n }\n }\n }\n ]\n }\n }\n ]\n }\n}"
}
\ No newline at end of file

MODIFY
packages/@romejs/js-compiler/__rtests__/lint.ts
packages/@romejs/js-compiler/__rtests__/lint.ts
@@ -79,6 +79,31 @@ test('undeclared variable', async t => {
]);
});
+test('no async promise executor', async t => {
+ const validTestCases = [
+ 'new Promise(() => {})',
+ 'new Promise(() => {}, async function unrelated() {})',
+ 'class Foo {} new Foo(async () => {})',
+ ];
+ const invalidTestCases = [
+ 'new Promise(async function foo() {})',
+ 'new Promise(async () => {})',
+ 'new Promise(((((async () => {})))))',
+ ];
+ for (const validTestCase of validTestCases) {
+ const {diagnostics} = await testLint(
+ validTestCase,
+ LINT_ENABLED_FORMAT_DISABLED_CONFIG,
+ );
+ t.is(diagnostics.length, 0);
+ }
+ for (const invalidTestCase of invalidTestCases) {
+ t.snapshot(
+ await testLint(invalidTestCase, LINT_ENABLED_FORMAT_DISABLED_CONFIG),
+ );
+ }
+});
+
test('format disabled in project config should not regenerate the file', async t => {
// Intentionally weird formatting
const sourceText = 'foobar ( "yes" );';

MODIFY
packages/@romejs/js-compiler/transforms/lint/index.ts
packages/@romejs/js-compiler/transforms/lint/index.ts
@@ -9,10 +9,12 @@ import defaultExportSameBasename from './defaultExportSameBasename';
import undeclaredVariables from './undeclaredVariables';
import unusedVariables from './unusedVariables';
import emptyBlocks from './emptyBlocks';
+import noAsyncPromiseExecutor from './noAsyncPromiseExecutor';
export const lintTransforms = [
undeclaredVariables,
defaultExportSameBasename,
unusedVariables,
emptyBlocks,
+ noAsyncPromiseExecutor,
];

ADD
packages/@romejs/js-compiler/transforms/lint/noAsyncPromiseExecutor.ts
+import {Path} from '@romejs/js-compiler';
+import {TransformExitResult} from '@romejs/js-compiler/types';
+
+export default {
+ name: 'noAsyncPromiseExecutor',
+ enter(path: Path): TransformExitResult {
+ const {node, context} = path;
+
+ if (
+ node.type === 'NewExpression' &&
+ node.callee.type === 'ReferenceIdentifier' &&
+ node.callee.name === 'Promise' &&
+ node.arguments.length > 0 &&
+ (node.arguments[0].type === 'ArrowFunctionExpression' ||
+ node.arguments[0].type === 'FunctionExpression') &&
+ node.arguments[0].head.async
+ ) {
+ context.addNodeDiagnostic(node.arguments[0], {
+ category: 'lint/noAsyncPromiseExecutor',
+ message: 'Promise executor functions should not be async.',
+ });
+ }
+
+ return node;
+ },
+};

js-compiler: add lint no-async-promise-executor