dart-sass/tool/grind.dart
Natalie Weizenbaum 8090b992de
Test against real-world Sass frameworks (#1487)
In a future commit, I'll update these jobs to only run just before
release, since they're expected to be substantially less likely to
fail and we don't want to waste cycles. For now, I have them runnning
always to verify that they run successfully at least once.
2021-09-17 23:17:41 +00:00

147 lines
5.4 KiB
Dart

// Copyright 2016 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.
import 'dart:convert';
import 'dart:io';
import 'package:charcode/charcode.dart';
import 'package:cli_pkg/cli_pkg.dart' as pkg;
import 'package:grinder/grinder.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';
import 'grind/synchronize.dart';
export 'grind/bazel.dart';
export 'grind/benchmark.dart';
export 'grind/frameworks.dart';
export 'grind/sanity_check.dart';
export 'grind/subpackages.dart';
export 'grind/synchronize.dart';
void main(List<String> args) {
pkg.humanName.value = "Dart Sass";
pkg.botName.value = "Sass Bot";
pkg.botEmail.value = "sass.bot.beep.boop@gmail.com";
pkg.executables.value = {"sass": "bin/sass.dart"};
pkg.chocolateyNuspec.value = _nuspec;
pkg.homebrewRepo.value = "sass/homebrew-sass";
pkg.homebrewFormula.value = "sass.rb";
pkg.jsRequires.value = {"chokidar": "chokidar", "readline": "readline"};
pkg.jsModuleMainLibrary.value = "lib/src/node.dart";
pkg.npmPackageJson.fn = () =>
json.decode(File("package/package.json").readAsStringSync())
as Map<String, dynamic>;
pkg.npmReadme.fn = () => _readAndResolveMarkdown("package/README.npm.md");
pkg.standaloneName.value = "dart-sass";
pkg.githubUser.fn = () => Platform.environment["GH_USER"];
pkg.githubPassword.fn = () => Platform.environment["GH_TOKEN"];
pkg.githubReleaseNotes.fn = () =>
"To install Sass ${pkg.version}, download one of the packages below "
"and [add it to your PATH][], or see [the Sass website][] for full "
"installation instructions.\n"
"\n"
"[add it to your PATH]: https://katiek2.github.io/path-doc/\n"
"[the Sass website]: https://sass-lang.com/install\n"
"\n"
"# Changes\n"
"\n"
"${pkg.githubReleaseNotes.defaultValue}";
pkg.addAllTasks();
grind(args);
}
@DefaultTask('Compile async code and reformat.')
@Depends(format, synchronize)
void all() {}
@Task('Run the Dart formatter.')
void format() {
Pub.run('dart_style',
script: 'format', arguments: ['--overwrite', '--fix', '.']);
}
@Task('Installs dependencies from npm.')
void npmInstall() =>
run(Platform.isWindows ? "npm.cmd" : "npm", arguments: ["install"]);
@Task('Runs the tasks that are required for running tests.')
@Depends(format, synchronize, "pkg-npm-dev", npmInstall, "pkg-standalone-dev")
void beforeTest() {}
String get _nuspec => """
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>sass</id>
<title>Sass</title>
<authors>Natalie Weizenbaum</authors>
<owners>nex3</owners>
<projectUrl>https://github.com/sass/dart-sass</projectUrl>
<licenseUrl>https://github.com/sass/dart-sass/blob/${pkg.version}/LICENSE</licenseUrl>
<iconUrl>https://cdn.rawgit.com/sass/sass-site/f99ee33e4f688e244c7a5902c59d61f78daccc55/source/assets/img/logos/logo-seal.png</iconUrl>
<bugTrackerUrl>https://github.com/sass/dart-sass/issues</bugTrackerUrl>
<description>**Sass makes CSS fun again**. Sass is an extension of CSS, adding nested rules, variables, mixins, selector inheritance, and more. It's translated to well-formatted, standard CSS using the command line tool or a web-framework plugin.
This package is Dart Sass, the new Dart implementation of Sass.</description>
<summary>Sass makes CSS fun again.</summary>
<tags>css preprocessor style sass</tags>
<copyright>Copyright ${DateTime.now().year} Google, Inc.</copyright>
</metadata>
</package>
""";
final _readAndResolveRegExp = RegExp(
r"^<!-- +#include +([^\s]+) +"
'"([^"\n]+)"'
r" +-->$",
multiLine: true);
/// Reads a Markdown file from [path] and resolves include directives.
///
/// Include directives have the syntax `"<!-- #include" PATH HEADER "-->"`,
/// which must appear on its own line. PATH is a relative file: URL to another
/// Markdown file, and HEADER is the name of a header in that file whose
/// contents should be included as-is.
String _readAndResolveMarkdown(String path) => File(path)
.readAsStringSync()
.replaceAllMapped(_readAndResolveRegExp, (match) {
late String included;
try {
included = File(p.join(p.dirname(path), p.fromUri(match[1])))
.readAsStringSync();
} catch (error) {
_matchError(match, error.toString(), url: p.toUri(path));
}
late Match headerMatch;
try {
headerMatch = "# ${match[2]}".allMatches(included).first;
} on StateError {
_matchError(match, "Could not find header.", url: p.toUri(path));
}
var headerLevel = 0;
var index = headerMatch.start;
while (index >= 0 && included.codeUnitAt(index) == $hash) {
headerLevel++;
index--;
}
// The section goes until the next header of the same level, or the end
// of the document.
var sectionEnd = included.indexOf("#" * headerLevel, headerMatch.end);
if (sectionEnd == -1) sectionEnd = included.length;
return included.substring(headerMatch.end, sectionEnd).trim();
});
/// Throws a nice [SourceSpanException] associated with [match].
void _matchError(Match match, String message, {Object? url}) {
var file = SourceFile.fromString(match.input, url: url);
throw SourceSpanException(message, file.span(match.start, match.end));
}