Skip to content

Commit

Permalink
Refactor to prepare the plugin to work in browsers
Browse files Browse the repository at this point in the history
  • Loading branch information
madyankin committed Nov 4, 2022
1 parent 1ad9a28 commit e87c4ab
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 82 deletions.
5 changes: 3 additions & 2 deletions src/FileSystemLoader.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Initially copied from https://github.com/css-modules/css-modules-loader-core

import postcss from "postcss";
import fs from "fs";
import path from "path";

import Parser from "./Parser";
import { getFileSystem } from "./fs";

class Core {
constructor(plugins) {
Expand Down Expand Up @@ -62,6 +62,7 @@ export default class FileSystemLoader {
this.importNr = 0;
this.core = new Core(plugins);
this.tokensByFile = {};
this.fs = getFileSystem();
}

async fetch(_newPath, relativeTo, _trace) {
Expand Down Expand Up @@ -97,7 +98,7 @@ export default class FileSystemLoader {
if (tokens) return tokens;

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

const { injectableSource, exportTokens } = await this.core.load(
Expand Down
40 changes: 21 additions & 19 deletions src/Parser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copied from https://github.com/css-modules/css-modules-loader-core
// Initially copied from https://github.com/css-modules/css-modules-loader-core

const importRegexp = /^:import\((.+)\)$/;
import { replaceSymbols } from "icss-utils";
Expand All @@ -16,10 +16,10 @@ export default class Parser {
const parser = this;
return {
postcssPlugin: "css-modules-parser",
OnceExit(css) {
return Promise.all(parser.fetchAllImports(css))
.then(() => parser.linkImportedSymbols(css))
.then(() => parser.extractExports(css));
async OnceExit(css) {
await Promise.all(parser.fetchAllImports(css));
parser.linkImportedSymbols(css);
return parser.extractExports(css);
},
};
}
Expand Down Expand Up @@ -56,19 +56,21 @@ export default class Parser {
exportNode.remove();
}

fetchImport(importNode, relativeTo, depNr) {
let file = importNode.selector.match(importRegexp)[1],
depTrace = this.trace + String.fromCharCode(depNr);
return this.pathFetcher(file, relativeTo, depTrace).then(
(exports) => {
importNode.each((decl) => {
if (decl.type == "decl") {
this.translations[decl.prop] = exports[decl.value];
}
});
importNode.remove();
},
(err) => console.log(err)
);
async fetchImport(importNode, relativeTo, depNr) {
const file = importNode.selector.match(importRegexp)[1];
const depTrace = this.trace + String.fromCharCode(depNr);

const exports = await this.pathFetcher(file, relativeTo, depTrace);

try {
importNode.each((decl) => {
if (decl.type == "decl") {
this.translations[decl.prop] = exports[decl.value];
}
});
importNode.remove();
} catch (err) {
console.log(err);
}
}
}
28 changes: 0 additions & 28 deletions src/behaviours.js

This file was deleted.

18 changes: 18 additions & 0 deletions src/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let fileSystem = {
readFile: () => {
throw Error("readFile not implemented");
},

writeFile: () => {
throw Error("writeFile not implemented");
},
};

export function setFileSystem(fs) {
fileSystem.readFile = fs.readFile
fileSystem.writeFile = fs.writeFile
}

export function getFileSystem() {
return fileSystem;
}
9 changes: 0 additions & 9 deletions src/generateScopedName.js

This file was deleted.

33 changes: 11 additions & 22 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
import postcss from "postcss";
import camelCase from "lodash.camelcase";
import genericNames from "generic-names";
import unquote from "./unquote";
import { readFile, writeFile } from "fs";
import { setFileSystem } from "./fs";

import Parser from "./Parser";
import FileSystemLoader from "./FileSystemLoader";

import generateScopedName from "./generateScopedName";
import saveJSON from "./saveJSON";
import { getDefaultPlugins, isValidBehaviour, behaviours } from "./behaviours";
import {
getDefaultPlugins,
getDefaultScopeBehaviour,
behaviours,
getScopedNameGenerator,
} from "./scoping";

const PLUGIN_NAME = "postcss-modules";

function getDefaultScopeBehaviour(opts) {
if (opts.scopeBehaviour && isValidBehaviour(opts.scopeBehaviour)) {
return opts.scopeBehaviour;
}

return behaviours.LOCAL;
}

function getScopedNameGenerator(opts) {
const scopedNameGenerator = opts.generateScopedName || generateScopedName;

if (typeof scopedNameGenerator === "function") return scopedNameGenerator;
return genericNames(scopedNameGenerator, {
context: process.cwd(),
hashPrefix: opts.hashPrefix,
});
}
setFileSystem({ readFile, writeFile });

function getLoader(opts, plugins) {
const root = typeof opts.root === "undefined" ? "/" : opts.root;
Expand All @@ -44,8 +33,8 @@ function isGlobalModule(globalModules, inputFile) {
function getDefaultPluginsList(opts, inputFile) {
const globalModulesList = opts.globalModulePaths || null;
const exportGlobals = opts.exportGlobals || false;
const defaultBehaviour = getDefaultScopeBehaviour(opts);
const generateScopedName = getScopedNameGenerator(opts);
const defaultBehaviour = getDefaultScopeBehaviour(opts.scopeBehaviour);
const generateScopedName = getScopedNameGenerator(opts.generateScopedName, opts.hashPrefix);

if (globalModulesList && isGlobalModule(globalModulesList, inputFile)) {
return getDefaultPlugins({
Expand Down
3 changes: 2 additions & 1 deletion src/saveJSON.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { writeFile } from "fs";
import { getFileSystem } from "./fs";

export default function saveJSON(cssFile, json) {
return new Promise((resolve, reject) => {
const { writeFile } = getFileSystem();
writeFile(`${cssFile}.json`, JSON.stringify(json), (e) => (e ? reject(e) : resolve(json)));
});
}
55 changes: 55 additions & 0 deletions src/scoping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import extractImports from "postcss-modules-extract-imports";
import genericNames from "generic-names";
import localByDefault from "postcss-modules-local-by-default";
import modulesScope from "postcss-modules-scope";
import stringHash from "string-hash";
import values from "postcss-modules-values";

export const behaviours = {
LOCAL: "local",
GLOBAL: "global",
};

export function getDefaultPlugins({ behaviour, generateScopedName, exportGlobals }) {
const scope = modulesScope({ generateScopedName, exportGlobals });

const plugins = {
[behaviours.LOCAL]: [values, localByDefault({ mode: "local" }), extractImports, scope],
[behaviours.GLOBAL]: [values, localByDefault({ mode: "global" }), extractImports, scope],
};

return plugins[behaviour];
}

function isValidBehaviour(behaviour) {
return (
Object.keys(behaviours)
.map((key) => behaviours[key])
.indexOf(behaviour) > -1
);
}

export function getDefaultScopeBehaviour(scopeBehaviour) {
return scopeBehaviour && isValidBehaviour(scopeBehaviour) ? scopeBehaviour : behaviours.LOCAL;
}

function generateScopedNameDefault(name, filename, css) {
const i = css.indexOf(`.${name}`);
const lineNumber = css.substr(0, i).split(/[\r\n]/).length;
const hash = stringHash(css).toString(36).substr(0, 5);

return `_${name}_${hash}_${lineNumber}`;
}

export function getScopedNameGenerator(generateScopedName, hashPrefix) {
const scopedNameGenerator = generateScopedName || generateScopedNameDefault;

if (typeof scopedNameGenerator === "function") {
return scopedNameGenerator;
}

return genericNames(scopedNameGenerator, {
context: process.cwd(),
hashPrefix: hashPrefix,
});
}
2 changes: 1 addition & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import autoprefixer from "autoprefixer";
import fs from "fs";
import path from "path";
import plugin from "../src";
import { behaviours } from "../src/behaviours";
import { behaviours } from "../src/scoping";

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

Expand Down

0 comments on commit e87c4ab

Please sign in to comment.