@typed/content-hash
Version:
Content hash a directory of HTML/JS/CSS files and other static assets
129 lines • 5.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCssPlugin = void 0;
const FxEnv_1 = require("@typed/fp/FxEnv");
const css_tree_1 = require("css-tree");
const Option_1 = require("fp-ts/Option");
const path_1 = require("path");
const typed_colors_1 = require("typed-colors");
const logging_1 = require("../../application/services/logging");
const fsReadFile_1 = require("../fsReadFile");
const getHashFor_1 = require("../hashes/getHashFor");
const defaults_1 = require("./defaults");
const getFileExtension_1 = require("./getFileExtension");
const isExternalUrl_1 = require("./isExternalUrl");
const resolvePackage_1 = require("./resolvePackage");
const supportedExtensions = ['.css.map', '.css'];
const sourceMapExt = '.map';
function createCssPlugin({ mainFields = defaults_1.MAIN_FIELDS }) {
const css = {
readFilePath: (filePath) => (0, FxEnv_1.Do)(function* (_) {
const ext = (0, getFileExtension_1.getFileExtension)(filePath);
if (!supportedExtensions.includes(ext)) {
yield* _((0, logging_1.debug)(`${(0, typed_colors_1.red)(`[CSS]`)} Unsupported file extension ${filePath}`));
return Option_1.none;
}
yield* _((0, logging_1.debug)(`${(0, typed_colors_1.yellow)(`[CSS]`)} Reading ${filePath}...`));
const initial = yield* _((0, fsReadFile_1.fsReadFile)(filePath, { supportsSourceMaps: true, isBase64Encoded: false }));
// Map files should just get setup with appropriate hashes
if (ext === sourceMapExt) {
return (0, Option_1.some)((0, getHashFor_1.getHashFor)(initial, '.css'));
}
yield* _((0, logging_1.debug)(`${(0, typed_colors_1.yellow)(`[CSS]`)} Finding dependencies ${filePath}...`));
return (0, Option_1.some)(findDependencies(initial, mainFields));
}),
};
return css;
}
exports.createCssPlugin = createCssPlugin;
function findDependencies(document, mainFields) {
const filename = path_1.posix.basename(document.filePath);
const ast = (0, css_tree_1.parse)(document.contents, { filename, positions: true });
const dependencies = new Set();
(0, css_tree_1.walk)(ast, (node) => {
if (isAtRule(node)) {
return parseAtRule(document.filePath, node, dependencies, mainFields);
}
if (isUrl(node)) {
return parseUrl(document.filePath, node, dependencies, mainFields);
}
return node;
});
return { ...document, dependencies: Array.from(dependencies) };
}
const isAtRule = (node) => node.type === 'Atrule' && !!node.loc;
const isUrl = (node) => node.type === 'Url' && !!node.loc;
const findAtRuleSpecifier = (rule) => {
if (rule.name === 'import' && rule.prelude && rule.prelude.type === 'AtrulePrelude') {
const specifierNode = rule.prelude.children.first();
if (specifierNode && specifierNode.type === 'String') {
const { start, end } = specifierNode.loc;
return {
specifier: specifierNode.value.slice(1, -1),
position: { start: start.offset + 1, end: end.offset - 1 },
};
}
}
if (rule.name === 'import' && rule.prelude && rule.prelude.type === 'Raw') {
const specifierNode = rule.prelude;
const { start, end } = specifierNode.loc;
return {
specifier: specifierNode.value,
position: { start: start.offset, end: end.offset },
};
}
return null;
};
const parseAtRule = (filePath, rule, dependencies, mainFields) => {
const specifier = findAtRuleSpecifier(rule);
if (specifier && !(0, isExternalUrl_1.isExternalUrl)(specifier.specifier)) {
const specifierFilePath = (0, resolvePackage_1.resolvePackage)({
directory: path_1.posix.dirname(filePath),
moduleSpecifier: specifier.specifier,
extensions: supportedExtensions,
mainFields,
});
const dependency = {
...specifier,
filePath: specifierFilePath,
fileExtension: (0, getFileExtension_1.getFileExtension)(specifierFilePath),
};
dependencies.add(dependency);
}
};
const parseUrl = (filePath, url, dependencies, mainFields) => {
const specifier = findUrlSpecifier(url);
if (specifier && !(0, isExternalUrl_1.isExternalUrl)(specifier.specifier)) {
const specifierFilePath = (0, resolvePackage_1.resolvePackage)({
directory: path_1.posix.dirname(filePath),
moduleSpecifier: specifier.specifier,
extensions: supportedExtensions,
mainFields,
});
const dependency = {
...specifier,
filePath: specifierFilePath,
fileExtension: (0, getFileExtension_1.getFileExtension)(specifierFilePath),
};
dependencies.add(dependency);
}
};
const findUrlSpecifier = (url) => {
const specifierNode = url.value;
if (specifierNode.type === 'String') {
const { start, end } = specifierNode.loc;
return {
specifier: specifierNode.value.slice(1, -1),
position: { start: start.offset + 1, end: end.offset - 1 },
};
}
if (specifierNode.type === 'Raw') {
const { start, end } = specifierNode.loc;
return {
specifier: specifierNode.value,
position: { start: start.offset, end: end.offset },
};
}
return null;
};
//# sourceMappingURL=css.js.map