Repository: tivac/modular-css
Pull request #671 (2019-09-19 15:21:31)

Custom file reader api
not ready, this is some on going work likely needed for a better webpack loader integration, work in progress here: https://github.com/jquense/css-module-loader

jquense: cc @evilebottnawi
evilebottnawi: Yes, idea is good, better use promisify'd api as recommended above
tivac: @jquense are you still planning to pursue this? I have some time and could tackle it if necessary since I think it's a big improvement over my original bad "always read from the filesystem" version.
jquense: @tivac I am still planning on it but need to get some stuff at work done first, so If you want to jump please feel free!
jquense: @tivac I'll pick this back up this week if you've not made additional progress on it.
tivac: @jquense I have made zero progress on this, so glad to see you back at it! I'm on vacation atm so it'll be a little bit before I can provide proper reviews and replies but I'll try to not let it sit for too long.

Patch:
diff --git a/.github/labeler.yml b/.github/labeler.yml
deleted file mode 100644
index b501f8c2..00000000
--- a/.github/labeler.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-pkg:core:
-- packages/processor/**/*
-
-pkg:rollup:
-- packages/rollup/**/*
-
-pkg:rollup-rewriter:
-- packages/rollup-rewriter/**/*
-
-pkg:svelte:
-- packages/svelte/**/*
-
-pkg:webpack:
-- packages/webpack/**/*
-
-pkg:browserify:
-- packages/browserify/**/*
-
-pkg:cli:
-- packages/cli/**/*
-
-pkg:www:
-- packages/www/**/*
-
-greenkeeper:
-- packages/processor/**/*
diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml
deleted file mode 100644
index 57d931fd..00000000
--- a/.github/workflows/issue-labeler.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-name: "Pull Request Labeler"
-on:
-  pull_request:
-    branches:
-    - master
-
-jobs:
-  triage:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/labeler@v2
-      with:
-        repo-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/packages/processor/processor.js b/packages/processor/processor.js
index b8b966c5..35eaf8fa 100644
--- a/packages/processor/processor.js
+++ b/packages/processor/processor.js
@@ -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;
diff --git a/packages/www/src/api/usage-js.md b/packages/www/src/api/usage-js.md
index 98d12b0f..edaadeea 100644
--- a/packages/www/src/api/usage-js.md
+++ b/packages/www/src/api/usage-js.md
@@ -141,9 +141,25 @@ new Processor({
         (src, file, resolve) => ...,
         require("@modular-css/path-resolver")(
             "./some/other/path"
-        )
-    ]
-})
+        ),
+    ],
+});
+```
+
+##### `loadFile`
+
+Specify a function that will be responsible for taking a file path and returning the text contents of the file. The function can be synchronous, return a promise, or use `async`/`await`.
+
+The default implementation uses `fs` to read files off the local filesystem.
+
+```js
+new Processor({
+    async loadFile(id) {
+        const text = await goGetItFromSomewhere(id);
+
+        return text;
+    },
+});
 ```
 
 ##### `exportGlobals`


Test patch:
diff --git a/packages/processor/test/api.test.js b/packages/processor/test/api.test.js
index 067159c7..3dd12638 100644
--- a/packages/processor/test/api.test.js
+++ b/packages/processor/test/api.test.js
@@ -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,7 +184,7 @@ 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();
@@ -192,25 +192,25 @@ describe("/processor.js", () => {
 
             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(
diff --git a/packages/svelte/test/__snapshots__/svelte.test.js.snap b/packages/svelte/test/__snapshots__/svelte.test.js.snap
index b9063f8f..75ae404f 100644
--- a/packages/svelte/test/__snapshots__/svelte.test.js.snap
+++ b/packages/svelte/test/__snapshots__/svelte.test.js.snap
@@ -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]",