diff --git a/rules/string-content.js b/rules/string-content.js index a48eab1c32..894184db1f 100644 --- a/rules/string-content.js +++ b/rules/string-content.js @@ -8,6 +8,11 @@ const defaultPatterns = { const defaultMessage = 'Prefer `{{suggest}}` over `{{match}}`.'; +const escapeTemplateElementRaw = string => string.replace( + /(?<=(?:^|[^\\])(?:\\\\)*)(?(?:`|\$(?={)))/g, + '\\$' +); + function getReplacements(patterns) { return Object.entries({ ...defaultPatterns, @@ -88,8 +93,11 @@ const create = context => { const fixRange = [start + 1, end - 1]; problem.fix = fixer => fixer.replaceTextRange(fixRange, fixed); } else { - fixed = fixed.replace(/`/g, '\\`').replace(/\$(?={)/g, '\\$'); - problem.fix = fixer => replaceTemplateElement(fixer, node, fixed); + problem.fix = fixer => replaceTemplateElement( + fixer, + node, + escapeTemplateElementRaw(fixed) + ); } context.report(problem); diff --git a/test/string-content.js b/test/string-content.js index 41a06cce5a..8b9e986c27 100644 --- a/test/string-content.js +++ b/test/string-content.js @@ -37,8 +37,12 @@ ruleTester.run('string-content', rule, { code: 'const foo = \'\\\'\'', options: [{patterns: {'\'': false}}] }, + /* eslint-disable no-template-curly-in-string */ // `TemplateLiteral` - 'const foo = `🦄`' + 'const foo = `🦄`', + // Should not escape + 'const foo = `\\`\\${1}`' + /* eslint-enable no-template-curly-in-string */ ], invalid: [ // `Literal` string @@ -144,16 +148,28 @@ ruleTester.run('string-content', rule, { }, // Escape { - code: 'const foo = `foo`', - output: 'const foo = `bar\\`bar`', + code: 'const foo = `foo_foo`', + output: 'const foo = `bar\\`bar_bar\\`bar`', options: [{patterns: {foo: 'bar`bar'}}], errors: createError('foo', 'bar`bar') }, { - code: 'const foo = `foo`', - output: 'const foo = `\\${bar}`', + code: 'const foo = `foo_foo`', + output: 'const foo = `\\${bar}_\\${bar}`', options: [{patterns: {foo: '${bar}'}}], errors: createError('foo', '${bar}') + }, + { + code: 'const foo = `$foo`', // <-- not escaped $ + output: 'const foo = `\\${bar}`', + options: [{patterns: {foo: '{bar}'}}], + errors: createError('foo', '{bar}') + }, + { + code: 'const foo = `\\$foo`', // <-- escaped $ + output: 'const foo = `\\${bar}`', + options: [{patterns: {foo: '{bar}'}}], + errors: createError('foo', '{bar}') } /* eslint-enable no-template-curly-in-string */ ]