Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support package: URLs in Dart #53

Merged
merged 7 commits into from
Feb 3, 2017
Merged

Conversation

luisvt
Copy link
Contributor

@luisvt luisvt commented Dec 1, 2016

fixes #19

@nex3
Copy link
Contributor

nex3 commented Dec 2, 2016

I like this change, but I think we should take a SyncPackageResolver rather than a raw map. A resolver is a lot easier to get for the current isolate, and it's more flexible in case the user wants to use packages/ directories for whatever reason.

@luisvt
Copy link
Contributor Author

luisvt commented Dec 2, 2016

Using SyncPackageResolverer inside visitor will make the application not compilable to js because this depends on dart:io. That's why I created a separated file for handling the PackageResolver.

@nex3
Copy link
Contributor

nex3 commented Dec 6, 2016

We use configuration-specific imports to support VM-only APIs as well as JS. You can add a conditional import that imports a stubbed SyncPackageResolver with only the APIs we use when compiling to JS.

@luisvt
Copy link
Contributor Author

luisvt commented Dec 8, 2016

ok, I'll try to make the changes. I'll let you know

@luisvt luisvt force-pushed the support-package-url branch 4 times, most recently from b8509ca to a32d759 Compare December 15, 2016 06:30
@luisvt
Copy link
Contributor Author

luisvt commented Dec 18, 2016

Changes has been made. Please review them @nex3

lib/sass.dart Outdated
@@ -15,12 +16,12 @@ import 'src/visitor/serialize.dart';
/// If [color] is `true`, this will use terminal colors in warnings.
///
/// Throws a [SassException] if conversion fails.
String render(String path, {bool color: false}) {
Future<String> render(String path, {bool color: false}) async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should take the SyncPackageResolver, not _PerformVisitor. Rendering needs to be synchronous in order to be compatible with the node-sass API.

Also, there should be a command-line --packages flag that allows the user to manually specify a package spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean with package spec?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A .packages file.

@@ -1403,6 +1403,12 @@ abstract class StylesheetParser extends Parser {
break;

case $0:
if (scanner.peekChar(1) == $backslash && scanner.peekChar(2) == $0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this all about?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these lines are for parsing code like next:

@media screen and (min-width:0\0) {
  ...
}

specifically are for parsing 0\0 inside a media query.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave fixes for other issues outside of this PR. One thing at a time makes it easier to review.

/// [PackageInfo] is usually preferable when the current Isolate's package
/// resolution logic may be used.
///
/// This class should not be implemented by user code.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to copy over the documentation here or in the stub implementation.

/// Returns `null` when using a [packageRoot] for resolution, or when no
/// package resolution is being used.
Map<String, Uri> get packageConfigMap =>
throw new Exception('not implemented for node');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods should throw UnsupportedExceptions, which should include the name of the class and method (for example, "SyncPackageResolver.packageConfigMap isn't supported on Node.js.").

@@ -509,11 +519,17 @@ class _PerformVisitor
});
}

