@bscotch/stitch
Version:
Stitch: The GameMaker Studio 2 Asset Pipeline Development Kit.
159 lines • 6.27 kB
JavaScript
import { oneline } from '@bscotch/utility';
import { Yy } from '@bscotch/yy';
import { StitchError } from '../../utility/errors.js';
import { warn } from '../../utility/log.js';
import paths from '../../utility/paths.js';
export class Gms2IncludedFile {
storage;
data;
constructor(option, storage) {
this.storage = storage;
this.data = { ...option };
}
get name() {
return this.data.name;
}
/** The folder path name as seen in the IDE browser. */
get folder() {
return this.directoryRelative.replace(/^datafiles\//, '');
}
/** The directory containing this file, relative to project root */
get directoryRelative() {
return this.data.filePath;
}
get directoryAbsolute() {
return paths.join(this.storage.yypDirAbsolute, this.directoryRelative);
}
get filePathRelative() {
return paths.join(this.directoryRelative, this.name);
}
get filePathAbsolute() {
return paths.join(this.directoryAbsolute, this.name);
}
/** Get the file content */
get contentAsBuffer() {
return this.storage.readBlobSync(this.filePathAbsolute);
}
/**
* Set the file content on disk. If string or Buffer,
* just directly write. In all other cases, JSON stringify.
*/
setContent(data) {
if (typeof data == 'string' || Buffer.isBuffer(data)) {
this.storage.writeBlobSync(this.filePathAbsolute, data);
}
else {
this.storage.writeJsonSync(this.filePathAbsolute, data);
}
}
/** If the content is JSON, get it as a parsed Javascript structure (else throw) */
get contentParsedAsJson() {
return Yy.parse(this.contentAsString);
}
/** Get the file content as a string */
get contentAsString() {
return this.contentAsBuffer.toString();
}
/** The list of configurations that apply to this file in some way. */
get configNames() {
return Object.keys(this.data.ConfigValues || {});
}
/** The configuration overrides for this file */
get config() {
return this.data.ConfigValues;
}
set config(configuration) {
this.data.ConfigValues = configuration;
}
/**
* Replace this Included File's content with the content
* from another file (names don't need to match)
*/
replaceWithFileContent(sourceFile) {
this.storage.copyFileSync(sourceFile, this.filePathAbsolute);
}
toJSON() {
return { ...this.data };
}
static get defaultDataValues() {
return {
CopyToMask: -1n,
resourceType: 'GMIncludedFile',
resourceVersion: '1.0',
};
}
static importFromDirectory(project, path, subdirectory, allowedExtensions) {
if (!project.storage.isDirectorySync(path)) {
throw new StitchError(`${path} is not a directory`);
}
const filePaths = project.storage.listFilesSync(path, true, allowedExtensions);
const importedFiles = [];
for (const filePath of filePaths) {
// Use relative pathing to ensure that organization inside GMS2
// matches original folder heirarchy, but all inside whatever 'subdirectory' was provided
const filePathRelativeToStart = paths.relative(path, filePath);
const relativeSubdirectory = paths.join(subdirectory || 'NEW', paths.dirname(filePathRelativeToStart));
importedFiles.push(Gms2IncludedFile.importFromFile(project, filePath, relativeSubdirectory));
}
return importedFiles;
}
static importFromFile(project, path, subdirectory) {
const blob = project.storage.readBlobSync(path);
return Gms2IncludedFile.importFromData(project, path, blob, subdirectory);
}
static importFromData(project, path, content, subdirectory) {
if ([null, undefined].includes(content)) {
throw new StitchError(`IncludedFile import using data cannot have null/undefined as that data.`);
}
const fileName = paths.parse(path).base;
// (Ensure POSIX-style seps)
let directoryRelative = `datafiles`;
if (subdirectory) {
directoryRelative += `/${paths.asPosixPath(subdirectory)}`;
}
// See if something already exists with project name
const matchingFile = project.includedFiles.findByField('name', fileName);
if (matchingFile) {
// If the file is in the SAME PLACE, then just replace the file contents
// If it's in a different subdir, assume that something unintended is going on
matchingFile.setContent(content);
if (matchingFile.directoryRelative != directoryRelative) {
warn(oneline `
A file by name ${fileName} already exists in a different subdirectory.
Check to make sure that it is the file that you intended to change!
`);
}
return matchingFile;
}
else {
// This is a new file
// Create the Yyp data and add to the project
// Copy over the file
const newIncludedFile = project.includedFiles.addNew({
...Gms2IncludedFile.defaultDataValues,
name: fileName,
filePath: directoryRelative,
});
newIncludedFile.setContent(content);
project.save();
return newIncludedFile;
}
}
static import(project, path, content, subdirectory, allowedExtensions) {
if (![null, undefined].includes(content)) {
return [
Gms2IncludedFile.importFromData(project, path, content, subdirectory),
];
}
else if (!project.storage.existsSync(path)) {
throw new StitchError(`Path ${path} does not exist and no alternate content provided.`);
}
else if (project.storage.isDirectorySync(path)) {
return Gms2IncludedFile.importFromDirectory(project, path, subdirectory, allowedExtensions);
}
else {
return [Gms2IncludedFile.importFromFile(project, path, subdirectory)];
}
}
}
//# sourceMappingURL=Gms2IncludedFile.js.map