@shockpkg/dir-projector
Version:
Package for creating Shockwave Director projectors
461 lines (421 loc) • 9.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProjectorOtto = void 0;
var _promises = require("node:fs/promises");
var _nodePath = require("node:path");
var _archiveFiles = require("@shockpkg/archive-files");
var _projector = require("../projector.js");
var _util = require("../util.js");
/**
* Include Xtra mapping.
*/
/**
* Include Xtra mapping, best match.
*/
/**
* Include Xtras.
*/
/**
* File patch.
*/
/**
* ProjectorOtto object.
*/
class ProjectorOtto extends _projector.Projector {
/**
* Make a Shockwave projector.
*/
shockwave = false;
/**
* Splash image data.
*/
splashImageData = null;
/**
* Splash image file.
*/
splashImageFile = null;
/**
* Lingo data.
*/
lingoData = null;
/**
* Lingo file.
*/
lingoFile = null;
/**
* Xtras include map.
*/
includeXtras = null;
/**
* Nest xtras in a Configuration directory.
*/
nestXtrasConfiguration = false;
/**
* Skeleton path.
*/
skeleton = null;
/**
* Config data.
*/
configData = null;
/**
* Config file.
*/
configFile = null;
/**
* ProjectorOtto constructor.
*
* @param path Output path.
*/
constructor(path) {
super(path);
}
/**
* Config file extension.
*
* @returns File extension.
*/
get configExtension() {
return '.INI';
}
/**
* Lingo file name.
*
* @returns File name.
*/
get lingoName() {
return 'LINGO.INI';
}
/**
* Xtras directory name.
*
* @returns Directory encoding.
*/
get xtrasName() {
return 'xtras';
}
/**
* Configuration directory name.
*
* @returns Directory encoding.
*/
get configurationName() {
return 'Configuration';
}
/**
* Name of a projector trimming the extension, case insensitive.
*
* @returns Projector name without extension.
*/
get name() {
return (0, _util.trimExtension)((0, _nodePath.dirname)(this.path), this.extension, true);
}
/**
* Config file path.
*
* @returns Config path.
*/
get configPath() {
const base = (0, _util.trimExtension)(this.path, this.extension, true);
return `${base}${this.configExtension}`;
}
/**
* Splash image file path.
*
* @returns Splash image path.
*/
get splashImagePath() {
const base = (0, _util.trimExtension)(this.path, this.extension, true);
return `${base}${this.splashImageExtension}`;
}
/**
* Lingo file path.
*
* @returns Lingo file path.
*/
get lingoPath() {
return (0, _nodePath.join)((0, _nodePath.dirname)(this.path), this.lingoName);
}
/**
* Get outout Xtras path.
*
* @returns Output path.
*/
get xtrasPath() {
const cn = this.configurationName;
return this.nestXtrasConfiguration && cn ? (0, _nodePath.join)((0, _nodePath.dirname)(this.path), cn, this.xtrasName) : (0, _nodePath.join)((0, _nodePath.dirname)(this.path), this.xtrasName);
}
/**
* Get config file data.
*
* @returns Config data or null.
*/
async getConfigData() {
const {
configData,
configFile
} = this;
if (configData) {
switch (typeof configData) {
case 'function':
{
const d = await configData();
if (typeof d === 'string') {
return new TextEncoder().encode(d);
}
if (Array.isArray(d)) {
return new TextEncoder().encode(d.join(this.configNewline));
}
return d;
}
case 'string':
{
return new TextEncoder().encode(configData);
}
default:
{
// Fall through.
}
}
if (Array.isArray(configData)) {
return new TextEncoder().encode(configData.join(this.configNewline));
}
return configData;
}
if (configFile) {
const d = await (0, _promises.readFile)(configFile);
return new Uint8Array(d.buffer, d.byteOffset, d.byteLength);
}
return null;
}
/**
* Get splash image data if any specified, from data or file.
*
* @returns Splash image data or null.
*/
async getSplashImageData() {
const {
splashImageData,
splashImageFile
} = this;
if (splashImageData) {
return typeof splashImageData === 'function' ? splashImageData() : splashImageData;
}
if (splashImageFile) {
const d = await (0, _promises.readFile)(splashImageFile);
return new Uint8Array(d.buffer, d.byteOffset, d.byteLength);
}
return null;
}
/**
* Get lingo data if any specified, from data or file.
*
* @returns Lingo data or null.
*/
async getLingoData() {
const {
lingoData,
lingoFile
} = this;
if (lingoData) {
switch (typeof lingoData) {
case 'function':
{
const d = await lingoData();
if (typeof d === 'string') {
return new TextEncoder().encode(d);
}
if (Array.isArray(d)) {
return new TextEncoder().encode(d.join(this.lingoNewline));
}
return d;
}
case 'string':
{
return new TextEncoder().encode(lingoData);
}
default:
{
// Fall through.
}
}
if (Array.isArray(lingoData)) {
return new TextEncoder().encode(lingoData.join(this.lingoNewline));
}
return lingoData;
}
if (lingoFile) {
const d = await (0, _promises.readFile)(lingoFile);
return new Uint8Array(d.buffer, d.byteOffset, d.byteLength);
}
return null;
}
/**
* Get include Xtras as a list of mappings.
*
* @returns Mappings list.
*/
getIncludeXtrasMappings() {
const {
includeXtras
} = this;
const r = [];
if (includeXtras) {
for (const src of Object.keys(includeXtras)) {
const dest = includeXtras[src];
r.push({
src,
dest
});
}
}
return r;
}
/**
* Find the best match for a path in a list of Xtras mappings.
* Path search is case-insensitive.
*
* @param mappings Mappings list.
* @param path Path to search for.
* @returns Best match or null.
*/
findIncludeXtrasMappingsBestMatch(mappings, path) {
let best = null;
let bestScore = -1;
for (const map of mappings) {
const {
src
} = map;
const relative = src === '' ? path : (0, _util.pathRelativeBase)(path, src, true);
if (relative === null || bestScore >= src.length) {
continue;
}
best = {
map,
relative
};
bestScore = src.length;
}
return best;
}
/**
* Find output path for an Xtra.
*
* @param mappings Mappings list.
* @param path Path to search for.
* @returns Output path or null.
*/
includeXtrasMappingsDest(mappings, path) {
const best = this.findIncludeXtrasMappingsBestMatch(mappings, path);
if (!best) {
return null;
}
const {
map,
relative
} = best;
const base = map.dest || map.src;
// eslint-disable-next-line no-nested-ternary
return base ? relative ? `${base}/${relative}` : base : relative;
}
/**
* @inheritdoc
*/
async write() {
const {
skeleton
} = this;
if (!skeleton) {
throw new Error('No projector skeleton configured');
}
await this._checkOutput();
await this._writeSkeleton(skeleton);
await this._writeConfig();
await this._writeSplashImage();
await this._writeLingo();
}
/**
* Check that output path is valid, else throws.
*/
async _checkOutput() {
await Promise.all([this.path, this.configPath, this.splashImagePath, this.lingoPath].map(async p => {
if (await (0, _archiveFiles.fsLstatExists)(p)) {
throw new Error(`Output path already exists: ${p}`);
}
}));
}
/**
* Write out the projector config file.
*/
async _writeConfig() {
const data = await this.getConfigData();
if (data) {
const {
configPath
} = this;
await (0, _promises.mkdir)((0, _nodePath.dirname)(configPath), {
recursive: true
});
await (0, _promises.writeFile)(configPath, data);
}
}
/**
* Write out the projector splash image file.
*/
async _writeSplashImage() {
const data = await this.getSplashImageData();
if (data) {
const {
splashImagePath
} = this;
await (0, _promises.mkdir)((0, _nodePath.dirname)(splashImagePath), {
recursive: true
});
await (0, _promises.writeFile)(splashImagePath, data);
}
}
/**
* Write out the projector lingo file.
*/
async _writeLingo() {
const data = await this.getLingoData();
if (data) {
const {
lingoPath
} = this;
await (0, _promises.mkdir)((0, _nodePath.dirname)(lingoPath), {
recursive: true
});
await (0, _promises.writeFile)(lingoPath, data);
}
}
/**
* Projector file extension.
*
* @returns File extension.
*/
/**
* Splash image file extension.
*
* @returns File extension.
*/
/**
* Config file newline characters.
*
* @returns Newline characters.
*/
/**
* Lingo file newline characters.
*
* @returns Newline characters.
*/
/**
* Write the projector skeleton.
*
* @param skeleton Skeleton path.
*/
}
exports.ProjectorOtto = ProjectorOtto;
//# sourceMappingURL=otto.js.map