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

[Shared Resources] dart-sass implementation #2134

Merged
merged 13 commits into from
Jan 18, 2024
6 changes: 6 additions & 0 deletions lib/src/js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'js/exception.dart';
import 'js/exports.dart';
import 'js/compile.dart';
import 'js/compiler.dart';
import 'js/legacy.dart';
import 'js/legacy/types.dart';
import 'js/legacy/value.dart';
Expand All @@ -24,6 +25,11 @@ void main() {
exports.compileAsync = allowInteropNamed('sass.compileAsync', compileAsync);
exports.compileStringAsync =
allowInteropNamed('sass.compileStringAsync', compileStringAsync);
exports.initCompiler = allowInteropNamed('sass.initCompiler', initCompiler);
exports.initAsyncCompiler =
allowInteropNamed('sass.initAsyncCompiler', initAsyncCompiler);
exports.Compiler = compilerClass;
exports.AsyncCompiler = asyncCompilerClass;
exports.Value = valueClass;
exports.SassBoolean = booleanClass;
exports.SassArgumentList = argumentListClass;
Expand Down
113 changes: 113 additions & 0 deletions lib/src/js/compiler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2024 Google LLC. 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:js_util';

import 'package:async/async.dart';
import 'package:node_interop/js.dart';

import 'compile.dart';
import 'compile_options.dart';
import 'reflection.dart';
import 'utils.dart';

/// The Dart Compiler class.
class Compiler {
jamesnw marked this conversation as resolved.
Show resolved Hide resolved
jamesnw marked this conversation as resolved.
Show resolved Hide resolved
/// A flag signifying whether the instance has been disposed.
bool _disposed = false;

/// Checks if `dispose()` has been called on this instance, and throws an
/// error if it has. Used to verify that compilation methods are not called
/// after disposal.
void _throwIfDisposed() {
if (_disposed) {
jsThrow(JsError('Compiler has already been disposed.'));
}
}
}

/// The Dart Async Compiler class.
class AsyncCompiler extends Compiler {
/// A set of all compilations, tracked to ensure all compilations complete
/// before async disposal resolves.
final FutureGroup<void> compilations = FutureGroup();

/// Adds a compilation to the FutureGroup.
void addCompilation(Promise compilation) {
Future<dynamic> comp = promiseToFuture(compilation);
var wrappedComp = comp.catchError((err) {
/// Ignore errors so FutureGroup doesn't close when a compilation fails.
});
compilations.add(wrappedComp);
}
}

/// The JavaScript `Compiler` class.
final JSClass compilerClass = () {
var jsClass = createJSClass(
'sass.Compiler',
(Object self) => {
jsThrow(JsError(("Compiler can not be directly constructed. "
"Please use `sass.initCompiler()` instead.")))
});

jsClass.defineMethods({
'compile': (Compiler self, String path, [CompileOptions? options]) {
self._throwIfDisposed();
return compile(path, options);
},
'compileString': (Compiler self, String source,
[CompileStringOptions? options]) {
self._throwIfDisposed();
return compileString(source, options);
},
'dispose': (Compiler self) {
self._disposed = true;
},
});

getJSClass(Compiler()).injectSuperclass(jsClass);
return jsClass;
}();

Compiler initCompiler() => Compiler();

/// The JavaScript `AsyncCompiler` class.
final JSClass asyncCompilerClass = () {
var jsClass = createJSClass(
'sass.AsyncCompiler',
(Object self) => {
jsThrow(JsError(("AsyncCompiler can not be directly constructed. "
"Please use `sass.initAsyncCompiler()` instead.")))
});

jsClass.defineMethods({
'compileAsync': (AsyncCompiler self, String path,
[CompileOptions? options]) {
self._throwIfDisposed();
var compilation = compileAsync(path, options);
self.addCompilation(compilation);
return compilation;
},
'compileStringAsync': (AsyncCompiler self, String source,
[CompileStringOptions? options]) {
self._throwIfDisposed();
var compilation = compileStringAsync(source, options);
self.addCompilation(compilation);
return compilation;
},
'dispose': (AsyncCompiler self) {
self._disposed = true;
return futureToPromise((() async {
self.compilations.close();
await self.compilations.future;
})());
}
});

getJSClass(AsyncCompiler()).injectSuperclass(jsClass);
return jsClass;
}();

Promise initAsyncCompiler() => futureToPromise((() async => AsyncCompiler())());
4 changes: 4 additions & 0 deletions lib/src/js/exports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class Exports {
external set compileStringAsync(Function function);
external set compile(Function function);
external set compileAsync(Function function);
external set initCompiler(Function function);
external set initAsyncCompiler(Function function);
external set Compiler(JSClass function);
external set AsyncCompiler(JSClass function);
external set info(String info);
external set Exception(JSClass function);
external set Logger(LoggerNamespace namespace);
Expand Down
4 changes: 4 additions & 0 deletions tool/grind.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ void main(List<String> args) {
'compileAsync',
'compileString',
'compileStringAsync',
'initCompiler',
'initAsyncCompiler',
'Compiler',
'AsyncCompiler',
'Logger',
'SassArgumentList',
'SassBoolean',
Expand Down