Skip to content

Commit

Permalink
[Package Importer] Embedded Host (#260)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonny Gerig Meyer <[email protected]>
  • Loading branch information
jamesnw and jgerigmeyer authored Feb 6, 2024
1 parent e3f8462 commit 5e2abf5
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 6 deletions.
5 changes: 5 additions & 0 deletions lib/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const compile = sass.compile;
export const compileAsync = sass.compileAsync;
export const compileString = sass.compileString;
export const compileStringAsync = sass.compileStringAsync;
export const NodePackageImporter = sass.NodePackageImporter;
export const AsyncCompiler = sass.AsyncCompiler;
export const Compiler = sass.Compiler;
export const initAsyncCompiler = sass.initAsyncCompiler;
Expand Down Expand Up @@ -65,6 +66,10 @@ export default {
defaultExportDeprecation();
return sass.compileStringAsync;
},
get NodePackageImporter() {
defaultExportDeprecation();
return sass.NodePackageImporter;
},
get initAsyncCompiler() {
defaultExportDeprecation();
return sass.initAsyncCompiler;
Expand Down
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export {
compileString,
compileAsync,
compileStringAsync,
NodePackageImporter,
} from './src/compile';
export {initAsyncCompiler, AsyncCompiler} from './src/compiler/async';
export {initCompiler, Compiler} from './src/compiler/sync';
Expand Down
2 changes: 2 additions & 0 deletions lib/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {OptionsWithLegacy, StringOptionsWithLegacy} from './compiler/utils';
import {initCompiler} from './compiler/sync';
import {CompileResult} from './vendor/sass';

export {NodePackageImporter} from './importer-registry';

export function compile(
path: string,
options?: OptionsWithLegacy<'sync'>
Expand Down
39 changes: 36 additions & 3 deletions lib/src/importer-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ import {FileImporter, Importer, Options} from './vendor/sass';
import * as proto from './vendor/embedded_sass_pb';
import {catchOr, thenOr, PromiseOr} from './utils';

const entryPointDirectoryKey = Symbol();

export class NodePackageImporter {
readonly [entryPointDirectoryKey]: string;

constructor(entryPointDirectory?: string) {
entryPointDirectory = entryPointDirectory
? p.resolve(entryPointDirectory)
: require.main?.filename
? p.dirname(require.main.filename)
: undefined;
if (!entryPointDirectory) {
throw new Error(
'The Node package importer cannot determine an entry point ' +
'because `require.main.filename` is not defined. ' +
'Please provide an `entryPointDirectory` to the `NodePackageImporter`.'
);
}
this[entryPointDirectoryKey] = entryPointDirectory;
}
}

/**
* A registry of importers defined in the host that can be invoked by the
* compiler.
Expand All @@ -30,7 +52,11 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {

constructor(options?: Options<sync>) {
this.importers = (options?.importers ?? [])
.map(importer => this.register(importer))
.map(importer =>
this.register(
importer as Importer<sync> | FileImporter<sync> | NodePackageImporter
)
)
.concat(
(options?.loadPaths ?? []).map(
path =>
Expand All @@ -43,10 +69,17 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {

/** Converts an importer to a proto without adding it to `this.importers`. */
register(
importer: Importer<sync> | FileImporter<sync>
importer: Importer<sync> | FileImporter<sync> | NodePackageImporter
): proto.InboundMessage_CompileRequest_Importer {
const message = new proto.InboundMessage_CompileRequest_Importer();
if ('canonicalize' in importer) {
if (importer instanceof NodePackageImporter) {
const importerMessage = new proto.NodePackageImporter();
importerMessage.entryPointDirectory = importer[entryPointDirectoryKey];
message.importer = {
case: 'nodePackageImporter',
value: importerMessage,
};
} else if ('canonicalize' in importer) {
if ('findFileUrl' in importer) {
throw new Error(
'Importer may not contain both canonicalize() and findFileUrl(): ' +
Expand Down
16 changes: 14 additions & 2 deletions lib/src/legacy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import * as fs from 'fs';
import * as p from 'path';
import {pathToFileURL, URL} from 'url';
import {NodePackageImporter} from '../importer-registry';

import {Exception} from '../exception';
import {
Expand All @@ -31,6 +32,8 @@ import {
LegacyStringOptions,
Options,
StringOptions,
Importer,
FileImporter,
} from '../vendor/sass';
import {wrapFunction} from './value/wrap';
import {endOfLoadProtocol, LegacyImporterWrapper} from './importer';
Expand Down Expand Up @@ -158,7 +161,10 @@ function convertOptions<sync extends 'sync' | 'async'>(

return {
functions,
importers,
importers:
options.pkgImporter instanceof NodePackageImporter
? [options.pkgImporter, ...(importers ?? [])]
: importers,
sourceMap: wasSourceMapRequested(options),
sourceMapIncludeSources: options.sourceMapContents,
loadPaths: importers ? undefined : options.includePaths,
Expand All @@ -178,14 +184,20 @@ function convertStringOptions<sync extends 'sync' | 'async'>(
): StringOptions<sync> & {legacy: true} {
const modernOptions = convertOptions(options, sync);

// Find the first non-NodePackageImporter to pass as legacy `importer` option.
// NodePackageImporter will be passed in `modernOptions.importers`.
const importer = modernOptions.importers?.find(
_importer => !(_importer instanceof NodePackageImporter)
) as Importer<sync> | FileImporter<sync>;

return {
...modernOptions,
url: options.file
? options.importer
? pathToLegacyFileUrl(options.file)
: pathToFileURL(options.file)
: new URL(legacyImporterProtocol),
importer: modernOptions.importers ? modernOptions.importers[0] : undefined,
importer,
syntax: options.indentedSyntax ? 'indented' : 'scss',
};
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sass-embedded",
"version": "1.70.0",
"protocol-version": "2.4.0",
"protocol-version": "2.5.0",
"compiler-version": "1.70.0",
"description": "Node.js library that communicates with Embedded Dart Sass using the Embedded Sass protocol",
"repository": "sass/embedded-host-node",
Expand Down

0 comments on commit 5e2abf5

Please sign in to comment.