Skip to content

Commit e87c4ab

Browse files
committed
Refactor to prepare the plugin to work in browsers
1 parent 1ad9a28 commit e87c4ab

File tree

9 files changed

+111
-82
lines changed

9 files changed

+111
-82
lines changed

src/FileSystemLoader.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Initially copied from https://github.com/css-modules/css-modules-loader-core
22

33
import postcss from "postcss";
4-
import fs from "fs";
54
import path from "path";
65

76
import Parser from "./Parser";
7+
import { getFileSystem } from "./fs";
88

99
class Core {
1010
constructor(plugins) {
@@ -62,6 +62,7 @@ export default class FileSystemLoader {
6262
this.importNr = 0;
6363
this.core = new Core(plugins);
6464
this.tokensByFile = {};
65+
this.fs = getFileSystem();
6566
}
6667

6768
async fetch(_newPath, relativeTo, _trace) {
@@ -97,7 +98,7 @@ export default class FileSystemLoader {
9798
if (tokens) return tokens;
9899

99100
return new Promise((resolve, reject) => {
100-
fs.readFile(fileRelativePath, "utf-8", async (err, source) => {
101+
this.fs.readFile(fileRelativePath, "utf-8", async (err, source) => {
101102
if (err) reject(err);
102103

103104
const { injectableSource, exportTokens } = await this.core.load(

src/Parser.js

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copied from https://github.com/css-modules/css-modules-loader-core
1+
// Initially copied from https://github.com/css-modules/css-modules-loader-core
22

33
const importRegexp = /^:import\((.+)\)$/;
44
import { replaceSymbols } from "icss-utils";
@@ -16,10 +16,10 @@ export default class Parser {
1616
const parser = this;
1717
return {
1818
postcssPlugin: "css-modules-parser",
19-
OnceExit(css) {
20-
return Promise.all(parser.fetchAllImports(css))
21-
.then(() => parser.linkImportedSymbols(css))
22-
.then(() => parser.extractExports(css));
19+
async OnceExit(css) {
20+
await Promise.all(parser.fetchAllImports(css));
21+
parser.linkImportedSymbols(css);
22+
return parser.extractExports(css);
2323
},
2424
};
2525
}
@@ -56,19 +56,21 @@ export default class Parser {
5656
exportNode.remove();
5757
}
5858

59-
fetchImport(importNode, relativeTo, depNr) {
60-
let file = importNode.selector.match(importRegexp)[1],
61-
depTrace = this.trace + String.fromCharCode(depNr);
62-
return this.pathFetcher(file, relativeTo, depTrace).then(
63-
(exports) => {
64-
importNode.each((decl) => {
65-
if (decl.type == "decl") {
66-
this.translations[decl.prop] = exports[decl.value];
67-
}
68-
});
69-
importNode.remove();
70-
},
71-
(err) => console.log(err)
72-
);
59+
async fetchImport(importNode, relativeTo, depNr) {
60+
const file = importNode.selector.match(importRegexp)[1];
61+
const depTrace = this.trace + String.fromCharCode(depNr);
62+
63+
const exports = await this.pathFetcher(file, relativeTo, depTrace);
64+
65+
try {
66+
importNode.each((decl) => {
67+
if (decl.type == "decl") {
68+
this.translations[decl.prop] = exports[decl.value];
69+
}
70+
});
71+
importNode.remove();
72+
} catch (err) {
73+
console.log(err);
74+
}
7375
}
7476
}

src/behaviours.js

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/fs.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
let fileSystem = {
2+
readFile: () => {
3+
throw Error("readFile not implemented");
4+
},
5+
6+
writeFile: () => {
7+
throw Error("writeFile not implemented");
8+
},
9+
};
10+
11+
export function setFileSystem(fs) {
12+
fileSystem.readFile = fs.readFile
13+
fileSystem.writeFile = fs.writeFile
14+
}
15+
16+
export function getFileSystem() {
17+
return fileSystem;
18+
}

src/generateScopedName.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/index.js

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,23 @@
11
import postcss from "postcss";
22
import camelCase from "lodash.camelcase";
3-
import genericNames from "generic-names";
43
import unquote from "./unquote";
4+
import { readFile, writeFile } from "fs";
5+
import { setFileSystem } from "./fs";
56

67
import Parser from "./Parser";
78
import FileSystemLoader from "./FileSystemLoader";
89

9-
import generateScopedName from "./generateScopedName";
1010
import saveJSON from "./saveJSON";
11-
import { getDefaultPlugins, isValidBehaviour, behaviours } from "./behaviours";
11+
import {
12+
getDefaultPlugins,
13+
getDefaultScopeBehaviour,
14+
behaviours,
15+
getScopedNameGenerator,
16+
} from "./scoping";
1217

1318
const PLUGIN_NAME = "postcss-modules";
1419

15-
function getDefaultScopeBehaviour(opts) {
16-
if (opts.scopeBehaviour && isValidBehaviour(opts.scopeBehaviour)) {
17-
return opts.scopeBehaviour;
18-
}
19-
20-
return behaviours.LOCAL;
21-
}
22-
23-
function getScopedNameGenerator(opts) {
24-
const scopedNameGenerator = opts.generateScopedName || generateScopedName;
25-
26-
if (typeof scopedNameGenerator === "function") return scopedNameGenerator;
27-
return genericNames(scopedNameGenerator, {
28-
context: process.cwd(),
29-
hashPrefix: opts.hashPrefix,
30-
});
31-
}
20+
setFileSystem({ readFile, writeFile });
3221

3322
function getLoader(opts, plugins) {
3423
const root = typeof opts.root === "undefined" ? "/" : opts.root;
@@ -44,8 +33,8 @@ function isGlobalModule(globalModules, inputFile) {
4433
function getDefaultPluginsList(opts, inputFile) {
4534
const globalModulesList = opts.globalModulePaths || null;
4635
const exportGlobals = opts.exportGlobals || false;
47-
const defaultBehaviour = getDefaultScopeBehaviour(opts);
48-
const generateScopedName = getScopedNameGenerator(opts);
36+
const defaultBehaviour = getDefaultScopeBehaviour(opts.scopeBehaviour);
37+
const generateScopedName = getScopedNameGenerator(opts.generateScopedName, opts.hashPrefix);
4938

5039
if (globalModulesList && isGlobalModule(globalModulesList, inputFile)) {
5140
return getDefaultPlugins({

src/saveJSON.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { writeFile } from "fs";
1+
import { getFileSystem } from "./fs";
22

33
export default function saveJSON(cssFile, json) {
44
return new Promise((resolve, reject) => {
5+
const { writeFile } = getFileSystem();
56
writeFile(`${cssFile}.json`, JSON.stringify(json), (e) => (e ? reject(e) : resolve(json)));
67
});
78
}

src/scoping.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import extractImports from "postcss-modules-extract-imports";
2+
import genericNames from "generic-names";
3+
import localByDefault from "postcss-modules-local-by-default";
4+
import modulesScope from "postcss-modules-scope";
5+
import stringHash from "string-hash";
6+
import values from "postcss-modules-values";
7+
8+
export const behaviours = {
9+
LOCAL: "local",
10+
GLOBAL: "global",
11+
};
12+
13+
export function getDefaultPlugins({ behaviour, generateScopedName, exportGlobals }) {
14+
const scope = modulesScope({ generateScopedName, exportGlobals });
15+
16+
const plugins = {
17+
[behaviours.LOCAL]: [values, localByDefault({ mode: "local" }), extractImports, scope],
18+
[behaviours.GLOBAL]: [values, localByDefault({ mode: "global" }), extractImports, scope],
19+
};
20+
21+
return plugins[behaviour];
22+
}
23+
24+
function isValidBehaviour(behaviour) {
25+
return (
26+
Object.keys(behaviours)
27+
.map((key) => behaviours[key])
28+
.indexOf(behaviour) > -1
29+
);
30+
}
31+
32+
export function getDefaultScopeBehaviour(scopeBehaviour) {
33+
return scopeBehaviour && isValidBehaviour(scopeBehaviour) ? scopeBehaviour : behaviours.LOCAL;
34+
}
35+
36+
function generateScopedNameDefault(name, filename, css) {
37+
const i = css.indexOf(`.${name}`);
38+
const lineNumber = css.substr(0, i).split(/[\r\n]/).length;
39+
const hash = stringHash(css).toString(36).substr(0, 5);
40+
41+
return `_${name}_${hash}_${lineNumber}`;
42+
}
43+
44+
export function getScopedNameGenerator(generateScopedName, hashPrefix) {
45+
const scopedNameGenerator = generateScopedName || generateScopedNameDefault;
46+
47+
if (typeof scopedNameGenerator === "function") {
48+
return scopedNameGenerator;
49+
}
50+
51+
return genericNames(scopedNameGenerator, {
52+
context: process.cwd(),
53+
hashPrefix: hashPrefix,
54+
});
55+
}

test/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import autoprefixer from "autoprefixer";
33
import fs from "fs";
44
import path from "path";
55
import plugin from "../src";
6-
import { behaviours } from "../src/behaviours";
6+
import { behaviours } from "../src/scoping";
77

88
const fixturesPath = path.resolve(__dirname, "./fixtures");
99

0 commit comments

Comments
 (0)