Don't canonicalize file case in source maps (#541)

Closes #540
This commit is contained in:
Natalie Weizenbaum 2019-01-04 14:17:18 -05:00 committed by GitHub
parent 948fe17a53
commit 7a75b7b786
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 2 deletions

View File

@ -407,7 +407,7 @@ class ExecutableOptions {
Uri sourceMapUrl(Uri url, String destination) {
if (url.scheme.isNotEmpty && url.scheme != 'file') return url;
var path = p.canonicalize(p.fromUri(url));
var path = p.fromUri(url);
return p.toUri(_options['source-map-urls'] == 'relative'
? p.relative(path, from: p.dirname(destination))
: p.absolute(path));

View File

@ -27,7 +27,12 @@ class FilesystemImporter extends Importer {
ImporterResult load(Uri url) {
var path = p.fromUri(url);
return ImporterResult(io.readFile(path),
sourceMapUrl: url, syntax: Syntax.forPath(path));
sourceMapUrl:
// [io.realCasePath] will short-circuit on case-sensitive
// filesystems anyway, but we still avoid calling it here so we
// don't have to re-parse the URL.
io.couldBeCaseInsensitive ? p.toUri(io.realCasePath(path)) : url,
syntax: Syntax.forPath(path));
}
DateTime modificationTime(Uri url) => io.modificationTime(p.fromUri(url));

View File

@ -2,6 +2,41 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'package:path/path.dart' as p;
import 'io/interface.dart'
if (dart.library.io) 'io/vm.dart'
if (dart.library.js) 'io/node.dart';
import 'utils.dart';
export 'io/interface.dart'
if (dart.library.io) 'io/vm.dart'
if (dart.library.js) 'io/node.dart';
/// Returns whether the current operating system might be case-insensitive.
///
/// We can't know for sure because different Mac OS systems are configured
/// differently.
bool get couldBeCaseInsensitive => isWindows || isMacOS;
/// Returns `path` with the case updated to match the path's case on disk.
///
/// This only updates `path`'s basename. It always returns `path` as-is on
/// operating systems other than Windows or Mac OS, since they almost never uses
/// case-insensitive filesystems.
String realCasePath(String path) {
// TODO(nweiz): Use an SDK function for this when dart-lang/sdk#35370 and/or
// nodejs/node#24942 are fixed.
if (!couldBeCaseInsensitive) return path;
var basename = p.basename(path);
var matches = listDir(p.dirname(path))
.where((realPath) => equalsIgnoreCase(p.basename(realPath), basename))
.toList();
// If the file doesn't exist, or if there are multiple options (meaning the
// filesystem isn't actually case-insensitive), return `path` as-is.
if (matches.length != 1) return path;
return matches.first;
}

View File

@ -33,6 +33,9 @@ Stderr get stderr => null;
/// Whether the current process is running on Windows.
bool get isWindows => false;
/// Whether the current process is running on Mac OS.
bool get isMacOS => false;
/// Returns whether or not stdout is connected to an interactive terminal.
bool get hasTerminal => false;

View File

@ -232,6 +232,8 @@ bool get hasTerminal => _hasTerminal ?? false;
bool get isWindows => _process.platform == 'win32';
bool get isMacOS => _process.platform == 'darwin';
bool get isNode => true;
// Node seems to support ANSI escapes on all terminals.

View File

@ -19,6 +19,8 @@ io.Stdout get stderr => io.stderr;
bool get isWindows => io.Platform.isWindows;
bool get isMacOS => io.Platform.isMacOS;
bool get hasTerminal => io.stdout.hasTerminal;
bool get isNode => false;

View File

@ -89,6 +89,34 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
});
});
group("doesn't normalize file case", () {
setUp(() => d.file("TeSt.scss", "a {b: c}").create());
test("when loaded with the same case", () async {
await (await runSass(["TeSt.scss", "out.css"])).shouldExit(0);
expect(_readJson("out.css.map"), containsPair("sources", ["TeSt.scss"]));
});
test("when imported with the same case", () async {
await d.file("importer.scss", "@import 'TeSt.scss'").create();
await (await runSass(["importer.scss", "out.css"])).shouldExit(0);
expect(_readJson("out.css.map"), containsPair("sources", ["TeSt.scss"]));
});
// The following tests rely on Windows' case-insensitive filesystem.
test("when loaded with a different case", () async {
await (await runSass(["test.scss", "out.css"])).shouldExit(0);
expect(_readJson("out.css.map"), containsPair("sources", ["TeSt.scss"]));
}, testOn: "windows");
test("when imported with a different case", () async {
await d.file("importer.scss", "@import 'test.scss'").create();
await (await runSass(["importer.scss", "out.css"])).shouldExit(0);
expect(_readJson("out.css.map"), containsPair("sources", ["TeSt.scss"]));
}, testOn: "windows");
});
test("includes a source map comment", () async {
await d.file("test.scss", "a {b: c}").create();
await (await runSass(["test.scss", "out.css"])).shouldExit(0);