implement prefer-template lint rule
MODIFY
packages/@romejs/js-compiler/__rtests__/__rsnapshots__/lint.ts.rsnap
packages/@romejs/js-compiler/__rtests__/__rsnapshots__/lint.ts.rsnap
"no async promise executor": "Object {\n filters: Array []\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}",
"no cond assign: 3": "Object {\n filters: Array []\n src: 'do {\\n console.log(\\'foo)\\n } while (foo = \\'bar\\')'\n diagnostics: Array [\n Object {\n advice: undefined\n category: 'parse/js'\n filename: 'unknown'\n message: 'Unterminated string constant'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'js-parser'}]\n end: Object {\n column: 0\n index: 28\n line: 3\n }\n start: Object {\n column: 0\n index: 28\n line: 3\n }\n }\n Object {\n category: 'lint/undeclaredVariables'\n filename: 'unknown'\n language: 'js'\n message: 'Undeclared variable <emphasis>INVALID_PLACEHOLDER</emphasis>'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 50\n index: 55\n line: 2\n }\n start: Object {\n column: 50\n index: 55\n line: 2\n }\n }\n Object {\n category: 'lint/undeclaredVariables'\n filename: 'unknown'\n language: 'js'\n message: 'Undeclared variable <emphasis>bar</emphasis>'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 47\n index: 52\n line: 2\n }\n start: Object {\n column: 44\n index: 49\n line: 2\n }\n }\n ]\n}",
"no async promise executor: 1": "Object {\n filters: Array []\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}",
- "no async promise executor: 2": "Object {\n filters: Array []\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}"
+ "no async promise executor: 2": "Object {\n filters: Array []\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}",
+ "prefer template": "Object {\n filters: Array []\n src: 'const foo = \\'bar\\'; console.log(foo + \\'baz\\')'\n diagnostics: Array [\n Object {\n category: 'lint/preferTemplate'\n filename: 'unknown'\n language: 'js'\n message: 'You\\'re using string concatenation when template literals are preferred'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 42\n index: 42\n line: 1\n }\n start: Object {\n column: 31\n index: 31\n line: 1\n }\n }\n ]\n}",
+ "prefer template: 1": "Object {\n filters: Array []\n src: 'console.log((1 * 2) + \\'baz\\')'\n diagnostics: Array [\n Object {\n category: 'lint/preferTemplate'\n filename: 'unknown'\n language: 'js'\n message: 'You\\'re using string concatenation when template literals are preferred'\n mtime: undefined\n sourceType: 'module'\n origins: Array [Object {category: 'lint'}]\n end: Object {\n column: 27\n index: 27\n line: 1\n }\n start: Object {\n column: 12\n index: 12\n line: 1\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
@@ -464,6 +464,22 @@ test('no template curly in string', async t => {
]);
});
+test('prefer template', async t => {
+ const template1 = await testLint(
+ `const foo = 'bar'; console.log(foo + 'baz')`,
+ LINT_ENABLED_FORMAT_DISABLED_CONFIG,
+ );
+
+ t.snapshot(template1);
+
+ const template2 = await testLint(
+ `console.log((1 * 2) + 'baz')`,
+ LINT_ENABLED_FORMAT_DISABLED_CONFIG,
+ );
+
+ t.snapshot(template2);
+});
+
test('no import assign', async t => {
let failingCases = [
'import x from "y";\nx=1;',

MODIFY
packages/@romejs/js-compiler/transforms/lint/index.ts
packages/@romejs/js-compiler/transforms/lint/index.ts
@@ -16,6 +16,7 @@ import noDebugger from './noDebugger';
import noDuplicateKeys from './noDuplicateKeys';
import noDupeArgs from './noDupeArgs';
import noLabelVar from './noLabelVar';
+import preferTemplate from './preferTemplate';
import undeclaredVariables from './undeclaredVariables';
import unsafeNegation from './unsafeNegation';
import unusedVariables from './unusedVariables';
@@ -28,19 +29,20 @@ export const lintTransforms = [
defaultExportSameBasename,
disallowVar,
emptyBlocks,
- sparseArray,
- noCompareNegZero,
- unsafeNegation,
noAsyncPromiseExecutor,
+ noCompareNegZero,
noCondAssign,
- noDuplicateKeys,
+ noDebugger,
+ noDeleteVars,
noDupeArgs,
+ noDuplicateKeys,
+ noImportAssign,
noLabelVar,
+ noTemplateCurlyInString,
+ noUnsafeFinally,
+ preferTemplate,
+ sparseArray,
undeclaredVariables,
+ unsafeNegation,
unusedVariables,
- noUnsafeFinally,
- noDeleteVars,
- noTemplateCurlyInString,
- noImportAssign,
- noDebugger,
];

ADD
packages/@romejs/js-compiler/transforms/lint/preferTemplate.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 {AnyNode} from '@romejs/js-ast';
+
+export default {
+ name: 'sparseArray',
+ enter(path: Path): AnyNode {
+ const {node} = path;
+
+ if (
+ node.type === 'BinaryExpression' &&
+ node.operator === '+' &&
+ (node.left.type === 'StringLiteral' ||
+ node.right.type === 'StringLiteral')
+ ) {
+ path.context.addNodeDiagnostic(node, {
+ category: 'lint/preferTemplate',
+ message:
+ "You're using string concatenation when template literals are preferred",
+ });
+ }
+
+ return node;
+ },
+};

implement prefer-template lint rule