sass / dart-sass

The reference implementation of Sass, written in Dart.
https://sass-lang.com/dart-sass
MIT License
3.94k stars 358 forks source link

JS API: Create a method to get SASS AST #88

Open AleshaOleg opened 7 years ago

AleshaOleg commented 7 years ago

I want to implement SASS parser for @postcss - written by @ai. But for this purpose I need convert SASS AST to PostCSS AST. It would be great, if I can use official parser from @sass (i'm really appreciate that you implemented SASS on compiled to JS language).

So, @nex3 - what you think if I will try to write a new method which return SASS AST? I'm newbie in @dart, so it will take some time to learn it:D I think it will be a method very similar to render() from node-sass.

ai commented 7 years ago

I really like this idea. We could replace postcss-scss with 100% compatible PostCSS parser to SCSS and Sass syntaxes.

I think our users will happy. For example, Sass users will get a Stylelint support.

nex3 commented 7 years ago

Using our current compiler Dart to JavaScript, it's very difficult to expose Dart classes to JS in a usable way. I know @jmesserly was hoping to look into an alternate compiler that would make this easier, but it's fairly likely that it won't have the performance we need.

In the long term I hope this will get easier, but it's not a short-term goal. We're intentionally keeping the API surface small even in pure Dart; we don't want to commit to maintaining anything backwards-compatible while development is still so active.

ai commented 7 years ago

@nex3 sad to know that Dart classes problem :(. In this case we could return simple non-class object.

What we should do right now? What is the best way to parse Sass to PostCSS AST in current API?

Should we write a own parser from scratch (but I think it will be bad for Sass ecosystem). Or should we send PR todart-sass with extra methods?

nex3 commented 7 years ago

I suppose we could just dump a bunch of nested maps, but that sounds like it would be a pretty crummy API—and it would still have the same backwards-compatibility issues as a proper object-oriented API :confused:. Or we could wait until we get real info on the performance implications of the alternative compiler and see if it makes sense to switch over.

If you're chomping at the bit to do some work here, though, you could create a Dart Sass visitor, written in Dart, that traverses a Sass AST and emits a PostCSS AST. Instantiating JS classes from Dart is easy. I'm not sure what the best way to expose that would be, since it would have to be compiled into the same JS blob as the rest of Dart Sass, but we could figure that out later.

ai commented 7 years ago

@nex3 Dart Sass visitor looks like great idea. Doyou have some docs or examples?

nex3 commented 7 years ago

You can look at the perform visitor as an example.

nex3 commented 7 years ago

There's no clean way to do this as a dependency, since the Dart package doesn't publicly export the AST types at the moment—I'd recommend just forking this repository and adding the visitor locally for the time being.

In general, you import Dart code from dependencies using package: URLs. For example:

import "package:sass/sass.dart" as sass;

void main(List<String> args) {
  print(sass.render(args.first));
}

You declare dependencies in a pubspec.yaml file at the root of your package:

name: my_pkg
version: 1.2.3

dependencies:
  sass:

and run pub get to fetch them in a way that can be imported using package: URLs.

ai commented 7 years ago

@nex3 Maybe it will be more easy to send PR with private visitor API? If you will find a better way, you will be able to change this visitor API without major updates, since it will be a private API for single use case.

AleshaOleg commented 7 years ago

@nex3 sorry, for deleting comment which I wrote before. We don't wont to fork, because we'll need to update this fork every time, as you update your version. Is it really no other way to do this? Can you describe a "not clean" way?

AleshaOleg commented 7 years ago

Please look to this example, is this ok to import files in this way from package?

nex3 commented 7 years ago

We don't currently have the resources to devote to making a nice, well-supported version of this. You're going to need to update your code frequently to deal with upstream changes—there's no way around this in the short term, because the APIs are still in flux. Whether you fork or import libraries from src/ (which indicates that they're private), you're likely to get broken down the line.

I encourage you to think about this work as a proof-of-concept or prototype for now. Once we release 1.0.0, I'll spend some time factoring this out into separate packages, including a sass_ast package (or something like that) which you can interface with in a more stable way.

matthew-dean commented 7 years ago

FYI: I wrote a Less-AST-to-PostCSS-AST plugin, and while it worked, according to at least one person who tested it, it ended up being slower to convert the ASTs then to simply output CSS and re-parse into PostCSS. So don't automatically assume you're saving any time by skipping stringifying / re-parsing. It may seem more direct in theory, but you can't make that assumption.

octref commented 4 years ago

Hi, this is Pine from VS Code team. I work on the builtin SCSS support in VS Code, and recently I started contributing to the SCSS extension.

A parser / AST would be very helpful for me to continue maintain SCSS support, because I no longer have to update it from time to time to accommodate new language syntax changes.

However, IMO, language team should really own the language server themselves. That's the reason why TypeScript has really good support in the editors. Many popular languages, such as Rust, Go, Swift have also realized this and start to develop their language servers based on the core parser / compiler APIs. I understand that SASS originally started with Ruby and C/C++ and providing these interfaces hasn't been a goal, but lack of such API means it's much harder to develop language tooling for it.

Also there's currently no language support for the indented SASS syntax by any editor. I really want to do it, but if that means I would have to write a parser for indented SASS to begin with, I really don't have enough time.

nex3 commented 4 years ago

Creating a language-server protocol implementation for Sass is on our roadmap, but it's non-trivial and we have a very small team with a lot of responsibilities. The Sass ecosystem relies heavily on user contributions; if this is something users want to see, the best way to make it happen is to contribute your time to its development or helping to find someone else who's interested in working on it. We'd be thrilled to collaborate.

octref commented 4 years ago

@nex3 Thanks for getting back to me! Your last comment was in 2017. Can you post an updated version as to what would it take to get a JS API for getting the AST from raw SCSS/SASS strings?

nex3 commented 4 years ago

Just to be clear, for the specific use-case of IDE support, I think creating an LSP implementation in Dart where it'll have access to static analysis information from the infrastructure we're building for the Sass migrator is a better path forward than exposing an AST to JS.

That said, I do still think exposing an AST to JS would generally be valuable. Doing that would involve using Dart's JS interop to define types for the JS classes we want to expose (like this), a visitor to traverse a Sass AST and return a JS AST, and some build infrastructure so we can create a separate package for that AST (that part I can handle).

gregjacobs commented 4 years ago

Just wanted to chime in here: this would also be useful for writing source code transformation utilities (like the one I'm trying to write!)

There doesn't currently seem to be a good parser out there for sass/scss:

Would really be good to have the parser/AST exposed at the source of the language so that we can't go wrong!

TheJaredWilcurt commented 3 years ago

This would enable so much, better linting, code quality enforcement, code mods, reporting/analysis tools.

Even if the JS API outputs a Sass AST that doesn't match anything else, but is consistent, someone else could create a translation library that ports it to other AST streams. These tasks could even be done separately to make it easier to achieve. Outputting any AST, and then when time permits having the translation layer be built in later. This allows the community to contribute to the translation layer (which would be easier to help with).

TheJaredWilcurt commented 3 years ago

Still waiting on this. Sasslint (linter that supports .sass files) has been unmaintained for 2 years and is building up security vulnerabilities from it's older dependencies.

If this could be prioritized then it would unlock tons of tooling potential that isn't reliant on partially complete, buggy, home-made ASTs.

Any way to fund this or something, if it was all JS I'd help out, but I have no desire to learn Dart.

nex3 commented 3 years ago

We are unlikely to have time to implement this in the near future. For our purposes, the existing postcss-scss parser has generally been sufficient.

forivall commented 3 years ago

Thanks. I'll consider building my own parser then, at the very least, to support vscode tooling. Good to know, so that we're not doubling the effort.

niksy commented 3 years ago

Now that there is sass_api Dart package, are there any plans for making it available in JS?

I’ve tried compiling Dart version to JS with dart2js but I’m getting errors such as:

sass_api.js:4460 Uncaught TypeError: J.getInterceptor$s(...).get$codeUnits is not a function
    at Object.get$codeUnits$s (sass_api.js:4460)
    at Object.SourceFile$fromString (file.dart:62)
    at Object.SpanScanner$ (span_scanner.dart:63)
    at Object.Parser$ (parser.dart:52)
    at Object.Parser_parseIdentifier (parser.dart:32)
    at Object.main (sass_api.dart:30)
    at callMain (js_helper.dart:2684)
    at js_helper.dart:2684
    at js_helper.dart:2684
    at dartProgram (js_helper.dart:2684)
nex3 commented 3 years ago

The existence of Dart's sass_api package doesn't make it particularly easier to expose a JS API. It would still require a manual implementation of a translation layer, which we are unlikely to have time to implement ourselves.

TheJaredWilcurt commented 3 years ago

I think it's worth noting that postcss-scss is an insufficient solution in comparison to an official AST provided by Sass.

Again, happy to fund this.

nex3 commented 3 years ago

It's not a question of whether it would be valuable, we simply don't have time to work on it. If you've got funding available, we'd be happy to work with a contractor you've funded to help make this happen.

niksy commented 3 years ago

If anyone’s interested, I’ve created module which extracts render errors and deprecations to machine readable format (JSON), and it’s used in related Stylelint plugin.

There’s a proposal to make this part of the specification, but if anyone’s looking for something similar in the meantime, glad I could help. Suggestions welcome!