Skip to content

Commit

Permalink
Add a sass_api package and publishing infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Jul 31, 2021
1 parent b64200e commit 7900dda
Show file tree
Hide file tree
Showing 21 changed files with 364 additions and 29 deletions.
29 changes: 24 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
# TODO(nweiz): Use the latest Dart when dart-lang/sdk#45488
with: {sdk: 2.12.4}
- run: dart pub get
- name: Analyze dart
run: dartanalyzer --fatal-warnings --fatal-infos lib tool test
- name: Analyze Dart
run: dart analyze --fatal-warnings --fatal-infos .

dartdoc:
name: Dartdoc
Expand All @@ -135,10 +133,14 @@ jobs:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- name: Run dartdoc
- name: dartdoc sass
run: dartdoc --quiet --no-generate-docs
--errors ambiguous-doc-reference,broken-link,deprecated
--errors unknown-directive,unknown-macro,unresolved-doc-reference
- name: dartdoc sass_api
run: cd pkg/sass_api && dartdoc --quiet --no-generate-docs
--errors ambiguous-doc-reference,broken-link,deprecated
--errors unknown-directive,unknown-macro,unresolved-doc-reference

sanity_checks:
name: Sanity checks
Expand Down Expand Up @@ -252,6 +254,23 @@ jobs:
run: dart pub run grinder pkg-pub-deploy
env: {PUB_CREDENTIALS: "${{ secrets.PUB_CREDENTIALS }}"}

deploy_sub_packages:
name: "Deploy Sub-Packages"
runs-on: ubuntu-latest
needs: [deploy_pub]
if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass'"

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- name: Deploy
run: dart pub run grinder deploy-sub-packages
env:
PUB_CREDENTIALS: "${{ secrets.PUB_CREDENTIALS }}"
GH_TOKEN: "${{ secrets.GH_TOKEN }}"
GH_USER: sassbot

