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

[Package Importer] Embedded Host #260

Merged
merged 31 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
32e455f
Export nodePackageImporter
jamesnw Oct 26, 2023
8de2e60
Setup NodePackageImporter message
jamesnw Oct 27, 2023
67c812d
Add nodePackageImporter to legacy importers
jamesnw Oct 30, 2023
7bda416
Fix typo
jamesnw Nov 1, 2023
7b82352
Update protocol version
jamesnw Nov 9, 2023
e566b2f
Change export to Symbol
jamesnw Nov 17, 2023
e591fad
Remove type predicate, move check inline
jamesnw Nov 17, 2023
317ab80
Workaround symbol changes
jamesnw Nov 21, 2023
8c95697
Add link to Typescript issue
jamesnw Nov 22, 2023
5a5cfd2
Adjust entrypoint logic
jamesnw Nov 27, 2023
b3f5414
Address review
jamesnw Dec 4, 2023
cf4b0cc
Lint
jamesnw Dec 4, 2023
97b3685
review
jgerigmeyer Dec 15, 2023
34298c4
Workaround Node regression: https://github.com/nodejs/node/issues/51167
jgerigmeyer Dec 15, 2023
2417f0b
Merge branch 'main' into feature.package-importer
jgerigmeyer Dec 15, 2023
b5c84a6
Update NodePackageImporter to class
jamesnw Dec 19, 2023
8964f75
Revert legacyImporterProtocol
jamesnw Dec 20, 2023
a55acff
Fix path import, legacy importer options.
jamesnw Dec 20, 2023
a469cf1
Merge branch 'main' into feature.package-importer
jgerigmeyer Jan 5, 2024
0f7f3f9
remove outdated legacy importer syntax
jgerigmeyer Jan 5, 2024
75e338a
re-add legacy pkgImporter logic
jgerigmeyer Jan 5, 2024
b8e96d6
Address review
jgerigmeyer Jan 7, 2024
623a0b9
Merge branch 'main' of https://github.com/sass/embedded-host-node int…
jamesnw Jan 17, 2024
988fabb
Update protocol version
jamesnw Jan 17, 2024
abd2a71
Merge branch 'main' of https://github.com/sass/embedded-host-node int…
jamesnw Jan 18, 2024
f05aa50
Address review
jgerigmeyer Jan 25, 2024
83be63a
Update entry point to directory
jamesnw Feb 1, 2024
be27f0b
Use directory of require.main.filename
jamesnw Feb 1, 2024
dfe637a
Remove redundant cwd in p.resolve
jamesnw Feb 1, 2024
1f4489c
Make entryPointDirectoryKey readonly and non-nullable
jgerigmeyer Feb 2, 2024
f571bfe
typo
jgerigmeyer Feb 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 Logger = sass.Logger;
export const CalculationInterpolation = sass.CalculationInterpolation
export const CalculationOperation = sass.CalculationOperation
Expand Down Expand Up @@ -60,6 +61,10 @@ export default {
defaultExportDeprecation();
return sass.compileStringAsync;
},
get nodePackageImporter() {
defaultExportDeprecation();
return sass.nodePackageImporter;
},
get Logger() {
defaultExportDeprecation();
return sass.Logger;
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 {render, renderSync} from './src/legacy';

Expand Down
10 changes: 6 additions & 4 deletions lib/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
legacyImporterProtocol,
} from './legacy/utils';

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

