|
| 1 | +// Copyright 2024 Google LLC. Use of this source code is governed by an |
| 2 | +// MIT-style license that can be found in the LICENSE file or at |
| 3 | +// https://opensource.org/licenses/MIT. |
| 4 | + |
| 5 | +import 'dart:js_util'; |
| 6 | + |
| 7 | +import 'package:async/async.dart'; |
| 8 | +import 'package:node_interop/js.dart'; |
| 9 | + |
| 10 | +import 'compile.dart'; |
| 11 | +import 'compile_options.dart'; |
| 12 | +import 'reflection.dart'; |
| 13 | +import 'utils.dart'; |
| 14 | + |
| 15 | +/// The Dart Compiler class. |
| 16 | +class Compiler { |
| 17 | + /// A flag signifying whether the instance has been disposed. |
| 18 | + bool _disposed = false; |
| 19 | + |
| 20 | + /// Checks if `dispose()` has been called on this instance, and throws an |
| 21 | + /// error if it has. Used to verify that compilation methods are not called |
| 22 | + /// after disposal. |
| 23 | + void _throwIfDisposed() { |
| 24 | + if (_disposed) { |
| 25 | + jsThrow(JsError('Compiler has already been disposed.')); |
| 26 | + } |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +/// The Dart Async Compiler class. |
| 31 | +class AsyncCompiler extends Compiler { |
| 32 | + /// A set of all compilations, tracked to ensure all compilations complete |
| 33 | + /// before async disposal resolves. |
| 34 | + final FutureGroup<void> compilations = FutureGroup(); |
| 35 | + |
| 36 | + /// Adds a compilation to the FutureGroup. |
| 37 | + void addCompilation(Promise compilation) { |
| 38 | + Future<dynamic> comp = promiseToFuture(compilation); |
| 39 | + var wrappedComp = comp.catchError((err) { |
| 40 | + /// Ignore errors so FutureGroup doesn't close when a compilation fails. |
| 41 | + }); |
| 42 | + compilations.add(wrappedComp); |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +/// The JavaScript `Compiler` class. |
| 47 | +final JSClass compilerClass = () { |
| 48 | + var jsClass = createJSClass( |
| 49 | + 'sass.Compiler', |
| 50 | + (Object self) => { |
| 51 | + jsThrow(JsError(("Compiler can not be directly constructed. " |
| 52 | + "Please use `sass.initCompiler()` instead."))) |
| 53 | + }); |
| 54 | + |
| 55 | + jsClass.defineMethods({ |
| 56 | + 'compile': (Compiler self, String path, [CompileOptions? options]) { |
| 57 | + self._throwIfDisposed(); |
| 58 | + return compile(path, options); |
| 59 | + }, |
| 60 | + 'compileString': (Compiler self, String source, |
| 61 | + [CompileStringOptions? options]) { |
| 62 | + self._throwIfDisposed(); |
| 63 | + return compileString(source, options); |
| 64 | + }, |
| 65 | + 'dispose': (Compiler self) { |
| 66 | + self._disposed = true; |
| 67 | + }, |
| 68 | + }); |
| 69 | + |
| 70 | + getJSClass(Compiler()).injectSuperclass(jsClass); |
| 71 | + return jsClass; |
| 72 | +}(); |
| 73 | + |
| 74 | +Compiler initCompiler() => Compiler(); |
| 75 | + |
| 76 | +/// The JavaScript `AsyncCompiler` class. |
| 77 | +final JSClass asyncCompilerClass = () { |
| 78 | + var jsClass = createJSClass( |
| 79 | + 'sass.AsyncCompiler', |
| 80 | + (Object self) => { |
| 81 | + jsThrow(JsError(("AsyncCompiler can not be directly constructed. " |
| 82 | + "Please use `sass.initAsyncCompiler()` instead."))) |
| 83 | + }); |
| 84 | + |
| 85 | + jsClass.defineMethods({ |
| 86 | + 'compileAsync': (AsyncCompiler self, String path, |
| 87 | + [CompileOptions? options]) { |
| 88 | + self._throwIfDisposed(); |
| 89 | + var compilation = compileAsync(path, options); |
| 90 | + self.addCompilation(compilation); |
| 91 | + return compilation; |
| 92 | + }, |
| 93 | + 'compileStringAsync': (AsyncCompiler self, String source, |
| 94 | + [CompileStringOptions? options]) { |
| 95 | + self._throwIfDisposed(); |
| 96 | + var compilation = compileStringAsync(source, options); |
| 97 | + self.addCompilation(compilation); |
| 98 | + return compilation; |
| 99 | + }, |
| 100 | + 'dispose': (AsyncCompiler self) { |
| 101 | + self._disposed = true; |
| 102 | + return futureToPromise((() async { |
| 103 | + self.compilations.close(); |
| 104 | + await self.compilations.future; |
| 105 | + })()); |
| 106 | + } |
| 107 | + }); |
| 108 | + |
| 109 | + getJSClass(AsyncCompiler()).injectSuperclass(jsClass); |
| 110 | + return jsClass; |
| 111 | +}(); |
| 112 | + |
| 113 | +Promise initAsyncCompiler() => futureToPromise((() async => AsyncCompiler())()); |
0 commit comments