;
+}
+
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/TEST_CASES.json
new file mode 100644
index 0000000000..f6abe9469d
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/TEST_CASES.json
@@ -0,0 +1,121 @@
+{
+ "$schema": "../../test_case_schema.json",
+ "cases": [
+ {
+ "description": "should create external template source-mapping (full compile)",
+ "inputFiles": [
+ "external_template.ts"
+ ],
+ "compilationModeFilter": [
+ "full compile"
+ ],
+ "compilerOptions": {
+ "sourceMap": true,
+ "inlineSources": true
+ }
+ },
+ {
+ "description": "should create external template source-mapping (linked compile)",
+ "inputFiles": [
+ "external_template.ts"
+ ],
+ "expectations": [
+ {
+ "files": [
+ {
+ "generated": "external_template.js",
+ "expected": "external_template_partial.js"
+ }
+ ]
+ }
+ ],
+ "compilationModeFilter": [
+ "linked compile"
+ ],
+ "compilerOptions": {
+ "sourceMap": true,
+ "inlineSources": true
+ }
+ },
+ {
+ "description": "should create correct mappings when templateUrl is in a different rootDir (full compile)",
+ "inputFiles": [
+ "extra_root_dir.ts"
+ ],
+ "compilationModeFilter": [
+ "full compile"
+ ],
+ "compilerOptions": {
+ "sourceMap": true,
+ "inlineSources": true,
+ "rootDirs": [
+ ".",
+ "extraRootDir"
+ ]
+ }
+ },
+ {
+ "description": "should create correct mappings when templateUrl is in a different rootDir (linked compile)",
+ "inputFiles": [
+ "extra_root_dir.ts"
+ ],
+ "compilationModeFilter": [
+ "linked compile"
+ ],
+ "expectations": [
+ {
+ "files": [
+ {
+ "generated": "extra_root_dir.js",
+ "expected": "extra_root_dir_partial.js"
+ }
+ ]
+ }
+ ],
+ "compilerOptions": {
+ "sourceMap": true,
+ "inlineSources": true,
+ "rootDirs": [
+ ".",
+ "extraRootDir"
+ ]
+ }
+ },
+ {
+ "description": "should handle unusual escaped chars when source-mapping (full compile)",
+ "inputFiles": [
+ "escaped_chars.ts"
+ ],
+ "compilationModeFilter": [
+ "full compile"
+ ],
+ "compilerOptions": {
+ "sourceMap": true,
+ "inlineSources": true
+ }
+ },
+ {
+ "description": "should handle unusual escaped chars when source-mapping (linked compile)",
+ "inputFiles": [
+ "escaped_chars.ts"
+ ],
+ "expectations": [
+ {
+ "files": [
+ {
+ "generated": "escaped_chars.js",
+ "expected": "escaped_chars_partial.js"
+ }
+ ]
+ }
+ ],
+ "compilationModeFilter": [
+ "linked compile"
+ ],
+ "compilerOptions": {
+ "sourceMap": true,
+ "inlineSources": true
+ }
+ }
+ ]
+}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/dir/test.html b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/dir/test.html
new file mode 100644
index 0000000000..52c8532fbb
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/dir/test.html
@@ -0,0 +1,2 @@
+this is a test
+{{ 1 + 2 }}
\ No newline at end of file
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.html b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.html
new file mode 100644
index 0000000000..c9065ed671
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.html
@@ -0,0 +1,8 @@
+
+\r\n
+ Some Message\r\n
+ Encoded character: 🚀\r\n
+
\ No newline at end of file
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.js b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.js
new file mode 100644
index 0000000000..51a98de501
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.js
@@ -0,0 +1,6 @@
+i0.ɵɵelementStart(0, "div") // SOURCE: "/escaped_chars.html" \r\n
+…
+// NOTE: the `\\r\\n` at the end of the next line will be unescaped to `\r\n`. If it was just `\r\n` it would get unescaped to the actual characters.
+i0.ɵɵtext(1, " Some Message Encoded character: \uD83D\uDE80\\n") // SOURCE: "/escaped_chars.html" Some Message\r\n Encoded character: 🚀\\r\\n
+…
+i0.ɵɵelementEnd() // SOURCE: "/escaped_chars.html"
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.ts b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.ts
new file mode 100644
index 0000000000..a154b2593e
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+@Component({
+ selector: 'test-cmp',
+ templateUrl: './escaped_chars.html',
+})
+export class TestCmp {
+}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars_partial.js b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars_partial.js
new file mode 100644
index 0000000000..7323175318
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/escaped_chars_partial.js
@@ -0,0 +1,6 @@
+.ɵɵelementStart(0, "div") // SOURCE: "/escaped_chars.html" \r\n
+…
+// NOTE: the `\\r\\n` at the end of the next line will be unescaped to `\r\n`. If it was just `\r\n` it would get unescaped to the actual characters.
+.ɵɵtext(1, " Some Message Encoded character: \uD83D\uDE80\\n") // SOURCE: "/escaped_chars.html" Some Message\r\n Encoded character: 🚀\\r\\n
+…
+.ɵɵelementEnd() // SOURCE: "/escaped_chars.html"
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template.js b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template.js
new file mode 100644
index 0000000000..6b3728b325
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template.js
@@ -0,0 +1,13 @@
+i0.ɵɵelementStart(0, "div") // SOURCE: "/dir/test.html"
+…
+i0.ɵɵtext(1, "this is a test") // SOURCE: "/dir/test.html" this is a test
+…
+i0.ɵɵelementEnd() // SOURCE: "/dir/test.html"
+…
+i0.ɵɵelementStart(2, "div") // SOURCE: "/dir/test.html"
+…
+i0.ɵɵtext(3) // SOURCE: "/dir/test.html" {{ 1 + 2 }}
+…
+i0.ɵɵelementEnd() // SOURCE: "/dir/test.html"
+…
+i0.ɵɵtextInterpolate(1 + 2) // SOURCE: "/dir/test.html" {{ 1 + 2 }}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template.ts b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template.ts
new file mode 100644
index 0000000000..7b40a2e552
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+@Component({
+ selector: 'test-cmp',
+ templateUrl: './dir/test.html',
+})
+export class TestCmp {
+}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template_partial.js b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template_partial.js
new file mode 100644
index 0000000000..ce85a291bf
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/external_template_partial.js
@@ -0,0 +1,14 @@
+.ɵɵelementStart(0, "div") // SOURCE: "/dir/test.html"
+…
+.ɵɵtext(1, "this is a test") // SOURCE: "/dir/test.html" this is a test
+…
+.ɵɵelementEnd() // SOURCE: "/dir/test.html"
\n
+…
+.ɵɵelementStart(2, "div") // SOURCE: "/dir/test.html"
+…
+.ɵɵtext(3) // SOURCE: "/dir/test.html" {{ 1 + 2 }}
+…
+// TODO: Work out how to fix the broken segment for the last item in a template
+.ɵɵelementEnd() // SOURCE: "/dir/test.html"
+…
+.ɵɵtextInterpolate(1 + 2) // SOURCE: "/dir/test.html" {{ 1 + 2 }}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extraRootDir/dir/extra.html b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extraRootDir/dir/extra.html
new file mode 100644
index 0000000000..52c8532fbb
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extraRootDir/dir/extra.html
@@ -0,0 +1,2 @@
+this is a test
+{{ 1 + 2 }}
\ No newline at end of file
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir.js b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir.js
new file mode 100644
index 0000000000..6611e6336c
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir.js
@@ -0,0 +1,13 @@
+i0.ɵɵelementStart(0, "div") // SOURCE: "/extraRootDir/dir/extra.html"
+…
+i0.ɵɵtext(1, "this is a test") // SOURCE: "/extraRootDir/dir/extra.html" this is a test
+…
+i0.ɵɵelementEnd() // SOURCE: "/extraRootDir/dir/extra.html"
+…
+i0.ɵɵelementStart(2, "div") // SOURCE: "/extraRootDir/dir/extra.html"
+…
+i0.ɵɵtext(3) // SOURCE: "/extraRootDir/dir/extra.html" {{ 1 + 2 }}
+…
+i0.ɵɵelementEnd() // SOURCE: "/extraRootDir/dir/extra.html"
+…
+i0.ɵɵtextInterpolate(1 + 2) // SOURCE: "/extraRootDir/dir/extra.html" {{ 1 + 2 }}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir.ts b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir.ts
new file mode 100644
index 0000000000..fc04db461f
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+@Component({
+ selector: 'test-cmp',
+ templateUrl: './dir/extra.html',
+})
+export class TestCmp {
+}
diff --git a/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir_partial.js b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir_partial.js
new file mode 100644
index 0000000000..b7216ad0db
--- /dev/null
+++ b/packages/compiler-cli/test/compliance/test_cases/source_mapping/external_templates/extra_root_dir_partial.js
@@ -0,0 +1,13 @@
+.ɵɵelementStart(0, "div") // SOURCE: "/extraRootDir/dir/extra.html"
+…
+.ɵɵtext(1, "this is a test") // SOURCE: "/extraRootDir/dir/extra.html" this is a test
+…
+.ɵɵelementEnd() // SOURCE: "/extraRootDir/dir/extra.html"
\n
+…
+.ɵɵelementStart(2, "div") // SOURCE: "/extraRootDir/dir/extra.html"
+…
+.ɵɵtext(3) // SOURCE: "/extraRootDir/dir/extra.html" {{ 1 + 2 }}
+…
+.ɵɵelementEnd() // SOURCE: "/extraRootDir/dir/extra.html"
+…
+.ɵɵtextInterpolate(1 + 2) // SOURCE: "/extraRootDir/dir/extra.html" {{ 1 + 2 }}