/// Allow the legacy API to pass in an option signaling to the modern API that
/// it's being run in legacy mode.
///
Expand All @@ -45,7 +47,7 @@ export function compile(
path: string,
options?: OptionsWithLegacy<'sync'>
): CompileResult {
const importers = new ImporterRegistry(options);
const importers = new ImporterRegistry(options, path);
return compileRequestSync(
newCompilePathRequest(path, importers, options),
importers,
Expand All @@ -57,7 +59,7 @@ export function compileString(
source: string,
options?: StringOptionsWithLegacy<'sync'>
): CompileResult {
const importers = new ImporterRegistry(options);
const importers = new ImporterRegistry(options, options?.url);
return compileRequestSync(
newCompileStringRequest(source, importers, options),
importers,
Expand All @@ -69,7 +71,7 @@ export function compileAsync(
path: string,
options?: OptionsWithLegacy<'async'>
): Promise<CompileResult> {
const importers = new ImporterRegistry(options);
const importers = new ImporterRegistry(options, path);
return compileRequestAsync(
newCompilePathRequest(path, importers, options),
importers,
Expand All @@ -81,7 +83,7 @@ export function compileStringAsync(
source: string,
options?: StringOptionsWithLegacy<'async'>
): Promise<CompileResult> {
const importers = new ImporterRegistry(options);
const importers = new ImporterRegistry(options, options?.url);
jgerigmeyer marked this conversation as resolved.
Show resolved Hide resolved
return compileRequestAsync(
newCompileStringRequest(source, importers, options),
importers,
Expand Down
41 changes: 36 additions & 5 deletions lib/src/importer-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@ import {URL} from 'url';
import {inspect} from 'util';

import * as utils from './utils';
import {FileImporter, Importer, Options} from './vendor/sass';
import {legacyImporterProtocol} from './legacy/utils';

import {
FileImporter,
Importer,
NodePackageImporter,
Options,
} from './vendor/sass';
import * as proto from './vendor/embedded_sass_pb';
import {catchOr, thenOr, PromiseOr} from './utils';

export const nodePackageImporter: NodePackageImporter =
Symbol() as NodePackageImporter;

/**
* A registry of importers defined in the host that can be invoked by the
* compiler.
Expand All @@ -28,9 +38,9 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {
/** The next ID to use for an importer. */
private id = 0;

constructor(options?: Options<sync>) {
constructor(options?: Options<sync>, entryPointURL?: string | URL) {
this.importers = (options?.importers ?? [])
.map(importer => this.register(importer))
.map(importer => this.register(importer, entryPointURL))
.concat(
(options?.loadPaths ?? []).map(
path =>
Expand All @@ -43,10 +53,31 @@ 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,
_entryPointURL?: string | URL
jamesnw marked this conversation as resolved.
Show resolved Hide resolved
): proto.InboundMessage_CompileRequest_Importer {
const message = new proto.InboundMessage_CompileRequest_Importer();
if ('canonicalize' in importer) {
if (typeof importer === 'symbol') {
if (importer !== nodePackageImporter) {
throw 'Incorrect Node Package Importer used';
jgerigmeyer marked this conversation as resolved.
Show resolved Hide resolved
}
const importerMessage = new proto.NodePackageImporter();
let entryPointURL = _entryPointURL ?? require.main?.filename;
entryPointURL = entryPointURL?.toString();
if (entryPointURL === legacyImporterProtocol)
entryPointURL = require.main?.filename;
jamesnw marked this conversation as resolved.
Show resolved Hide resolved

if (!entryPointURL) {
throw new Error(
'Node Package Importer requires access to a filesystem.'
jgerigmeyer marked this conversation as resolved.
Show resolved Hide resolved
);
}
importerMessage.entryPointUrl = entryPointURL;
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
60 changes: 43 additions & 17 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 @@ -140,25 +143,26 @@ function convertOptions<sync extends 'sync' | 'async'>(
functions[signature.trimLeft()] = wrapFunction(self, callback, sync);
}

const importers =
let importers;
if (
options.importer &&
(!(options.importer instanceof Array) || options.importer.length > 0)
? [
new LegacyImporterWrapper(
self,
options.importer instanceof Array
? options.importer
: [options.importer],
options.includePaths ?? [],
options.file ?? 'stdin',
sync
),
]
: undefined;
) {
importers = [
new LegacyImporterWrapper(
self,
options.importer instanceof Array
? options.importer
: [options.importer],
options.includePaths ?? [],
options.file ?? 'stdin',
sync
),
];
}

return {
const convertedOptions = {
functions,
importers,
sourceMap: wasSourceMapRequested(options),
sourceMapIncludeSources: options.sourceMapContents,
loadPaths: importers ? undefined : options.includePaths,
Expand All @@ -167,8 +171,24 @@ function convertOptions<sync extends 'sync' | 'async'>(
verbose: options.verbose,
charset: options.charset,
logger: options.logger,
legacy: true,
legacy: true as const,
};

// Use separate return statements, as applying logic directly to the inclusion
// of `nodePackageImporter` causes the symbol to use its unique flag.
// See https://github.com/microsoft/TypeScript/issues/55901
if (options.pkgImporter === 'node') {
importers = importers || [];
return {
...convertedOptions,
importers: [nodePackageImporter, ...importers],
};
} else {
return {
...convertedOptions,
importers,
};
}
jgerigmeyer marked this conversation as resolved.
Show resolved Hide resolved
}

// Converts `LegacyStringOptions` into new API `StringOptions`.
Expand All @@ -178,14 +198,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 !== 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.69.5",
"protocol-version": "2.3.0",
"protocol-version": "3.0.0-dev",
"compiler-version": "1.69.5",
"description": "Node.js library that communicates with Embedded Dart Sass using the Embedded Sass protocol",
"repository": "sass/embedded-host-node",
Expand Down
Loading