Uri _resolvePackageUri(Uri packageUri) {
return packageUri.scheme == 'package' && packageResolver != null
? packageResolver.resolveUri(packageUri) ?? new Uri()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think new Uri() is right here. A blank URL doesn't help anyone. We should throw a useful error message saying "Can't resolve "$packageUri"" if it fails to resolve, or if there's no resolver available.

@@ -0,0 +1 @@
$color: blue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this node_sample directory for?

main() {
group('import "package:" uri', () {
test('found', () async {
var result = await render('test/styles/import-package.scss');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using assets on the filesystem, Dart Sass tests use scheduled_test's descriptor library to create assets in the test itself. This helps keep the test self-contained, and makes diffs a lot easier to read. See test/cli_shared.dart for examples.

pubspec.yaml Outdated
@@ -29,3 +30,4 @@ dev_dependencies:
node_preamble: "^1.0.0"
test: "^0.12.0"
yaml: "^2.0.0"
bootstrap_sass: ^4.0.0-alpah.3+4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like making assertions about other packages' assets in tests. I'd rather create a folder in the test body, then create a .packages file that points to it.

tool/grind.dart Outdated
@@ -16,15 +15,15 @@ import 'package:yaml/yaml.dart';

/// The version of Dart Sass.
final String _version =
loadYaml(new File('pubspec.yaml').readAsStringSync())['version'];
loadYaml(new File('pubspec.yaml').readAsStringSync())['version'] as String;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be quicker for me to review this PR if you keep the changes focused on package: URLs.

@nex3
Copy link
Contributor

nex3 commented Jan 6, 2017

@luisvt Is this ready for another round of review?

@luisvt
Copy link
Contributor Author

luisvt commented Jan 7, 2017

Not yet sorry

@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.

@googlebot
Copy link

CLAs look good, thanks!

@luisvt
Copy link
Contributor Author

luisvt commented Jan 10, 2017

now I think is ready, please review it.

lib/sass.dart Outdated
/// If [color] is `true`, this will use terminal colors in warnings.
///
/// Throws a [SassException] if conversion fails.
Future<String> renderAsync(String path, {bool color: false}) async =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I want to add this. I don't think having a default for packageResolver is worth an extra top-level function.

void _render(
NodeOptions options, void callback(NodeError error, NodeResult result)) {
Future _render(NodeOptions options,
void callback(NodeError error, NodeResult result)) async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you changing the types here? Node doesn't understand what a "Future" is, so this will definitely break it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I forgot to revert it.

@@ -0,0 +1,3 @@
export 'interface.dart'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To match the way we stub out IO, this file (sync_package_resolver/index.dart) should be sync_package_resolver.dart instead.

import 'dart:async';

abstract class SyncPackageResolver {
Map<String, Uri> get packageConfigMap;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only include the members that Dart Sass actually uses in practice.

@@ -123,8 +128,13 @@ class _PerformVisitor
/// invocations, and imports surrounding the current context.
final _stack = <Frame>[];

final SyncPackageResolver packageResolver;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this private.

lib/sass.dart Outdated
@@ -15,12 +17,24 @@ import 'src/visitor/serialize.dart';
/// If [color] is `true`, this will use terminal colors in warnings.
///
/// Throws a [SassException] if conversion fails.
String render(String path, {bool color: false}) {
String render(String path,
{bool color: false, SyncPackageResolver packageResolver}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document the packageResolver parameter.

Uri _resolvePackageUri(DynamicImport import) {
var packageUri = import.url;
if (packageUri.scheme == 'package') {
if (packageResolver == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: include {} even for single-statement ifs (see the style guide).

pubspec.yaml Outdated
@@ -19,6 +19,7 @@ dependencies:
string_scanner: ">=0.1.5 <2.0.0"
stack_trace: ">=0.9.0 <2.0.0"
tuple: "^1.0.0"
package_resolver: ^1.0.2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always declare the lowest version that has all the APIs you need. In this case, that's 1.0.0.


group("supports package imports", () {
test("is found", () {
d.file("test.scss", "a {b: 1 + 2}").create('lib');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't create files outside of the sandbox during tests. To properly test this, you'll probably need to add that --packages flag.

@@ -47,7 +47,7 @@ main(List<String> args) async {

var color = (options['color'] as bool) ?? hasTerminal;
try {
var css = render(options.rest.first, color: color);
var css = await renderAsync(options.rest.first, color: color);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaulting to the current isolate's package resolver only makes sense here if Sass is being used as a library or a direct dependency of a package. If it's being run as a global or standalone executable—which is better supported anyway—that logic won't work.

Probably the best thing to do here is to follow Dart's behavior for auto-detecting package resolution from the Sass file's location, and allow users to override it with a --packages flag. For now, just remove the default behavior and implement the flag; we can do the auto-detection in a separate CL.

Copy link
Contributor

@nex3 nex3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really good! Just a few small changes left.


var resolvedPackageUri = _packageResolver.resolveUri(packageUri);
if (resolvedPackageUri == null ||
!dirExists(p.dirname(p.fromUri(resolvedPackageUri)))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the point of this check. If the package URI is resolvable, we'll already get an error when we try to load the file, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is for when the package URI is not resolvable. What should I do instead this check?

If I remove this check resolvedPackageUri will be null, which in turn will throw:

NoSuchMethodError: The getter 'scheme' was called on null.

Second option would be return an empty uri, which was what I have at the beginning and you told me to better add a check and throw a better error. Please see the comment you added on #53 (diff)

Third option would be return the original packageUri, but that lets to previous problem on having an error message not showing good information.

Finally the line 585 in #53 (diff) was added because previous version of sdk returned an URI even when there was no existing file.

// ]));
// sass.shouldExit(0);
// });
// });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this commented-out code.

"@import \"package:fake_package/test_aux\";\n"
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
" $sandbox/test.scss 1:9 root stylesheet");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's generally better to use the throwsA() matcher than to manually write a try/catch block. Then you can verify the exception's message with the predicate() matcher.

changes:
  * remove commented out code in `dart_cli_test.dart`
  * use `throwsA` instead doing a `try-catch` in `dart_script_test.dart`
@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.

@googlebot
Copy link

CLAs look good, thanks!

@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.

changes:
  * remove `dirExist` check for `packageUri`
@googlebot
Copy link

CLAs look good, thanks!

Exporting a stub produced errors when passing a real instance.
@nex3 nex3 merged commit cfc3a15 into sass:master Feb 3, 2017
@nex3
Copy link
Contributor

nex3 commented Feb 3, 2017

Thanks for the patch!

nex3 added a commit that referenced this pull request May 10, 2023
Co-authored-by: Natalie Weizenbaum <nweiz@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support package: URLs in Dart
3 participants