Files
RSSHub/plugins/rollup-plugin-art-templates.ts
github-actions[bot] a28890a135 style: auto format
2025-11-27 02:55:46 +00:00

85 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// rollup-plugin-art-templates.js
import { createHash } from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import MagicString from 'magic-string';
/**
* @param {object} [opts]
* @param {string} [opts.outputDir='templates'] Subfolder inside your Rollup output where the
* cloned templates will live (e.g. dist/templates)
*/
export default function artTemplatesPlugin(opts = {}) {
const templatesDir = opts.outputDir || 'templates';
/** Map<absoluteSourcePath, { newName, fileName, referenceId }> */
const emitted = new Map();
return {
name: 'art-template-assets',
/**
* Scan every JS/TS file for `path.join(...'.art'...)`
* and rewrite it on the fly.
*/
transform(code, id) {
// Skip dependencies
if (id.includes('node_modules')) {
return null;
}
// Quick precheck bail fast for files with no “.art”
if (!code.includes('.art')) {
return null;
}
const callRe = /path\.(join|resolve)\s*\(([^)]+)\)/g; // whole call
const strRe = /['"]([^'"]+\.art)['"]/g; // individual string literals
let match,
mString = null;
while ((match = callRe.exec(code))) {
const callSrc = match[0];
// Extract the **last** '.art' string literal in this call
let strMatch,
relPath = null;
while ((strMatch = strRe.exec(callSrc))) {
relPath = strMatch[1];
}
if (!relPath) {
continue;
} // nothing to do
// Resolve & hash the template file
const absPath = path.resolve(path.dirname(id), relPath);
const buf = fs.readFileSync(absPath);
const hash = createHash('sha256').update(buf).digest('hex').slice(0, 8);
const newName = `${path.basename(relPath, '.art')}-${hash}.art`;
const fileName = `${templatesDir}/${newName}`;
// Emit only once per unique file
if (!emitted.has(absPath)) {
const refId = this.emitFile({ type: 'asset', name: newName, fileName, source: buf });
emitted.set(absPath, { newName, fileName, refId });
}
// Replace the original string inside the call
const replacedCall = callSrc.replaceAll(strRe, `'${templatesDir}/${newName}'`);
mString ||= new MagicString(code);
mString.overwrite(match.index, match.index + callSrc.length, replacedCall);
}
if (mString) {
return {
code: mString.toString(),
map: mString.generateMap({ hires: true }),
};
}
return null; // untouched
},
};
}