Skip to content
Permalink
Browse files
feat: Custom file reader api (#671)
Add a new option, `loadFile`, that can be used to specify a custom file-loading function for cases where the file isn't necessarily a real file on the local file system.
  • Loading branch information
jquense authored and tivac committed Oct 29, 2019
1 parent da2a4f7 commit f1865c915c3a3553ca7731c3a015e25896aeea9f
Showing with 85 additions and 57 deletions.
  1. +17 −5 packages/processor/processor.js
  2. +39 −39 packages/processor/test/api.test.js
  3. +10 −10 packages/svelte/test/__snapshots__/svelte.test.js.snap
  4. +19 −3 packages/www/src/api/usage-js.md
@@ -18,6 +18,8 @@ const { resolvers } = require("./lib/resolve.js");

const noop = () => true;

const defaultLoadFile = (id) => fs.readFileSync(id, "utf8");

const params = ({ _options, _files, _graph, _resolve }, args) => Object.assign(
Object.create(null),
_options,
@@ -37,10 +39,12 @@ class Processor {
const options = Object.assign(
Object.create(null),
{
cwd : process.cwd(),
cwd : process.cwd(),
map : false,

dupewarn : true,
exportValues : true,
map : false,
loadFile : defaultLoadFile,
postcss : {},
resolvers : [],
rewrite : true,
@@ -70,7 +74,10 @@ class Processor {
// eslint-disable-next-line no-empty-function
() => {};

this._loadFile = options.loadFile;

this._resolve = resolvers(options.resolvers);

this._normalize = normalize.bind(null, this._options.cwd);

this._files = Object.create(null);
@@ -110,12 +117,14 @@ class Processor {
}

// Add a file on disk to the dependency graph
file(file) {
async file(file) {
const id = this._normalize(file);

this._log("file()", id);

return this._add(id, fs.readFileSync(id, "utf8"));
const text = await this._loadFile(id);

return this._add(id, text);
}

// Add a file by name + contents to the dependency graph
@@ -418,6 +427,9 @@ class Processor {
async _walk(name, text) {
// No need to re-process files unless they've been marked invalid
if(this._files[name] && this._files[name].valid) {
// Do want to wait until they're done being processed though
await this._files[name].walked;

return;
}

@@ -459,7 +471,7 @@ class Processor {
await Promise.all(
this._graph.dependenciesOf(name).map((dependency) => {
const { valid, walked : complete } = this._files[dependency] || false;

// If the file hasn't been invalidated wait for it to be done processing
if(valid) {
return complete;
@@ -18,7 +18,7 @@ describe("/processor.js", () => {
it("should be a function", () => {
expect(typeof Processor).toBe("function");
});

describe(".string()", () => {
it("should process a string", async () => {
const result = await processor.string(
@@ -31,11 +31,11 @@ describe("/processor.js", () => {
expect(result.details.processed.root.toResult().css).toMatchSnapshot();
});
});

describe(".file()", () => {
it("should process a relative file", async () => {
const result = await processor.file("./packages/processor/test/specimens/simple.css");

expect(result.exports).toMatchSnapshot();
expect(result.details.exports).toMatchSnapshot();
expect(result.details.text).toMatchSnapshot();
@@ -58,11 +58,11 @@ describe("/processor.js", () => {
processor.file(require.resolve("./specimens/overlapping/entry1.css")),
processor.file(require.resolve("./specimens/overlapping/entry2.css")),
]);

expect(results.map((result) => result.exports)).toMatchSnapshot();
});
});

describe(".has()", () => {
it("should return a boolean", async () => {
await processor.string(
@@ -73,7 +73,7 @@ describe("/processor.js", () => {
expect(processor.has("./simple.css")).toBe(true);
expect(processor.has("./nope.css")).toBe(false);
});

it("should normalize inputs before checking for existence", async () => {
await processor.string(
"./simple.css",
@@ -83,7 +83,7 @@ describe("/processor.js", () => {
expect(processor.has("../modular-css/simple.css")).toBe(true);
});
});

describe(".normalize()", () => {
it("should normalize inputs", async () => {
expect(relative([ processor.normalize("../modular-css/simple.css") ])).toMatchSnapshot();
@@ -98,7 +98,7 @@ describe("/processor.js", () => {
);

processor.remove("./simple.css");

expect(relative(processor.dependencies())).toMatchSnapshot();
});

@@ -109,28 +109,28 @@ describe("/processor.js", () => {
);

processor.remove(require.resolve("./specimens/simple.css"));

expect(relative(processor.dependencies())).toMatchSnapshot();
});

it("should remove multiple files", async () => {
await processor.string("./a.css", ".a { }");
await processor.string("./b.css", ".b { }");
await processor.string("./c.css", ".c { }");

processor.remove([
"./a.css",
"./b.css",
]);

expect(relative(processor.dependencies())).toMatchSnapshot();
});

it("should return an array of removed files", async () => {
await processor.string("./a.css", ".a { }");
await processor.string("./b.css", ".b { }");
await processor.string("./c.css", ".c { }");

expect(
relative(
processor.remove([
@@ -175,7 +175,7 @@ describe("/processor.js", () => {

expect(() => processor.invalidate()).toThrowErrorMatchingSnapshot();
});

it("should throw if an invalid file is passed", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

@@ -184,33 +184,33 @@ describe("/processor.js", () => {

it("should invalidate all dependents as well", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

processor.invalidate("./packages/processor/test/specimens/folder/folder.css");

expect(status(processor.files)).toMatchSnapshot();
});

it("should reprocess invalidated files", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

processor.invalidate("./packages/processor/test/specimens/start.css");

await processor.file("./packages/processor/test/specimens/start.css");

expect(status(processor.files)).toMatchSnapshot();
});
});

describe(".dependencies()", () => {
it("should return the dependencies of the specified file", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

expect(
relative(processor.dependencies(require.resolve("./specimens/start.css")))
)
.toMatchSnapshot();
});

it("should return the overall order of dependencies if no file is specified", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

@@ -227,14 +227,14 @@ describe("/processor.js", () => {
)
.toMatchSnapshot();
});

it("should throw if no file is passed", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

expect(() => processor.dependents()).toThrowErrorMatchingSnapshot();
});
});

describe(".output()", () => {
it("should reject unknown files", async () => {
await expect(processor.output({
@@ -243,19 +243,19 @@ describe("/processor.js", () => {
],
})).rejects.toThrow("Unknown file requested");
});

it("should return a postcss result", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

const result = await processor.output();

expect(result.css).toMatchSnapshot();
});

it("should generate css representing the output from all added files", async () => {
await processor.file("./packages/processor/test/specimens/start.css");
await processor.file("./packages/processor/test/specimens/simple.css");

const result = await processor.output();

expect(result.css).toMatchSnapshot();
@@ -264,26 +264,26 @@ describe("/processor.js", () => {
it("should avoid duplicating files in the output", async () => {
await processor.file("./packages/processor/test/specimens/start.css");
await processor.file("./packages/processor/test/specimens/local.css");

const result = await processor.output();

expect(result.css).toMatchSnapshot();
});

it("should generate a JSON structure of all the compositions", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

const result = await processor.output();

expect(result.compositions).toMatchSnapshot();
});

it("should order output by dependencies, then alphabetically", async () => {
await processor.file("./packages/processor/test/specimens/start.css");
await processor.file("./packages/processor/test/specimens/local.css");
await processor.file("./packages/processor/test/specimens/composes.css");
await processor.file("./packages/processor/test/specimens/deep.css");

const result = await processor.output();

expect(result.css).toMatchSnapshot();
@@ -292,7 +292,7 @@ describe("/processor.js", () => {
it("should support returning output for specified relative files", async () => {
await processor.file("./packages/processor/test/specimens/start.css");
await processor.file("./packages/processor/test/specimens/local.css");

const result = await processor.output({
files : [
"./packages/processor/test/specimens/start.css",
@@ -305,7 +305,7 @@ describe("/processor.js", () => {
it("should support returning output for specified absolute files", async () => {
await processor.file("./packages/processor/test/specimens/start.css");
await processor.file("./packages/processor/test/specimens/local.css");

const result = await processor.output({
files : [
require.resolve("./specimens/start.css"),
@@ -317,7 +317,7 @@ describe("/processor.js", () => {

it("should allow for seperate source map output", async () => {
await processor.file("./packages/processor/test/specimens/start.css");

const result = await processor.output({
map : {
inline : false,
@@ -347,7 +347,7 @@ describe("/processor.js", () => {
},
],
});

expect(
relative([
processor.resolve(
@@ -367,7 +367,7 @@ describe("/processor.js", () => {
() => undefined,
],
});

expect(
relative([
processor.resolve(
@@ -467,18 +467,18 @@ Array [
],
Array [
"[processor]",
"_add()",
"packages/svelte/test/specimens/simple.css",
"file()",
"packages/svelte/test/specimens/dependencies.css",
],
Array [
"[processor]",
"_before()",
"_add()",
"packages/svelte/test/specimens/simple.css",
],
Array [
"[processor]",
"file()",
"packages/svelte/test/specimens/dependencies.css",
"_before()",
"packages/svelte/test/specimens/simple.css",
],
Array [
"[processor]",
@@ -571,18 +571,18 @@ Array [
],
Array [
"[processor]",
"_add()",
"packages/svelte/test/specimens/simple.css",
"file()",
"packages/svelte/test/specimens/dependencies.css",
],
Array [
"[processor]",
"_before()",
"_add()",
"packages/svelte/test/specimens/simple.css",
],
Array [
"[processor]",
"file()",
"packages/svelte/test/specimens/dependencies.css",
"_before()",
"packages/svelte/test/specimens/simple.css",
],
Array [
"[processor]",

0 comments on commit f1865c9

Please sign in to comment.