Skip to content

Commit

Permalink
Merge pull request #108 from css-modules/move-deps-into-the-lib
Browse files Browse the repository at this point in the history
Copy css-modules-loader-core sources into the repo
  • Loading branch information
madyankin committed Jun 23, 2020
2 parents a15e236 + f89bca1 commit d7b7146
Show file tree
Hide file tree
Showing 11 changed files with 2,239 additions and 1,731 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Expand Up @@ -2,6 +2,5 @@ sudo: false
language: node_js
node_js:
- node
- 11
- 12
- 10
- 8
11 changes: 11 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog

## 3.0.0

### Changed

- Dropped `css-modules-loader-core` dependency
- [Upgraded all the dependencies](https://github.com/css-modules/postcss-modules/pull/108)

### Breaking changes

- Dropped support for unsupported Node versions. Supported versions are 10, 12 and 14+ https://nodejs.org/en/about/releases/

## 2.0.0

### Added
Expand Down
24 changes: 14 additions & 10 deletions package.json
Expand Up @@ -18,25 +18,29 @@
"url": "https://github.com/css-modules/postcss-modules.git"
},
"dependencies": {
"css-modules-loader-core": "^1.1.0",
"generic-names": "^2.0.1",
"icss-replace-symbols": "^1.1.0",
"lodash.camelcase": "^4.3.0",
"postcss": "^7.0.1",
"postcss": "^7.0.32",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.2",
"postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0",
"string-hash": "^1.1.1"
},
"devDependencies": {
"autoprefixer": "^9.6.1",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-eslint": "^10.0.3",
"babel-eslint": "^10.1.0",
"babel-preset-env": "^1.7.0",
"eslint": "^6.4.0",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-jest": "^22.17.0",
"husky": "^3.0.5",
"jest": "^24.9.0",
"lint-staged": "^9.2.5",
"prettier": "^1.18.2"
"eslint": "^7.3.1",
"eslint-plugin-import": "^2.21.2",
"eslint-plugin-jest": "^23.17.0",
"husky": "^4.2.5",
"jest": "^26.0.1",
"lint-staged": "^10.2.11",
"prettier": "^2.0.5"
},
"scripts": {
"pretest": "$(npm bin)/eslint src test",
Expand Down
10 changes: 5 additions & 5 deletions src/behaviours.js
@@ -1,8 +1,8 @@
import Core from "css-modules-loader-core";
import Core from "./css-loader-core";

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

export function getDefaultPlugins(behaviour, generateScopedName) {
Expand All @@ -13,10 +13,10 @@ export function getDefaultPlugins(behaviour, generateScopedName) {
Core.values,
Core.localByDefault,
Core.extractImports,
scope
scope,
],

[behaviours.GLOBAL]: [Core.values, Core.extractImports, scope]
[behaviours.GLOBAL]: [Core.values, Core.extractImports, scope],
};

return plugins[behaviour];
Expand All @@ -25,7 +25,7 @@ export function getDefaultPlugins(behaviour, generateScopedName) {
export function isValidBehaviour(behaviour) {
return (
Object.keys(behaviours)
.map(key => behaviours[key])
.map((key) => behaviours[key])
.indexOf(behaviour) > -1
);
}
36 changes: 36 additions & 0 deletions src/css-loader-core/index.js
@@ -0,0 +1,36 @@
// Copied from https://github.com/css-modules/css-modules-loader-core

import postcss from "postcss";
import localByDefault from "postcss-modules-local-by-default";
import extractImports from "postcss-modules-extract-imports";
import scope from "postcss-modules-scope";
import values from "postcss-modules-values";

import Parser from "./parser";

export default class Core {
constructor(plugins) {
this.plugins = plugins || Core.defaultPlugins;
}

load(sourceString, sourcePath, trace, pathFetcher) {
let parser = new Parser(pathFetcher, trace);

return postcss(this.plugins.concat([parser.plugin]))
.process(sourceString, { from: "/" + sourcePath })
.then((result) => {
return {
injectableSource: result.css,
exportTokens: parser.exportTokens,
};
});
}
}

// These four plugins are aliased under this package for simplicity.
Core.values = values;
Core.localByDefault = localByDefault;
Core.extractImports = extractImports;
Core.scope = scope;

Core.defaultPlugins = [values, localByDefault, extractImports, scope];
91 changes: 91 additions & 0 deletions src/css-loader-core/loader.js
@@ -0,0 +1,91 @@
// Copied from https://github.com/css-modules/css-modules-loader-core

import Core from "./index.js";
import fs from "fs";
import path from "path";

// Sorts dependencies in the following way:
// AAA comes before AA and A
// AB comes after AA and before A
// All Bs come after all As
// This ensures that the files are always returned in the following order:
// - In the order they were required, except
// - After all their dependencies
const traceKeySorter = (a, b) => {
if (a.length < b.length) {
return a < b.substring(0, a.length) ? -1 : 1;
} else if (a.length > b.length) {
return a.substring(0, b.length) <= b ? -1 : 1;
} else {
return a < b ? -1 : 1;
}
};

export default class FileSystemLoader {
constructor(root, plugins) {
this.root = root;
this.sources = {};
this.traces = {};
this.importNr = 0;
this.core = new Core(plugins);
this.tokensByFile = {};
}

fetch(_newPath, relativeTo, _trace) {
let newPath = _newPath.replace(/^["']|["']$/g, ""),
trace = _trace || String.fromCharCode(this.importNr++);
return new Promise((resolve, reject) => {
let relativeDir = path.dirname(relativeTo),
rootRelativePath = path.resolve(relativeDir, newPath),
fileRelativePath = path.resolve(
path.join(this.root, relativeDir),
newPath
);

// if the path is not relative or absolute, try to resolve it in node_modules
if (newPath[0] !== "." && newPath[0] !== "/") {
try {
fileRelativePath = require.resolve(newPath);
} catch (e) {
// noop
}
}

const tokens = this.tokensByFile[fileRelativePath];
if (tokens) {
return resolve(tokens);
}

fs.readFile(fileRelativePath, "utf-8", (err, source) => {
if (err) reject(err);
this.core
.load(source, rootRelativePath, trace, this.fetch.bind(this))
.then(({ injectableSource, exportTokens }) => {
this.sources[fileRelativePath] = injectableSource;
this.traces[trace] = fileRelativePath;
this.tokensByFile[fileRelativePath] = exportTokens;
resolve(exportTokens);
}, reject);
});
});
}

get finalSource() {
const traces = this.traces;
const sources = this.sources;
let written = new Set();

return Object.keys(traces)
.sort(traceKeySorter)
.map((key) => {
const filename = traces[key];
if (written.has(filename)) {
return null;
}
written.add(filename);

return sources[filename];
})
.join("");
}
}
74 changes: 74 additions & 0 deletions src/css-loader-core/parser.js
@@ -0,0 +1,74 @@
// Copied from https://github.com/css-modules/css-modules-loader-core

const importRegexp = /^:import\((.+)\)$/;
import replaceSymbols from "icss-replace-symbols";

export default class Parser {
constructor(pathFetcher, trace) {
this.pathFetcher = pathFetcher;
this.plugin = this.plugin.bind(this);
this.exportTokens = {};
this.translations = {};
this.trace = trace;
}

plugin(css) {
return Promise.all(this.fetchAllImports(css))
.then(() => this.linkImportedSymbols(css))
.then(() => this.extractExports(css));
}

fetchAllImports(css) {
let imports = [];
css.each((node) => {
if (node.type == "rule" && node.selector.match(importRegexp)) {
imports.push(
this.fetchImport(node, css.source.input.from, imports.length)
);
}
});
return imports;
}

linkImportedSymbols(css) {
replaceSymbols(css, this.translations);
}

extractExports(css) {
css.each((node) => {
if (node.type == "rule" && node.selector == ":export")
this.handleExport(node);
});
}

handleExport(exportNode) {
exportNode.each((decl) => {
if (decl.type == "decl") {
Object.keys(this.translations).forEach((translation) => {
decl.value = decl.value.replace(
translation,
this.translations[translation]
);
});
this.exportTokens[decl.prop] = decl.value;
}
});
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)
);
}
}
4 changes: 1 addition & 3 deletions src/generateScopedName.js
Expand Up @@ -3,9 +3,7 @@ import stringHash from "string-hash";
export default function generateScopedName(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);
const hash = stringHash(css).toString(36).substr(0, 5);

return `_${name}_${hash}_${lineNumber}`;
}
14 changes: 8 additions & 6 deletions src/index.js
@@ -1,8 +1,10 @@
import postcss from "postcss";
import camelCase from "lodash.camelcase";
import Parser from "css-modules-loader-core/lib/parser";
import FileSystemLoader from "css-modules-loader-core/lib/file-system-loader";
import genericNames from "generic-names";

import Parser from "./css-loader-core/parser";
import FileSystemLoader from "./css-loader-core/loader";

import generateScopedName from "./generateScopedName";
import saveJSON from "./saveJSON";
import { getDefaultPlugins, isValidBehaviour, behaviours } from "./behaviours";
Expand All @@ -23,7 +25,7 @@ function getScopedNameGenerator(opts) {
if (typeof scopedNameGenerator === "function") return scopedNameGenerator;
return genericNames(scopedNameGenerator, {
context: process.cwd(),
hashPrefix: opts.hashPrefix
hashPrefix: opts.hashPrefix,
});
}

Expand All @@ -35,7 +37,7 @@ function getLoader(opts, plugins) {
}

function isGlobalModule(globalModules, inputFile) {
return globalModules.some(regex => inputFile.match(regex));
return globalModules.some((regex) => inputFile.match(regex));
}

function getDefaultPluginsList(opts, inputFile) {
Expand Down Expand Up @@ -72,7 +74,7 @@ module.exports = postcss.plugin(PLUGIN_NAME, (opts = {}) => {
const parser = new Parser(loader.fetch.bind(loader));

await postcss([...plugins, parser.plugin]).process(css, {
from: inputFile
from: inputFile,
});

const out = loader.finalSource;
Expand Down Expand Up @@ -111,7 +113,7 @@ module.exports = postcss.plugin(PLUGIN_NAME, (opts = {}) => {
result.messages.push({
type: "export",
plugin: "postcss-modules",
exportTokens: parser.exportTokens
exportTokens: parser.exportTokens,
});

// getJSON may return a promise
Expand Down
6 changes: 2 additions & 4 deletions src/saveJSON.js
Expand Up @@ -2,10 +2,8 @@ import { writeFile } from "fs";

export default function saveJSON(cssFile, json) {
return new Promise((resolve, reject) => {
writeFile(
`${cssFile}.json`,
JSON.stringify(json),
e => (e ? reject(e) : resolve(json))
writeFile(`${cssFile}.json`, JSON.stringify(json), (e) =>
e ? reject(e) : resolve(json)
);
});
}

0 comments on commit d7b7146

Please sign in to comment.