fix(core): resolve some strip-source-code bugs (#15840)

This commit is contained in:
Emily Marigold Klassen 2023-03-23 08:55:54 -07:00 committed by GitHub
parent 5712abe670
commit 8af80de3e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 21 deletions

View File

@ -258,6 +258,20 @@ require('./d')`;
expect(stripSourceCode(scanner, input)).toEqual(expected); expect(stripSourceCode(scanner, input)).toEqual(expected);
}); });
it('should find an import after a template literal with a 2 variables in it', () => {
const input = `
const a = 1;
const b = 2;
const c = \`a: $\{a}, b: $\{b}\`
const d = await import('./d')
const e = require('./e')
`;
const expected = `import('./d')
require('./e')`;
expect(stripSourceCode(scanner, input)).toEqual(expected);
});
it('finds imports after an escaped character', () => { it('finds imports after an escaped character', () => {
const input = ` const input = `
const b = unquotedLiteral.replace(/"/g, '\\\\"') const b = unquotedLiteral.replace(/"/g, '\\\\"')
@ -282,4 +296,37 @@ require('./d')`;
expect(stripSourceCode(scanner, input)).toEqual(expected); expect(stripSourceCode(scanner, input)).toEqual(expected);
}); });
it('finds imports in the same line as template literals with division inside', () => {
const input = `
const a = 1;
const b = \`"$\{1 / 2} $\{await import('./b')} $\{await require('./c')}"\`;
`;
const expected = `import('./b')
require('./c')`;
expect(stripSourceCode(scanner, input)).toEqual(expected);
});
it('finds imports in the same line after a regex', () => {
const input = `
const a = 1;
const b = /"/g; const c = await import('./c'); const d = require('./d')
`;
const expected = `import('./c')
require('./d')`;
expect(stripSourceCode(scanner, input)).toEqual(expected);
});
it('finds imports inside template literals', () => {
const input = `
const a = \`"$\{require('./a')}"\`
const b = \`"$\{await import('./b')}"\`
`;
const expected = `require('./a')
import('./b')`;
expect(stripSourceCode(scanner, input)).toEqual(expected);
});
}); });

View File

@ -1,6 +1,29 @@
import type { Scanner } from 'typescript'; import type { Scanner } from 'typescript';
let SyntaxKind: typeof import('typescript').SyntaxKind; let SyntaxKind: typeof import('typescript').SyntaxKind;
function shouldRescanSlashToken(
lastNonTriviaToken: import('typescript').SyntaxKind
) {
switch (lastNonTriviaToken) {
case SyntaxKind.Identifier:
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.RegularExpressionLiteral:
case SyntaxKind.ThisKeyword:
case SyntaxKind.PlusPlusToken:
case SyntaxKind.MinusMinusToken:
case SyntaxKind.CloseParenToken:
case SyntaxKind.CloseBracketToken:
case SyntaxKind.CloseBraceToken:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
return false;
default:
return true;
}
}
export function stripSourceCode(scanner: Scanner, contents: string): string { export function stripSourceCode(scanner: Scanner, contents: string): string {
if (!SyntaxKind) { if (!SyntaxKind) {
SyntaxKind = require('typescript').SyntaxKind; SyntaxKind = require('typescript').SyntaxKind;
@ -12,9 +35,14 @@ export function stripSourceCode(scanner: Scanner, contents: string): string {
scanner.setText(contents); scanner.setText(contents);
let token = scanner.scan(); let token = scanner.scan();
let lastNonTriviaToken = SyntaxKind.Unknown;
const statements = []; const statements = [];
const templateStack = [];
let ignoringLine = false;
let braceDepth = 0;
let start = null; let start = null;
while (token !== SyntaxKind.EndOfFileToken) { while (token !== SyntaxKind.EndOfFileToken) {
const currentToken = token;
const potentialStart = scanner.getStartPos(); const potentialStart = scanner.getStartPos();
switch (token) { switch (token) {
case SyntaxKind.MultiLineCommentTrivia: case SyntaxKind.MultiLineCommentTrivia:
@ -33,21 +61,23 @@ export function stripSourceCode(scanner: Scanner, contents: string): string {
) { ) {
token = scanner.scan(); token = scanner.scan();
} }
ignoringLine = true;
// ignore next line
while (
token !== SyntaxKind.NewLineTrivia &&
token !== SyntaxKind.EndOfFileToken
) {
token = scanner.scan();
}
} }
break; break;
} }
case SyntaxKind.NewLineTrivia: {
ignoringLine = false;
token = scanner.scan();
break;
}
case SyntaxKind.RequireKeyword: case SyntaxKind.RequireKeyword:
case SyntaxKind.ImportKeyword: { case SyntaxKind.ImportKeyword: {
token = scanner.scan(); token = scanner.scan();
if (ignoringLine) {
break;
}
while ( while (
token === SyntaxKind.WhitespaceTrivia || token === SyntaxKind.WhitespaceTrivia ||
token === SyntaxKind.NewLineTrivia token === SyntaxKind.NewLineTrivia
@ -59,29 +89,44 @@ export function stripSourceCode(scanner: Scanner, contents: string): string {
} }
case SyntaxKind.TemplateHead: { case SyntaxKind.TemplateHead: {
while (true) { templateStack.push(braceDepth);
token = scanner.scan(); braceDepth = 0;
token = scanner.scan();
break;
}
if (token === SyntaxKind.SlashToken) { case SyntaxKind.SlashToken: {
token = scanner.reScanSlashToken(); if (shouldRescanSlashToken(lastNonTriviaToken)) {
} token = scanner.reScanSlashToken();
}
token = scanner.scan();
break;
}
if (token === SyntaxKind.EndOfFileToken) { case SyntaxKind.OpenBraceToken: {
// either the template is unterminated, or there ++braceDepth;
// is some other edge case we haven't compensated for token = scanner.scan();
break; break;
} }
if (token === SyntaxKind.CloseBraceToken) { case SyntaxKind.CloseBraceToken: {
token = scanner.reScanTemplateToken(false); if (braceDepth) {
break; --braceDepth;
} else if (templateStack.length) {
token = scanner.reScanTemplateToken(false);
if (token === SyntaxKind.LastTemplateToken) {
braceDepth = templateStack.pop();
} }
} }
token = scanner.scan();
break; break;
} }
case SyntaxKind.ExportKeyword: { case SyntaxKind.ExportKeyword: {
token = scanner.scan(); token = scanner.scan();
if (ignoringLine) {
break;
}
while ( while (
token === SyntaxKind.WhitespaceTrivia || token === SyntaxKind.WhitespaceTrivia ||
token === SyntaxKind.NewLineTrivia token === SyntaxKind.NewLineTrivia
@ -117,6 +162,10 @@ export function stripSourceCode(scanner: Scanner, contents: string): string {
token = scanner.scan(); token = scanner.scan();
} }
} }
if (currentToken > SyntaxKind.LastTriviaToken) {
lastNonTriviaToken = currentToken;
}
} }
return statements.join('\n'); return statements.join('\n');