oxjs/rollup.config.js
2026-02-18 17:36:01 +01:00

188 lines
6.5 KiB
JavaScript

import resolve from '@rollup/plugin-node-resolve';
import terser from '@rollup/plugin-terser';
import copy from 'rollup-plugin-copy';
import fs from 'fs';
import path from 'path';
import { version } from './package.json';
function install(options = {}) {
const sourcePath = options.sourcePath || 'source/';
const devPath = options.devPath || 'dev/';
const minPath = options.minPath || 'min/';
// Helper: parse CSS with variable substitutions
function parseCss(css, values) {
return css.replace(/\$(\w+)(\[\d+\])?/g, (match, key, index) => {
let value = values[key];
if (index) {
const idx = parseInt(index.slice(1, -1));
value = value[idx];
}
if (typeof value === 'string') {
return value;
}
// Handle numeric arrays (e.g., RGB or RGBA)
if (Array.isArray(value[0])) {
// Already nested arrays
return value
.map(vals => `rgb${vals.length === 4 ? 'a' : ''}(${vals.join(', ')})`)
.join(', ');
} else {
// Single array
return `rgb${value.length === 4 ? 'a' : ''}(${value.join(', ')})`;
}
});
}
function readJsonc(filePath) {
const jsoncText = fs.readFileSync(filePath, 'utf-8');
let text = jsoncText.replace(/\/\/.*$/gm, ''); // Remove single-line comments
text = text.replace(/\/\*[\s\S]*?\*\//g, ''); // Remove multi-line comments
text = text.replace(/,\s*(?=[}\]])/g, ''); // Remove trailing commas in objects and arrays
return JSON.parse(text);
}
function writeFile(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, typeof data === 'string' ? data : data.toString('utf-8'));
return data.length;
}
function formatColor(rgb) {
return '#' + rgb.map(c => c.toString(16).padStart(2, '0').toUpperCase()).join('');
}
function writeBundle() {
const themesDir = path.join(sourcePath, 'UI', 'themes');
const themes = fs.readdirSync(themesDir).filter(name => !['.', '_'].includes(name[0]));
const themeData = {};
for (const theme of themes) {
const themeJsonPath = path.join(themesDir, theme, 'json', 'theme.jsonc');
themeData[theme] = readJsonc(themeJsonPath);
themeData[theme].themeClass = 'OxTheme' + theme[0].toUpperCase() + theme.slice(1);
}
const cssPath = path.join(sourcePath, 'UI', 'css', 'theme.css');
const css = fs.readFileSync(cssPath, 'utf-8')
for (const theme of themes) {
let themeCss = parseCss(css, themeData[theme]);
themeCss = themeCss.replace(/\.png\)/g, `.png?${version})`);
writeFile(path.join(devPath, 'UI', 'themes', theme, 'css', 'theme.css'), themeCss);
writeFile(path.join(minPath, 'UI', 'themes', theme, 'css', 'theme.css'), themeCss);
}
const uiImages = {}
const svgDir = path.join(sourcePath, 'UI', 'svg');
const svgs = fs.readdirSync(svgDir).filter(name => !['.', '_'].includes(name[0]));
for (const filename of svgs) {
const svgPath = path.join(svgDir, filename);
let svg = fs.readFileSync(svgPath, 'utf-8')
svg = svg.replace(/\n\s*/g, '');
svg = svg.replace(/<!--.+?-->/g, '');
uiImages[filename.slice(0, -4)] = svg
if (filename.startsWith('symbolLoading')) {
for (const theme of themes) {
let themeSVG = svg.replace(/#808080/g, formatColor(themeData[theme]['symbolDefaultColor']))
writeFile(path.join(devPath, 'UI', 'themes', theme, 'svg', filename), themeSVG);
writeFile(path.join(minPath, 'UI', 'themes', theme, 'svg', filename), themeSVG);
}
}
}
}
return {
name: 'theme-plugin',
writeBundle
};
}
// TBD: get version
// TBD: add ' OxJS %s (c) %s 0x2620, dual-licensed GPL/MIT, see https://oxjs.org for details ' % (version, year)
//
/*
// kind of inline now, but missing cache busting!
# Ox.UI CSS
css = read_text(source_path + 'UI/css/UI.css')
css = css.replace('$import', '\n'.join([
'@import url("../themes/%s/css/theme.css?%s");' % (theme, version) for theme in themes
]))
write_file('%sUI/css/UI.css' % dev_path, css)
write_file('%sUI/css/UI.css' % min_path, css)
# Ox.UI SVGs
ui_images = {}
path = source_path + 'UI/svg/'
for filename in [filename for filename in os.listdir(path) if not filename[0] in '._']:
svg = read_text(path + filename)
svg = re.sub(r'\n\s*', '', svg)
svg = re.sub(r'<!--.+?-->', '', svg)
# end fix
ui_images[filename[:-4]] = svg
if filename.startswith('symbolLoading'):
for theme in themes:
theme_svg = re.sub(r'#808080', format_hex(theme_data[theme]['symbolDefaultColor']), svg)
write_file('%sUI/themes/%s/svg/%s' % (dev_path, theme, filename), theme_svg)
write_file('%sUI/themes/%s/svg/%s' % (min_path, theme, filename), theme_svg)
write_file(min_path + 'UI/json/UI.json', json.dumps({
'files': sorted(ui_files['min']),
'images': ui_images
}, sort_keys=True))
js = re.sub(
r'Ox.LOCALES = \{\}',
'Ox.LOCALES = ' + json.dumps(locales, indent=4, sort_keys=True),
js
)
js = re.sub(
r"Ox.VERSION = '([\d\.]+)'",
"Ox.VERSION = '%s'" % version,
js
)
*/
export default {
input: {
'Ox': 'source/Ox/Ox.js',
'UI': 'source/UI/UI.js',
'Unicode': 'source/Unicode/Unicode.js',
'Geo': 'source/Geo/Geo.js',
'Image': 'source/Image/Image.js',
},
output: {
dir: 'min',
format: 'es',
entryFileNames: '[name]/[name].js',
chunkFileNames: '[name]/[name].js',
},
plugins: [
resolve(),
terser(),
copy({
targets: [
{ src: "source/Ox.js", dest: 'min/' },
{ src: "source/Ox/json/locale.*.json", dest: 'min/Ox/json' },
{ src: "source/UI/css/*.css", dest: 'min/UI/css' },
{ src: "source/UI/json/locale.*.json", dest: 'min/UI/json' },
{ src: "source/UI/json/UI.json", dest: 'min/UI/json/' }, // FIXME: this one should be genreated first
{ src: "source/UI/png", dest: 'min/UI/' },
{ src: "source/UI/jquery/*.js", dest: 'min/UI/jquery' },
{ src: "source/UI/themes", dest: 'min/UI' },
{ src: "source/Unicode/json/*.json", dest: 'min/Unicode/json' },
{ src: "source/Geo/json/*.json", dest: 'min/Geo/json' },
{ src: "source/Geo/png/flags", dest: 'min/Geo/png/'}
],
hook: 'writeBundle'
}),
install()
]
};