@threeify/shader-transpiler
Version:
A glsl to JS module transpiler.
158 lines • 6.28 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import process, { exit } from 'node:process';
import { program } from 'commander';
import glob from 'glob';
import watch from 'watch';
import { Options } from './Options.js';
import { glslToJavaScriptTranspiler } from './transpiler.js';
function commaSeparatedList(value) {
return value.split(',');
}
const packageJson = JSON.parse(fs.readFileSync('./package.json').toString());
program
.name('@threeify/shader-transpiler')
.version(packageJson.version)
.option('-p, --projectDir <dirpath>', `the root of the project directory tree`)
.option('-r, --rootDir <dirpath>', `the root of the source directory tree`)
.option('-i', '--includeDirs <dirpaths>', 'a series of comma separated include directories')
.option('-o, --outDir <dirpath>', `the root of the output directory tree`)
.option('-w, --watch', `watch and incremental transpile any changed files`)
.option('-j, --allowJSIncludes', `allow referencing javascript and typescript code via includes`)
.option('-m, --minify', `reduce the size of the glsl code`)
.option('-e, --extensions <items>', 'comma separated list of extensions to transpile', commaSeparatedList)
.option('-v, --verboseLevel <level>', `higher numbers means more output`, Number.parseInt);
program.parse(process.argv);
const options = new Options();
let projectDir = process.cwd();
const programOptions = program.opts();
if (programOptions.projectDir) {
projectDir = programOptions.projectDir;
}
const tsConfigFilePath = path.join(projectDir, 'tsconfig.json');
if (fs.existsSync(tsConfigFilePath)) {
const tsConfig = JSON.parse(fs.readFileSync(tsConfigFilePath).toString());
if (tsConfig.compilerOptions) {
if (options.verboseLevel >= 1) {
console.log(` inferring setup from ${tsConfigFilePath}.`);
}
options.safeCopy({
rootDir: tsConfig.compilerOptions.rootDir,
outDir: tsConfig.compilerOptions.outDir
});
}
}
const threeifyFilePath = path.join(projectDir, 'threeify.json');
if (fs.existsSync(threeifyFilePath)) {
const threeifyConfig = JSON.parse(fs.readFileSync(threeifyFilePath).toString());
if (options.verboseLevel >= 1) {
console.log(` reading settings from ${threeifyFilePath}.`);
}
if (threeifyConfig.glsl) {
options.safeCopy(threeifyConfig.glsl);
}
}
if (options.verboseLevel >= 1) {
console.log(` applying command line overrides.`);
}
options.safeCopy(program);
if (options.verboseLevel >= 2) {
console.log(options);
}
options.extensions = options.extensions.map((ext) => ext.toLowerCase());
if (!options.rootDir) {
console.error(`no rootDir specified`);
exit(0);
}
if (!options.outDir) {
console.error(`no outDir specified`);
exit(0);
}
options.rootDir = path.normalize(path.join(projectDir, options.rootDir));
if (!fs.existsSync(options.rootDir)) {
console.error(`rootDir doesn't exist: ${options.rootDir}`);
exit(0);
}
options.outDir = path.normalize(path.join(projectDir, options.outDir));
options.includeDirs = options.includeDirs.map((includeDir) => path.normalize(path.join(projectDir, includeDir)));
if (options.verboseLevel >= 2) {
console.log(options);
}
let numFiles = 0;
let numErrors = 0;
function inputFileNameToOutputFileName(inputFileName) {
inputFileName = path.normalize(inputFileName);
const outputFileName = inputFileName.replace(options.rootDir, options.outDir) + '.js';
return outputFileName;
}
function transpile(sourceFileName) {
if (!fs.lstatSync(sourceFileName).isFile()) {
return [];
}
sourceFileName = path.normalize(sourceFileName);
const outputFileName = inputFileNameToOutputFileName(sourceFileName);
const fileErrors = glslToJavaScriptTranspiler(sourceFileName, outputFileName, options);
if (fileErrors.length > 0) {
numErrors++;
console.error(` ${sourceFileName} --> ${path.basename(outputFileName)}: ${fileErrors.length} Errors.`);
fileErrors.forEach((error) => {
console.error(` ${error}`);
});
}
else {
if (options.verboseLevel >= 1) {
console.log(` ${sourceFileName} --> ${path.basename(outputFileName)}`);
}
}
return fileErrors;
}
function isFileSupported(fileName) {
let ext = path.extname(fileName);
if (ext.length > 1) {
ext = ext.slice(1);
}
const result = options.extensions.includes(ext.toLowerCase());
return result;
}
const extGlob = options.extensions.join('|');
const globRegex = `${options.rootDir}/**/*.+(${extGlob})`;
glob(globRegex, {}, function (er, sourceFileNames) {
sourceFileNames.forEach((inputFileName) => {
numFiles++;
transpile(inputFileName);
});
if (numErrors > 0) {
console.error(`${numErrors} files failed to transpile.`);
}
console.log(`${numFiles - numErrors} files transpile successfully.`);
if (programOptions.watch) {
watch.createMonitor(options.rootDir, function (monitor) {
monitor.on('created', function (sourceFileName, stat) {
if (options.verboseLevel > 1)
console.log(`created ${sourceFileName}`);
if (isFileSupported(sourceFileName)) {
transpile(sourceFileName);
}
});
monitor.on('changed', function (sourceFileName, curr, prev) {
if (options.verboseLevel > 1)
console.log(`changed ${sourceFileName}`);
if (isFileSupported(sourceFileName)) {
transpile(sourceFileName);
}
});
monitor.on('removed', function (sourceFileName, stat) {
if (options.verboseLevel > 1)
console.log(`removed ${sourceFileName}`);
if (isFileSupported(sourceFileName)) {
const outputFileName = inputFileNameToOutputFileName(sourceFileName);
if (fs.existsSync(outputFileName)) {
fs.unlinkSync(outputFileName);
}
}
});
});
}
});
//# sourceMappingURL=index.js.map