[web] Fix some regex issues in the sdk_rewriter (#25866)

diff --git a/web_sdk/sdk_rewriter.dart b/web_sdk/sdk_rewriter.dart
index dfa63e2..ceab562 100644
--- a/web_sdk/sdk_rewriter.dart
+++ b/web_sdk/sdk_rewriter.dart
@@ -18,17 +18,17 @@
   ..addOption('stamp');
 
 final List<Replacer> uiPatterns = <Replacer>[
-  AllReplacer('library ui;', 'library dart.ui;'),
-  AllReplacer('part of ui;', 'part of dart.ui;'),
-  AllReplacer(r'''
-import 'src/engine.dart' as engine;
-''', r'''
+  AllReplacer(RegExp(r'library\s+ui;'), 'library dart.ui;'),
+  AllReplacer(RegExp(r'part\s+of\s+ui;'), 'part of dart.ui;'),
+  AllReplacer(RegExp(r'''
+import\s*'src/engine.dart'\s*as\s+engine;
+'''), r'''
 import 'dart:_engine' as engine;
 '''),
-  AllReplacer(
+  AllReplacer(RegExp(
     r'''
-export 'src/engine.dart'
-''',
+export\s*'src/engine.dart'
+'''),
     r'''
 export 'dart:_engine'
 ''',
@@ -36,44 +36,44 @@
 ];
 
 final List<Replacer> engineLibraryPatterns = <Replacer>[
-  AllReplacer('library engine;', 'library dart._engine;'),
-  AllReplacer(r'''
-import '../ui.dart' as ui;
-''', r'''
+  AllReplacer(RegExp(r'library\s+engine;'), 'library dart._engine;'),
+  AllReplacer(RegExp(r'''
+import\s*'../ui.dart' as ui;
+'''), r'''
 import 'dart:ui' as ui;
 '''),
-  AllReplacer(r'''
-import 'package:ui/ui.dart' as ui;
-''', r'''
+  AllReplacer(RegExp(r'''
+import\s*'package:ui/ui.dart' as ui;
+'''), r'''
 import 'dart:ui' as ui;
 '''),
   // Remove imports of engine part files.
-  AllReplacer(RegExp(r"import 'engine/.*';"), ''),
+  AllReplacer(RegExp(r"import\s*'engine/.*';"), ''),
   // Replace exports of engine files with "part" directives.
   MappedReplacer(RegExp(r'''
-export 'engine/(.*)';
+export\s*'engine/(.*)';
 '''), (Match match) => '''
 part 'engine/${match.group(1)}';
 '''),
   AllReplacer(
-    'import \'package:js/js.dart\'',
-    'import \'dart:_js_annotations\'',
+    RegExp(r"import\s*'package:js/js.dart'"),
+    r"import 'dart:_js_annotations'",
   ),
 ];
 
 final List<Replacer> enginePartsPatterns = <Replacer>[
-  AllReplacer('part of engine;', 'part of dart._engine;'),
+  AllReplacer(RegExp(r'part\s+of\s+engine;'), 'part of dart._engine;'),
   // Remove library-level JS annotations.
   AllReplacer(RegExp(r'\n@JS(.*)\nlibrary .+;'), ''),
   // Remove library directives.
   AllReplacer(RegExp(r'\nlibrary .+;'), ''),
   // Remove imports/exports from all engine parts.
-  AllReplacer(RegExp(r'import .*'), ''),
-  AllReplacer(RegExp(r'export .*'), ''),
+  AllReplacer(RegExp(r'\nimport\s*.*'), ''),
+  AllReplacer(RegExp(r'\nexport\s*.*'), ''),
 ];
 
 final List<Replacer> sharedPatterns = <Replacer>[
-  AllReplacer("import 'package:meta/meta.dart';", ''),
+  AllReplacer(RegExp(r"import\s*'package:meta/meta.dart';"), ''),
   AllReplacer('@required', ''),
   AllReplacer('@protected', ''),
   AllReplacer('@mustCallSuper', ''),
@@ -92,31 +92,41 @@
     final File outputFile = File(path.join(
         directory.path, inputFile.path.substring(inputDirectoryPath.length)))
       ..createSync(recursive: true);
-    String source = inputFile.readAsStringSync();
-    final List<Replacer> replacementPatterns = <Replacer>[];
-    replacementPatterns.addAll(sharedPatterns);
-    if (results['ui'] as bool) {
-      replacementPatterns.addAll(uiPatterns);
-    } else if (results['engine'] as bool) {
-      if (inputFilePath.endsWith('lib/src/engine.dart')) {
-        replacementPatterns.addAll(engineLibraryPatterns);
-      } else {
-        source = _preprocessEnginePartFile(source);
-        replacementPatterns.addAll(enginePartsPatterns);
-      }
-    }
-    for (final Replacer replacer in replacementPatterns) {
-      source = replacer.perform(source);
-    }
-    outputFile.writeAsStringSync(source);
+    final String source = inputFile.readAsStringSync();
+    final String rewrittenContent = rewriteFile(
+      source,
+      filePath: inputFilePath,
+      isUi: results['ui'] as bool,
+      isEngine: results['engine'] as bool,
+    );
+    outputFile.writeAsStringSync(rewrittenContent);
     if (results['stamp'] != null) {
       File(results['stamp'] as String).writeAsStringSync('stamp');
     }
   }
 }
 
+String rewriteFile(String source, {String filePath, bool isUi, bool isEngine}) {
+  final List<Replacer> replacementPatterns = <Replacer>[];
+  replacementPatterns.addAll(sharedPatterns);
+  if (isUi) {
+    replacementPatterns.addAll(uiPatterns);
+  } else if (isEngine) {
+    if (filePath.endsWith('lib/src/engine.dart')) {
+      replacementPatterns.addAll(engineLibraryPatterns);
+    } else {
+      source = _preprocessEnginePartFile(source);
+      replacementPatterns.addAll(enginePartsPatterns);
+    }
+  }
+  for (final Replacer replacer in replacementPatterns) {
+    source = replacer.perform(source);
+  }
+  return source;
+}
+
 String _preprocessEnginePartFile(String source) {
-  if (source.contains('\npart of engine;')) {
+  if (source.startsWith('part of engine;') || source.contains('\npart of engine;')) {
     // The file hasn't been migrated yet.
     // Do nothing.
   } else {
diff --git a/web_sdk/test/sdk_rewriter_test.dart b/web_sdk/test/sdk_rewriter_test.dart
new file mode 100644
index 0000000..559e530
--- /dev/null
+++ b/web_sdk/test/sdk_rewriter_test.dart
@@ -0,0 +1,119 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+import '../sdk_rewriter.dart';
+
+void main() {
+  test('handles imports/exports correctly in the engine library file', () {
+    const String source = '''
+library engine;
+
+import '../ui.dart' as ui;
+import 'package:ui/ui.dart' as ui;
+
+import 'package:some_package/some_package.dart';
+
+import 'engine/file1.dart';
+export 'engine/file1.dart';
+
+import'engine/file2.dart';
+export'engine/file2.dart';
+
+import      'engine/file3.dart';
+export      'engine/file3.dart';
+''';
+
+    const String expected = '''
+library dart._engine;
+
+import 'dart:ui' as ui;
+import 'dart:ui' as ui;
+
+import 'package:some_package/some_package.dart';
+
+
+part 'engine/file1.dart';
+
+
+part 'engine/file2.dart';
+
+
+part 'engine/file3.dart';
+''';
+
+    final String result = rewriteFile(
+      source,
+      filePath: '/path/to/lib/web_ui/lib/src/engine.dart',
+      isUi: false,
+      isEngine: true,
+    );
+    expect(result, expected);
+  });
+
+  test('removes imports/exports from engine files', () {
+    const String source = '''
+import 'package:some_package/some_package.dart';
+import 'package:some_package/some_package/foo.dart';
+import 'package:some_package/some_package' as some_package;
+
+import 'file1.dart';
+import'file2.dart';
+import      'file3.dart';
+
+export 'file4.dart';
+export'file5.dart';
+export      'file6.dart';
+
+void printSomething() {
+  print('something');
+}
+''';
+
+    const String expected = '''
+part of dart._engine;
+
+
+
+void printSomething() {
+  print('something');
+}
+''';
+
+    final String result = rewriteFile(
+      source,
+      filePath: '/path/to/lib/web_ui/lib/src/engine/my_file.dart',
+      isUi: false,
+      isEngine: true,
+    );
+    expect(result, expected);
+  });
+
+  test('does not insert an extra part directive', () {
+    const String source = '''
+part of engine;
+
+void printSomething() {
+  print('something');
+}
+''';
+
+    const String expected = '''
+part of dart._engine;
+
+void printSomething() {
+  print('something');
+}
+''';
+
+    final String result = rewriteFile(
+      source,
+      filePath: '/path/to/lib/web_ui/lib/src/engine/my_file.dart',
+      isUi: false,
+      isEngine: true,
+    );
+    expect(result, expected);
+  });
+}