Skip to content

Commit 5e2abf5

Browse files
jamesnwjgerigmeyer
andauthored
[Package Importer] Embedded Host (#260)
Co-authored-by: Jonny Gerig Meyer <[email protected]>
1 parent e3f8462 commit 5e2abf5

File tree

6 files changed

+59
-6
lines changed

6 files changed

+59
-6
lines changed

lib/index.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export const compile = sass.compile;
44
export const compileAsync = sass.compileAsync;
55
export const compileString = sass.compileString;
66
export const compileStringAsync = sass.compileStringAsync;
7+
export const NodePackageImporter = sass.NodePackageImporter;
78
export const AsyncCompiler = sass.AsyncCompiler;
89
export const Compiler = sass.Compiler;
910
export const initAsyncCompiler = sass.initAsyncCompiler;
@@ -65,6 +66,10 @@ export default {
6566
defaultExportDeprecation();
6667
return sass.compileStringAsync;
6768
},
69+
get NodePackageImporter() {
70+
defaultExportDeprecation();
71+
return sass.NodePackageImporter;
72+
},
6873
get initAsyncCompiler() {
6974
defaultExportDeprecation();
7075
return sass.initAsyncCompiler;

lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export {
3131
compileString,
3232
compileAsync,
3333
compileStringAsync,
34+
NodePackageImporter,
3435
} from './src/compile';
3536
export {initAsyncCompiler, AsyncCompiler} from './src/compiler/async';
3637
export {initCompiler, Compiler} from './src/compiler/sync';

lib/src/compile.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {OptionsWithLegacy, StringOptionsWithLegacy} from './compiler/utils';
77
import {initCompiler} from './compiler/sync';
88
import {CompileResult} from './vendor/sass';
99

10+
export {NodePackageImporter} from './importer-registry';
11+
1012
export function compile(
1113
path: string,
1214
options?: OptionsWithLegacy<'sync'>

lib/src/importer-registry.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ import {FileImporter, Importer, Options} from './vendor/sass';
1111
import * as proto from './vendor/embedded_sass_pb';
1212
import {catchOr, thenOr, PromiseOr} from './utils';
1313

14+
const entryPointDirectoryKey = Symbol();
15+
16+
export class NodePackageImporter {
17+
readonly [entryPointDirectoryKey]: string;
18+
19+
constructor(entryPointDirectory?: string) {
20+
entryPointDirectory = entryPointDirectory
21+
? p.resolve(entryPointDirectory)
22+
: require.main?.filename
23+
? p.dirname(require.main.filename)
24+
: undefined;
25+
if (!entryPointDirectory) {
26+
throw new Error(
27+
'The Node package importer cannot determine an entry point ' +
28+
'because `require.main.filename` is not defined. ' +
29+
'Please provide an `entryPointDirectory` to the `NodePackageImporter`.'
30+
);
31+
}
32+
this[entryPointDirectoryKey] = entryPointDirectory;
33+
}
34+
}
35+
1436
/**
1537
* A registry of importers defined in the host that can be invoked by the
1638
* compiler.
@@ -30,7 +52,11 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {
3052

3153
constructor(options?: Options<sync>) {
3254
this.importers = (options?.importers ?? [])
33-
.map(importer => this.register(importer))
55+
.map(importer =>
56+
this.register(
57+
importer as Importer<sync> | FileImporter<sync> | NodePackageImporter
58+
)
59+
)
3460
.concat(
3561
(options?.loadPaths ?? []).map(
3662
path =>
@@ -43,10 +69,17 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {
4369

4470
/** Converts an importer to a proto without adding it to `this.importers`. */
4571
register(
46-
importer: Importer<sync> | FileImporter<sync>
72+
importer: Importer<sync> | FileImporter<sync> | NodePackageImporter
4773
): proto.InboundMessage_CompileRequest_Importer {
4874
const message = new proto.InboundMessage_CompileRequest_Importer();
49-
if ('canonicalize' in importer) {
75+
if (importer instanceof NodePackageImporter) {
76+
const importerMessage = new proto.NodePackageImporter();
77+
importerMessage.entryPointDirectory = importer[entryPointDirectoryKey];
78+
message.importer = {
79+
case: 'nodePackageImporter',
80+
value: importerMessage,
81+
};
82+
} else if ('canonicalize' in importer) {
5083
if ('findFileUrl' in importer) {
5184
throw new Error(
5285
'Importer may not contain both canonicalize() and findFileUrl(): ' +

lib/src/legacy/index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import * as fs from 'fs';
66
import * as p from 'path';
77
import {pathToFileURL, URL} from 'url';
8+
import {NodePackageImporter} from '../importer-registry';
89

910
import {Exception} from '../exception';
1011
import {
@@ -31,6 +32,8 @@ import {
3132
LegacyStringOptions,
3233
Options,
3334
StringOptions,
35+
Importer,
36+
FileImporter,
3437
} from '../vendor/sass';
3538
import {wrapFunction} from './value/wrap';
3639
import {endOfLoadProtocol, LegacyImporterWrapper} from './importer';
@@ -158,7 +161,10 @@ function convertOptions<sync extends 'sync' | 'async'>(
158161

159162
return {
160163
functions,
161-
importers,
164+
importers:
165+
options.pkgImporter instanceof NodePackageImporter
166+
? [options.pkgImporter, ...(importers ?? [])]
167+
: importers,
162168
sourceMap: wasSourceMapRequested(options),
163169
sourceMapIncludeSources: options.sourceMapContents,
164170
loadPaths: importers ? undefined : options.includePaths,
@@ -178,14 +184,20 @@ function convertStringOptions<sync extends 'sync' | 'async'>(
178184
): StringOptions<sync> & {legacy: true} {
179185
const modernOptions = convertOptions(options, sync);
180186

187+
// Find the first non-NodePackageImporter to pass as legacy `importer` option.
188+
// NodePackageImporter will be passed in `modernOptions.importers`.
189+
const importer = modernOptions.importers?.find(
190+
_importer => !(_importer instanceof NodePackageImporter)
191+
) as Importer<sync> | FileImporter<sync>;
192+
181193
return {
182194
...modernOptions,
183195
url: options.file
184196
? options.importer
185197
? pathToLegacyFileUrl(options.file)
186198
: pathToFileURL(options.file)
187199
: new URL(legacyImporterProtocol),
188-
importer: modernOptions.importers ? modernOptions.importers[0] : undefined,
200+
importer,
189201
syntax: options.indentedSyntax ? 'indented' : 'scss',
190202
};
191203
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sass-embedded",
33
"version": "1.70.0",
4-
"protocol-version": "2.4.0",
4+
"protocol-version": "2.5.0",
55
"compiler-version": "1.70.0",
66
"description": "Node.js library that communicates with Embedded Dart Sass using the Embedded Sass protocol",
77
"repository": "sass/embedded-host-node",

0 commit comments

Comments
 (0)