I might be stupid.

This commit is contained in:
flash 2024-06-09 20:13:03 +00:00
parent 72230e07b0
commit d0b9400212
11 changed files with 160 additions and 170 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "@flashwave/assproc", "name": "@flashwave/assproc",
"version": "0.2.0", "version": "0.3.0",
"description": "Personal frontend asset processing tool", "description": "Personal frontend asset processing tool",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View file

@ -1,92 +1,88 @@
import fs from 'fs'; const fs = require('fs');
import readline from 'readline'; const readline = require('readline');
import { join as pathJoin } from 'path'; const { join: pathJoin } = require('path');
import { trim, trimStart, trimEnd } from './trim.js'; const { trim, trimStart, trimEnd } = require('./trim.js');
const combine = { exports.folder = async (root, options) => {
folder: async (root, options) => { const macroPrefix = options.prefix || '#';
const macroPrefix = options.prefix || '#'; const entryPoint = options.entry || '';
const entryPoint = options.entry || '';
root = fs.realpathSync(root); root = fs.realpathSync(root);
const included = []; const included = [];
const processFile = async fileName => { const processFile = async fileName => {
const fullPath = pathJoin(root, fileName); const fullPath = pathJoin(root, fileName);
if(included.includes(fullPath)) if(included.includes(fullPath))
return ''; return '';
included.push(fullPath); included.push(fullPath);
if(!fullPath.startsWith(root)) if(!fullPath.startsWith(root))
throw `INVALID INCLUDED PATH: ${fullPath}`; throw `INVALID INCLUDED PATH: ${fullPath}`;
if(!fs.existsSync(fullPath)) if(!fs.existsSync(fullPath))
throw `INCLUDED FILE NOT FOUND: ${fullPath}`; throw `INCLUDED FILE NOT FOUND: ${fullPath}`;
const lines = readline.createInterface({ const lines = readline.createInterface({
input: fs.createReadStream(fullPath), input: fs.createReadStream(fullPath),
crlfDelay: Infinity, crlfDelay: Infinity,
}); });
let output = ''; let output = '';
let lastWasEmpty = false; let lastWasEmpty = false;
if(options.showPath) if(options.showPath)
output += "/* *** PATH: " + fullPath + " */\n"; output += "/* *** PATH: " + fullPath + " */\n";
for await(const line of lines) { for await(const line of lines) {
const lineTrimmed = trim(line); const lineTrimmed = trim(line);
if(lineTrimmed === '') if(lineTrimmed === '')
continue; continue;
if(line.startsWith(macroPrefix)) { if(line.startsWith(macroPrefix)) {
const args = lineTrimmed.split(' '); const args = lineTrimmed.split(' ');
const macro = trim(trimStart(args.shift(), macroPrefix)); const macro = trim(trimStart(args.shift(), macroPrefix));
switch(macro) { switch(macro) {
case 'comment': case 'comment':
break; break;
case 'include': { case 'include': {
const includePath = trimEnd(args.join(' '), ';'); const includePath = trimEnd(args.join(' '), ';');
output += trim(await processFile(includePath)); output += trim(await processFile(includePath));
output += "\n"; output += "\n";
break; break;
}
case 'vars':
if(typeof options.vars !== 'object' || options.vars === null)
break;
const bvSourceName = trimEnd(args.join(' '), ';');
const bvSource = options.vars[bvSourceName];
if(typeof bvSource !== 'objects' || bvSource === null)
throw `INVALID VARS SOURCE: ${bvSourceName}`;
const bvProps = [];
for(const bvName in bvSource)
bvProps.push(`${bvName}: { value: ${JSON.stringify(bvSource[bvName])} }`);
if(Object.keys(bvProps).length > 0)
output += `Object.defineProperties(${options.varsTarget}, { ${bvProps.join(', ')} });\n`;
break;
default:
output += line;
output += "\n";
break;
} }
} else {
output += line; case 'vars':
output += "\n"; if(typeof options.vars !== 'object' || options.vars === null)
break;
const bvSourceName = trimEnd(args.join(' '), ';');
const bvSource = options.vars[bvSourceName];
if(typeof bvSource !== 'objects' || bvSource === null)
throw `INVALID VARS SOURCE: ${bvSourceName}`;
const bvProps = [];
for(const bvName in bvSource)
bvProps.push(`${bvName}: { value: ${JSON.stringify(bvSource[bvName])} }`);
if(Object.keys(bvProps).length > 0)
output += `Object.defineProperties(${options.varsTarget}, { ${bvProps.join(', ')} });\n`;
break;
default:
output += line;
output += "\n";
break;
} }
} else {
output += line;
output += "\n";
} }
}
return output; return output;
}; };
return await processFile(entryPoint); return await processFile(entryPoint);
},
}; };
export combine;