deploy_homebrew:
name: "Deploy Homebrew"
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ package-lock.json
/benchmark/source
node_modules/
/doc/api
/pkg/*/doc/api
25 changes: 25 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Want to contribute? Great! First, read this page.
* [Changing the Node API](#changing-the-node-api)
* [Synchronizing](#synchronizing)
* [File Headers](#file-headers)
* [Release Process](#release-process)

## Before You Contribute

Expand Down Expand Up @@ -208,3 +209,27 @@ All files in the project must start with the following header.
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
```
## Release Process
Most of the release process is fully automated on GitHub actions, triggered by
pushing a tag matching the current `pubspec.yaml` version. However, there are a
few things to do before pushing that tag:
* Make sure the `pubspec.yaml` version doesn't end in `-dev`. (This is a Dart
convention to distinguish commits that aren't meant for release from commits
that are.)
* Make sure that `CHANGELOG.md` has an entry for the current version.
* Make sure that any packages in `pkg` depend on the current version of `sass`.
* Increment the versions of all packages in `pkg`. These should be incremented
at least as much as the `sass` version, and more if you add a new API that's
exposed by one of those packages.

* Make sure that every package in `pkg`'s `CHANGELOG.md` has an entry for its
current version.
You *don't* need to create tags for packages in `pkg`; that will be handled
automatically by GitHub actions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ A [Dart][dart] implementation of [Sass][sass]. **Sass makes CSS fun again**.
* [Standalone](#standalone)
* [From npm](#from-npm)
* [From Pub](#from-pub)
* [`sass_api` Package](#sass_api-package)
* [From Source](#from-source)
* [JavaScript API](#javascript-api)
* [Why Dart?](#why-dart)
Expand Down Expand Up @@ -129,6 +130,15 @@ See [the Dart API docs][api] for details.

[api]: https://www.dartdocs.org/documentation/sass/latest/sass/sass-library.html

#### `sass_api` Package

Dart users also have access to more in-depth APIs via the [`sass_api` package].
This provides access to the Sass AST and APIs for resolving Sass loads without
running a full compilation. It's separated out into its own package so that it
can increase its version number independently of the main `sass` package.

[`sass_api` package]: https://pub.dev/package/sass_api

### From Source

Assuming you've already checked out this repository:
Expand Down
3 changes: 3 additions & 0 deletions pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0-beta.1

* Initial beta release.
29 changes: 29 additions & 0 deletions pkg/sass_api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
This package exposes additional APIs for working with [Dart Sass], including
access to the Sass AST and its load resolution logic.

[Dart Sass]: https://pub.dev/packages/sass

This is split out into a separate package because so that it can be versioned
separately. The `sass_api` package's API is expected to evolve more quickly than
the Sass language itself, and will likely have more breaking changes as the
internals evolve to suit the needs of the Sass compiler.

## Depending on Development Versions

Sometimes it's necessary to depend on a version of a package that hasn't been
released yet. Because this package directly re-exports names from the main
`sass` package, you'll need to make sure you have a Git dependency on both it
*and* the `sass` package:

```yaml
dependency_overrides:
sass:
git:
url: git://github.com/sass/sass
ref: main # Replace this with a feature branch if necessary
sass_api:
git:
url: git://github.com/sass/sass
ref: main # Make sure this is the same as above!
path: pkg/sass_api
```
18 changes: 18 additions & 0 deletions pkg/sass_api/dartdoc_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
dartdoc:
categories:
AST:
markdown: doc/ast.md
name: Abstract Syntax Tree
Dependencies:
markdown: doc/dependencies.md
Importer:
markdown: doc/importer.md
Parsing:
markdown: doc/parsing.md
Compile:
markdown: doc/compile.md
Value:
markdown: doc/value.md
Visitor:
markdown: doc/visitor.md
ignore: [reexported-private-api-across-packages]
6 changes: 6 additions & 0 deletions pkg/sass_api/doc/ast.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Classes representing Sass's abstract syntax tree.

Certain AST classes, most notably [`Stylesheet`], have `parse()` constructors
that parse ASTs from string sources.

[`Stylesheet`]: ../sass/Stylesheet-class.html
1 change: 1 addition & 0 deletions pkg/sass_api/doc/compile.md
1 change: 1 addition & 0 deletions pkg/sass_api/doc/dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
APIs for resolving dependencies between Sass files.
1 change: 1 addition & 0 deletions pkg/sass_api/doc/importer.md
1 change: 1 addition & 0 deletions pkg/sass_api/doc/parsing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
APIs that parse Sass or CSS source.
1 change: 1 addition & 0 deletions pkg/sass_api/doc/value.md
10 changes: 10 additions & 0 deletions pkg/sass_api/doc/visitor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Classes that implement the [visitor pattern] for traversing the Sass [AST].
Callers can either implement interfaces like [`StatementVisitor`] from scratch
to handle *all* Sass node types, or extend helper classes like
[`RecursiveStatementVisitor`] which traverse the entire AST to handle only
specific nodes.

[visitor pattern]: https://en.wikipedia.org/wiki/Visitor_pattern
[AST]: AST-topic.html
[`StatementVisitor`]: ../sass/StatementVisitor-class.html
[`RecursiveStatementVisitor`]: ../sass/RecursiveStatementVisitor-class.html
36 changes: 36 additions & 0 deletions pkg/sass_api/lib/sass_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2021 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

/// We strongly recommend importing this library with the prefix `sass`.
library sass;

import 'package:sass/sass.dart';
import 'package:sass/src/parse/parser.dart';

export 'package:sass/sass.dart';
export 'package:sass/src/ast/node.dart';
export 'package:sass/src/ast/sass.dart' hide AtRootQuery;
export 'package:sass/src/async_import_cache.dart';
export 'package:sass/src/exception.dart' show SassFormatException;
export 'package:sass/src/import_cache.dart';
export 'package:sass/src/visitor/find_dependencies.dart';
export 'package:sass/src/visitor/interface/expression.dart';
export 'package:sass/src/visitor/interface/statement.dart';
export 'package:sass/src/visitor/recursive_ast.dart';
export 'package:sass/src/visitor/recursive_statement.dart';
export 'package:sass/src/visitor/statement_search.dart';

/// Parses [text] as a CSS identifier and returns the result.
///
/// Throws a [SassFormatException] if parsing fails.
///
/// {@category Parsing}
String parseIdentifier(String text) =>
Parser.parseIdentifier(text, logger: Logger.quiet);

/// Returns whether [text] is a valid CSS identifier.
///
/// {@category Parsing}
bool isIdentifier(String text) =>
Parser.isIdentifier(text, logger: Logger.quiet);
17 changes: 17 additions & 0 deletions pkg/sass_api/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: sass_api
# Note: Every time we add a new Sass AST node, we need to bump the *major*
# version because it's a breaking change for anyone who's implementing the
# visitor interface(s).
version: 1.0.0-beta.1
description: Additional APIs for Dart Sass.
author: Sass Team
homepage: https://github.com/sass/dart-sass

environment:
sdk: '>=2.12.0 <3.0.0'

dependencies:
sass: 1.37.0

dependency_overrides:
sass: {path: ../..}
6 changes: 4 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,21 @@ dependencies:
term_glyph: ^1.2.0
tuple: ^2.0.0
watcher: ^1.0.0
http: ^0.13.3

dev_dependencies:
archive: ^3.1.2
analyzer: ^1.1.0
archive: ^3.1.2
cli_pkg: ^1.3.0
crypto: ^3.0.0
dart_style: ^2.0.0
grinder: ^0.9.0
node_preamble: ^2.0.0
pedantic: ^1.11.0
pub_semver: ^2.0.0
pubspec_parse: ^1.0.0
stream_channel: ^2.1.0
test: ^1.16.7
test_descriptor: ^2.0.0
test_process: ^2.0.0
test: ^1.16.7
yaml: ^3.1.0
103 changes: 87 additions & 16 deletions test/double_check_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import 'dart:io';
import 'dart:convert';

import 'package:crypto/crypto.dart';
import 'package:path/path.dart' as p;
import 'package:pub_semver/pub_semver.dart';
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';

import '../tool/grind/synchronize.dart' as synchronize;

Expand Down Expand Up @@ -38,19 +40,88 @@ void main() {
// newline normalization issues.
testOn: "!windows");

test("pubspec version matches CHANGELOG version", () {
var firstLine = const LineSplitter()
.convert(File("CHANGELOG.md").readAsStringSync())
.first;
expect(firstLine, startsWith("## "));
var changelogVersion = firstLine.substring(3);

var pubspec = loadYaml(File("pubspec.yaml").readAsStringSync(),
sourceUrl: Uri(path: "pubspec.yaml")) as Map<dynamic, dynamic>;
expect(pubspec, containsPair("version", isA<String>()));
var pubspecVersion = pubspec["version"] as String;

expect(pubspecVersion,
anyOf(equals(changelogVersion), equals("$changelogVersion-dev")));
});
for (var package in [
".",
...Directory("pkg").listSync().map((entry) => entry.path)
]) {
group("in ${p.relative(package)}", () {
test("pubspec version matches CHANGELOG version", () {
var firstLine = const LineSplitter()
.convert(File("$package/CHANGELOG.md").readAsStringSync())
.first;
expect(firstLine, startsWith("## "));
var changelogVersion = firstLine.substring(3);

var pubspec = Pubspec.parse(
File("$package/pubspec.yaml").readAsStringSync(),
sourceUrl: p.toUri("$package/pubspec.yaml"));
expect(pubspec.version!.toString(),
anyOf(equals(changelogVersion), equals("$changelogVersion-dev")));
});
});
}

for (var package in Directory("pkg").listSync().map((entry) => entry.path)) {
group("in pkg/${p.basename(package)}", () {
late Pubspec sassPubspec;
late Pubspec pkgPubspec;
setUpAll(() {
sassPubspec = Pubspec.parse(File("pubspec.yaml").readAsStringSync(),
sourceUrl: Uri.parse("pubspec.yaml"));
pkgPubspec = Pubspec.parse(
File("$package/pubspec.yaml").readAsStringSync(),
sourceUrl: p.toUri("$package/pubspec.yaml"));
});

test("depends on the current sass version", () {
if (_isDevVersion(sassPubspec.version!)) return;

expect(pkgPubspec.dependencies, contains("sass"));
var dependency = pkgPubspec.dependencies["sass"]!;
expect(dependency, isA<HostedDependency>());
expect((dependency as HostedDependency).version,
equals(sassPubspec.version));
});

test("increments along with the sass version", () {
var sassVersion = sassPubspec.version!;
if (_isDevVersion(sassVersion)) return;

var pkgVersion = pkgPubspec.version!;
expect(_isDevVersion(pkgVersion), isFalse,
reason: "sass $sassVersion isn't a dev version but "
"${pkgPubspec.name} $pkgVersion is");

if (sassVersion.isPreRelease) {
expect(pkgVersion.isPreRelease, isTrue,
reason: "sass $sassVersion is a pre-release version but "
"${pkgPubspec.name} $pkgVersion isn't");
}

// If only sass's patch version was incremented, there's not a good way
// to tell whether the sub-package's version was incremented as well
// because we don't have access to the prior version.
if (sassVersion.patch != 0) return;

if (sassVersion.minor != 0) {
expect(pkgVersion.patch, equals(0),
reason: "sass minor version was incremented, ${pkgPubspec.name} "
"must increment at least its minor version");
} else {
expect(pkgVersion.minor, equals(0),
reason: "sass major version was incremented, ${pkgPubspec.name} "
"must increment at its major version as well");
}
});

test("matches SDK version", () {
expect(pkgPubspec.environment!["sdk"],
equals(sassPubspec.environment!["sdk"]));
});
});
}
}

/// Returns whether [version] is a `-dev` version.
bool _isDevVersion(Version version) =>
version.preRelease.length == 1 && version.preRelease.first == 'dev';
Loading

0 comments on commit 7900dda

Please sign in to comment.