Skip to content

Commit

Permalink
fix(less): respect paths options
Browse files Browse the repository at this point in the history
  • Loading branch information
Anidetrix committed Dec 28, 2020
1 parent f5aa1e2 commit a72ab4c
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 52 deletions.
14 changes: 4 additions & 10 deletions src/loaders/less/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,13 @@ const getStylesFileManager = (less: less.Less): less.FileManager =>
return true;
}

async loadFile(filename: string, basedir: string): Promise<less.File> {
async loadFile(filename: string, filedir: string, opts: less.Options): Promise<less.File> {
const url = normalizeUrl(filename);
const partialUrl = getUrlOfPartial(url);
const options = { basedir, extensions };

const options = { caller: "Less importer", basedirs: [filedir], extensions };
if (opts.paths) options.basedirs.push(...opts.paths);
// Give precedence to importing a partial
let id: string;
try {
id = await resolveAsync(partialUrl, options);
} catch {
id = await resolveAsync(url, options);
}

const id = await resolveAsync([partialUrl, url], options);
return { filename: id, contents: await fs.readFile(id, "utf8") };
}
})();
Expand Down
10 changes: 2 additions & 8 deletions src/loaders/postcss/icss/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,8 @@ export type Load = (
) => Promise<Record<string, string>>;

const load: Load = async (url, file, extensions, processor, opts) => {
let from: string;
const options = { basedir: path.dirname(file), extensions };
try {
from = await resolveAsync(url, options);
} catch {
from = await resolveAsync(`./${url}`, options);
}

const options = { caller: "ICSS loader", basedirs: [path.dirname(file)], extensions };
const from = await resolveAsync([url, `./${url}`], options);
const source = await fs.readFile(from);
const { messages } = await processor.process(source, { ...opts, from });

Expand Down
9 changes: 2 additions & 7 deletions src/loaders/postcss/import/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,8 @@ export type ImportResolve = (
) => Promise<ImportFile>;

const resolve: ImportResolve = async (url, basedir, extensions) => {
const options = { basedir, extensions };
let from: string;
try {
from = await resolveAsync(url, options);
} catch {
from = await resolveAsync(`./${url}`, options);
}
const options = { caller: "@import resolver", basedirs: [basedir], extensions };
const from = await resolveAsync([url, `./${url}`], options);
return { from, source: await fs.readFile(from) };
};

Expand Down
8 changes: 3 additions & 5 deletions src/loaders/postcss/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,9 @@ const loader: Loader<PostCSSLoaderOptions> = {
const injectorCall = `${injectorName}(${cssVarName},${JSON.stringify(injectorOptions)});`;

if (!injectorId) {
injectorId = await resolveAsync("./inject-css", {
basedir: path.join(testing ? process.cwd() : __dirname, "runtime"),
})
.then(normalizePath)
.then(JSON.stringify);
const opts = { basedirs: [path.join(testing ? process.cwd() : __dirname, "runtime")] };
injectorId = await resolveAsync(["./inject-css"], opts);
injectorId = `"${normalizePath(injectorId)}"`;
}

output.push(`import ${injectorName} from ${injectorId};`);
Expand Down
9 changes: 2 additions & 7 deletions src/loaders/postcss/url/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@ export interface UrlFile {
export type UrlResolve = (inputUrl: string, basedir: string) => Promise<UrlFile>;

const resolve: UrlResolve = async (inputUrl, basedir) => {
const options = { basedir };
let from: string;
const options = { caller: "URL resolver", basedirs: [basedir] };
const parseOptions: ParseOptions = { parseFragmentIdentifier: true, sort: false, decode: false };
const { url, query, fragmentIdentifier } = parseUrl(inputUrl, parseOptions);
try {
from = await resolveAsync(url, options);
} catch {
from = await resolveAsync(`./${url}`, options);
}
const from = await resolveAsync([url, `./${url}`], options);
const urlQuery = stringifyUrl({ url: "", query, fragmentIdentifier }, parseOptions);
return { from, source: await fs.readFile(from), urlQuery };
};
Expand Down
8 changes: 2 additions & 6 deletions src/loaders/sass/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,10 @@ export const importer: sass.Importer = (url, importer, done): void => {
if (!isModule(url)) return next();
const moduleUrl = normalizeUrl(url);
const partialUrl = getUrlOfPartial(moduleUrl);
const options = { basedir: path.dirname(importer), extensions };
const options = { caller: "Sass importer", basedirs: [path.dirname(importer)], extensions };

// Give precedence to importing a partial
resolveAsync(partialUrl, options)
.then(finalize)
.catch(() => {
resolveAsync(moduleUrl, options).then(finalize).catch(next);
});
resolveAsync([partialUrl, moduleUrl], options).then(finalize).catch(next);
};

const finalize = (id: string): sass.Data => ({ file: id.replace(/\.css$/i, "") });
Expand Down
6 changes: 3 additions & 3 deletions src/shims/less.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ declare namespace less {
}

class AbstractFileManager {
supportsSync(filename: string, basedir: string): boolean;
supportsSync(filename: string, filedir: string): boolean;
}

interface FileManager extends AbstractFileManager {
supports(filename: string, basedir: string): boolean;
loadFile(filename: string, basedir: string): Promise<File>;
supports(filename: string, filedir: string): boolean;
loadFile(filename: string, filedir: string, opts: Options): Promise<File>;
}

class PluginManager {
Expand Down
63 changes: 57 additions & 6 deletions src/utils/resolve-async.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,58 @@
import resolveAsync, { AsyncOpts } from "resolve";
import resolver, { AsyncOpts } from "resolve";
import arrayFmt from "./array-fmt";

export default async (id: string, options: AsyncOpts = {}): Promise<string> =>
new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- always present if there is no error
resolveAsync(id, options, (err, res) => (err ? reject(err) : resolve(res!)));
});
export interface ResolveOpts {
/** name of the caller for error message (default to `Resolver`) */
caller?: string;
/** directories to begin resolving from (defaults to `[__dirname]`) */
basedirs?: string[];
/** array of file extensions to search in order (defaults to `[".mjs", ".js", ".json"]`) */
extensions?: string | ReadonlyArray<string>;
/** don't resolve `basedirs` to real path before resolving. (defaults to `true`) */
preserveSymlinks?: boolean;
/** transform the parsed `package.json` contents before looking at the "main" field */
packageFilter?: (pkg: Package, pkgfile: string) => Package;
}

interface ResolveDefaultOpts {
caller: string;
basedirs: ReadonlyArray<string>;
extensions: ReadonlyArray<string>;
preserveSymlinks: boolean;
packageFilter: (pkg: Package, pkgfile: string) => Package;
}

interface Package {
main: string;
module?: string;
style?: string;
}

const defaultOpts: ResolveDefaultOpts = {
caller: "Resolver",
basedirs: [__dirname],
extensions: [".mjs", ".js", ".json"],
preserveSymlinks: true,
packageFilter(pkg) {
if (pkg.module) pkg.main = pkg.module;
if (pkg.style) pkg.main = pkg.style;
return pkg;
},
};

const resolveAsync = async (id: string, options: AsyncOpts = {}): Promise<string | undefined> =>
new Promise(resolve => resolver(id, options, (_, res) => resolve(res)));

export default async function (ids: string[], userOpts: ResolveOpts): Promise<string> {
const options = { ...defaultOpts, ...userOpts };
for await (const basedir of options.basedirs) {
const opts = { ...options, basedir, basedirs: undefined, caller: undefined };
for await (const id of ids) {
const resolved = await resolveAsync(id, opts);
if (resolved) return resolved;
}
}

const idsFmt = arrayFmt(ids);
throw new Error(`${options.caller} could not resolve ${idsFmt} `);
}

0 comments on commit a72ab4c

Please sign in to comment.