View file

@ -1,9 +1,9 @@
import postcss from 'postcss'; const postcss = require('postcss');
import combine from '../combine.js'; const combine = require('../combine.js');
import { join as pathJoin } from 'path'; const { join: pathJoin, dirname } = require('path');
import { strtr, shortHash, writeFile } from './utils.js'; const { strtr, shortHash, writeFile } = require('../utils.js');
export const function(env) { exports = function(env) {
const PREFIX = '@'; const PREFIX = '@';
const DEFAULT_ENTRY = 'main.css'; const DEFAULT_ENTRY = 'main.css';

View file

@ -1,8 +1,8 @@
import { minify as htmlminify } from 'html-minifier-terser'; const { minify: htmlminify } = require('html-minifier-terser');
import { join as pathJoin, dirname } from 'path'; const { join: pathJoin, dirname } = require('path');
import { strtr, shortHash, writeFile } from './utils.js'; const { strtr, shortHash, writeFile } = require('../utils.js');
export const function(env) { exports = function(env) {
const MINIFY_OPTS = { const MINIFY_OPTS = {
collapseBooleanAttributes: true, collapseBooleanAttributes: true,
collapseWhitespace: true, collapseWhitespace: true,

View file

@ -1,9 +1,10 @@
import swc from '@swc/core'; const swc = require('@swc/core');
import combine from '../combine.js'; const combine = require('../combine.js');
import { join as pathJoin } from 'path'; const { minify: htmlminify } = require('html-minifier-terser');
import { strtr, shortHash, writeFile } from './utils.js'; const { join: pathJoin, } = require('path');
const { strtr, shortHash, writeFile } = require('../utils.js');
export const function(env) { exports = function(env) {
const PREFIX = '#'; const PREFIX = '#';
const DEFAULT_ENTRY = 'main.js'; const DEFAULT_ENTRY = 'main.js';
const DEFAULT_VARS_TARGET = 'window'; const DEFAULT_VARS_TARGET = 'window';

View file

@ -1,12 +1,9 @@
import { exec as execLie } from 'child_process'; const exec = require('util').promisify(require('child_process').exec);
import { promisify } from 'util'; const { minify: htmlminify } = require('html-minifier-terser');
import { minify as htmlminify } from 'html-minifier-terser'; const { join: pathJoin, dirname } = require('path');
import { join as pathJoin, dirname } from 'path'; const { strtr, shortHash, writeFile } = require('../utils.js');
import { strtr, shortHash } from './utils.js';
export const function(env) {
const exec = promisify(execLie);
exports = function(env) {
const MINIFY_OPTS = { const MINIFY_OPTS = {
collapseBooleanAttributes: true, collapseBooleanAttributes: true,
collapseWhitespace: true, collapseWhitespace: true,

View file

@ -1,8 +1,8 @@
import fs from 'fs'; const fs = require('fs');
import { join as pathJoin, dirname } from 'path'; const { join: pathJoin, dirname } = require('path');
import { strtr, shortHash, writeFile } from './utils.js'; const { strtr, shortHash, writeFile } = require('../utils.js');
export const function(env) { exports = function(env) {
return { return {
process: async (task, vars) => { process: async (task, vars) => {
let body = JSON.parse(fs.readFileSync(pathJoin(env.source, task.source))); let body = JSON.parse(fs.readFileSync(pathJoin(env.source, task.source)));

View file

@ -1,7 +1,7 @@
import fs from 'fs'; const fs = require('fs');
import { join as pathJoin } from 'path'; const { join: pathJoin } = require('path');
export const housekeep = path => { exports.housekeep = path => {
const files = fs.readdirSync(path).map(fileName => { const files = fs.readdirSync(path).map(fileName => {
const stats = fs.statSync(pathJoin(path, fileName)); const stats = fs.statSync(pathJoin(path, fileName));
return { return {

View file

@ -1,9 +1,9 @@
import apCss from './handlers/css.js'; const apCss = require('./handlers/css.js');
import apHtml from './handlers/html.js'; const apHtml = require('./handlers/html.js');
import apJs from './handlers/js.js'; const apJs = require('./handlers/js.js');
import apTwig from './handlers/twig.js'; const apTwig = require('./handlers/twig.js');
import apWebManifest from './handlers/webmanifest.js'; const apWebManifest = require('./handlers/webmanifest.js');
import { housekeep } from './housekeep.js'; const { housekeep } = require('./housekeep.js');
const DEFAULT_ENV = { const DEFAULT_ENV = {
debug: false, debug: false,
@ -23,74 +23,70 @@ const DEFAULT_ENV = {
}, },
}; };
const public = { exports.process = async (env, tasks) => {
process: async (env, tasks) => { if(typeof env.source !== 'string')
if(typeof env.source !== 'string') throw 'env.source must be a path to the source directories';
throw 'env.source must be a path to the source directories'; if(typeof env.public !== 'string')
if(typeof env.public !== 'string') throw 'env.public must be a path to the root output directory';
throw 'env.public must be a path to the root output directory';
if(typeof tasks !== 'object' || tasks === null) if(typeof tasks !== 'object' || tasks === null)
throw 'tasks must be a non-null object'; throw 'tasks must be a non-null object';
env = { ...DEFAULT_ENV, ...env }; env = { ...DEFAULT_ENV, ...env };
const types = { const types = {
js: new apJs(env), js: new apJs(env),
css: new apCss(env), css: new apCss(env),
webmanifest: new apWebManifest(env), webmanifest: new apWebManifest(env),
html: new apHtml(env), html: new apHtml(env),
twig: new apTwig(env), twig: new apTwig(env),
}; };
const order = env.order ?? Object.keys(types); const order = env.order ?? Object.keys(types);
if(!Array.isArray(order)) if(!Array.isArray(order))
throw 'env.order must be undefined or an array'; throw 'env.order must be undefined or an array';
const vars = env.vars ?? {}; const vars = env.vars ?? {};
if(typeof vars !== 'object' || vars === null) if(typeof vars !== 'object' || vars === null)
throw 'env.vars must be a non-null object'; throw 'env.vars must be a non-null object';
const files = {}; const files = {};
for(const type of order) { for(const type of order) {
if(!(type in types)) if(!(type in types))
throw `${type} is not a supported build task type`; throw `${type} is not a supported build task type`;
const typeTasks = tasks[type]; const typeTasks = tasks[type];
if(!Array.isArray(typeTasks)) if(!Array.isArray(typeTasks))
throw 'children of the tasks object must be arrays'; throw 'children of the tasks object must be arrays';
console.info(`Building '${type}' assets...`); console.info(`Building '${type}' assets...`);
const handler = types[type]; const handler = types[type];
for(const task of typeTasks) { for(const task of typeTasks) {
console.info(` => ${task.source}...`); console.info(` => ${task.source}...`);
const path = await handler.process(task, vars); const path = await handler.process(task, vars);
if(typeof task.varsName === 'string') if(typeof task.varsName === 'string')
vars[task.varsGroup ?? ''][task.varsName] = path; vars[task.varsGroup ?? ''][task.varsName] = path;
files[task.source] = path; files[task.source] = path;
}
} }
}
const hkDirs = env.housekeep ?? []; const hkDirs = env.housekeep ?? [];
if(!Array.isArray(hkDirs)) if(!Array.isArray(hkDirs))
throw 'env.housekeep must be an array of folder paths'; throw 'env.housekeep must be an array of folder paths';
if(hkDirs.length > 0) { if(hkDirs.length > 0) {
console.info(`Doing some housekeeping...`); console.info(`Doing some housekeeping...`);
for(const path of hkDirs) { for(const path of hkDirs) {
console.info(` => ${path}...`); console.info(` => ${path}...`);
housekeep(path); housekeep(path);
}
} }
}
return files; return files;
},
}; };
export public;

View file

@ -16,6 +16,6 @@ const trim = (str, chars = " \n\r\t\v\0", flags = 0) => {
return str; return str;
}; };
export const trimStart = (str, chars) => trim(str, chars, 0x01); exports.trimStart = (str, chars) => trim(str, chars, 0x01);
export const trimEnd = (str, chars) => trim(str, chars, 0x02); exports.trimEnd = (str, chars) => trim(str, chars, 0x02);
export const trim = (str, chars) => trim(str, chars, 0x03); exports.trim = (str, chars) => trim(str, chars, 0x03);

View file

@ -1,18 +1,18 @@
import crypto from 'crypto'; const crypto = require('crypto');
import fs from 'fs'; const fs = require('fs');
import { dirname } from 'path'; const { dirname } = require('path');
export const strtr = (str, replacements) => str.toString().replace( exports.strtr = (str, replacements) => str.toString().replace(
/{([^}]+)}/g, (match, key) => replacements[key] || match /{([^}]+)}/g, (match, key) => replacements[key] || match
); );
export const shortHash = text => { exports.shortHash = text => {
const hash = crypto.createHash('sha256'); const hash = crypto.createHash('sha256');
hash.update(text); hash.update(text);
return hash.digest('hex').substring(0, 8); return hash.digest('hex').substring(0, 8);
}; };
export const writeFile = (path, data) => { exports.writeFile = (path, data) => {
const folderPath = dirname(path); const folderPath = dirname(path);
if(!fs.existsSync(folderPath)) if(!fs.existsSync(folderPath))
fs.mkdirSync(folderPath, { recursive: true }); fs.mkdirSync(folderPath, { recursive: true });