@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
293 lines (292 loc) • 12.3 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const BehaviorManifestDefinition_1 = __importDefault(require("../minecraft/BehaviorManifestDefinition"));
const Database_1 = __importDefault(require("../minecraft/Database"));
const StorageUtilities_1 = __importDefault(require("../storage/StorageUtilities"));
const esbuild = __importStar(require("esbuild-wasm"));
const Status_1 = require("./Status");
const IProjectItemData_1 = require("./IProjectItemData");
const IFile_1 = require("../storage/IFile");
class ProjectBuild {
project;
mainScriptsFolder = undefined;
libs = null;
distScriptsFolder = undefined;
entry = undefined;
static isInitialized = false;
constructor(projectIn) {
this.project = projectIn;
this.loadFile = this.loadFile.bind(this);
}
isInErrorState;
errorMessages;
resolveFile(resolve) {
if (Database_1.default.minecraftModuleNames.includes(resolve.path)) {
return {
external: true,
namespace: "ct",
};
}
return {
path: resolve.path,
namespace: "ct",
};
}
_pushError(message) {
this.isInErrorState = true;
if (!this.errorMessages) {
this.errorMessages = [];
}
this.errorMessages.push({ message: message });
}
_getErrorResponse(id, message) {
this._pushError("Project Build:" + message);
return {
errors: [
{
id: id,
text: message,
},
],
};
}
getTypeDefContentFor(name, isTs) {
if (!this.libs) {
return this._getErrorResponse("esb-typenotfound", "Could not find typedef '" + name + "'");
}
for (const typeDef of this.libs.typeDefs) {
if (typeDef.name === name) {
return {
contents: typeDef.content.join("\n"),
loader: isTs ? "ts" : "js",
};
}
}
return this._getErrorResponse("esb-typenotfound", "Could not find typedef '" + name + "'");
}
get isBuildable() {
return this.project && this.project.projectFolder !== undefined;
}
getHasBuildableElements() {
for (const projectItem of this.project.items) {
if (projectItem.itemType === IProjectItemData_1.ProjectItemType.ts) {
return true;
}
}
return false;
}
async loadFile(build) {
if (!this.project ||
!this.project.projectFolder ||
!this.mainScriptsFolder ||
!this.distScriptsFolder ||
!this.libs) {
return this._getErrorResponse("esb-uninit", "Project does not have buildable elements.");
}
if (build.path === "@minecraft/vanilla-data") {
return this.getTypeDefContentFor("@minecraft/vanilla-data", true);
}
else if (build.path === "@minecraft/math") {
return this.getTypeDefContentFor("@minecraft/math", false);
}
let path = build.path;
if (path.startsWith("./")) {
path = path.substring(1);
}
const ext = StorageUtilities_1.default.getTypeFromName(path);
if (ext === "js") {
path = path.substring(0, path.length - 3) + ".ts";
}
else if (ext === "") {
path = path + ".ts";
}
if (!path.startsWith("/")) {
return this._getErrorResponse("esb-importnotfound", "Could not find import '" + path + "'");
}
let file = await this.mainScriptsFolder.ensureFileFromRelativePath(path);
// Use existing in-memory content if already loaded (it may have been modified by the editor)
// Only load from storage if not yet loaded
if (!file.isContentLoaded) {
await file.loadContent(true);
}
let content = file.content;
if (!content || typeof content !== "string") {
if (StorageUtilities_1.default.getTypeFromName(path) === "ts") {
path = path.substring(0, path.length - 3) + ".js";
file = await this.mainScriptsFolder.ensureFileFromRelativePath(path);
// Use existing in-memory content if available
if (!file.isContentLoaded) {
await file.loadContent(true);
}
content = file.content;
if (!content || typeof content !== "string") {
content = "";
}
}
else {
return this._getErrorResponse("esb-filenotfound", "Could not find file '" + build.path + "'");
}
}
return {
contents: content,
loader: "ts",
resolveDir: StorageUtilities_1.default.getFolderPath(build.path),
};
}
async build() {
if (!this.isBuildable) {
return;
}
if (!this.getHasBuildableElements()) {
return;
}
const operId = await this.project.creatorTools.notifyOperationStarted("Script building '" + this.project.name + "'");
const defaultBehaviorPack = await this.project.getDefaultBehaviorPack();
if (defaultBehaviorPack === undefined) {
return;
}
const behaviorPackDefinition = await defaultBehaviorPack.ensureManifest();
if (!behaviorPackDefinition || !(behaviorPackDefinition instanceof BehaviorManifestDefinition_1.default)) {
return;
}
const scriptModule = behaviorPackDefinition.getScriptModule();
const libScriptsFolder = this.project.getLibScriptsFolder();
this.mainScriptsFolder = await this.project.getMainScriptsFolder();
if (scriptModule && scriptModule.entry && libScriptsFolder) {
this.libs = await Database_1.default.getLibs();
this.distScriptsFolder = await this.project.ensureDistBuildScriptsFolder();
if (this.libs) {
this.entry = scriptModule.entry;
if (this.entry.toLowerCase().startsWith("scripts/")) {
this.entry = this.entry.substring(7);
}
if (!ProjectBuild.isInitialized) {
try {
// In Node.js, esbuild-wasm auto-locates its .wasm file from the
// package directory — no wasmURL needed. In browsers, wasmURL must
// point to the .wasm file served by the web server.
const isNodeJs = typeof process !== "undefined" && process.versions?.node;
if (isNodeJs) {
await esbuild.initialize({});
}
else {
await esbuild.initialize({
wasmURL: "./dist/esbuild-wasm/esbuild.wasm",
});
}
}
catch (e) {
this._pushError("Failed to initialize build system: " + e.toString());
await this.project.creatorTools?.notifyOperationEnded(operId, "Unable to continue script building '" + this.project.name + "'", Status_1.StatusTopic.scriptBuild, this.isInErrorState);
return;
}
ProjectBuild.isInitialized = true;
}
const me = this;
try {
const result = await esbuild.build({
bundle: true,
entryPoints: [this.entry],
format: "esm",
external: Database_1.default.minecraftModuleNames,
plugins: [
{
name: "ct",
setup(build) {
build.onResolve({ filter: /.*/ }, me.resolveFile);
build.onLoad({ filter: /.*/, namespace: "ct" }, me.loadFile);
},
},
],
});
if (result && result.outputFiles && result.outputFiles.length > 0) {
const mainJsFile = await this.distScriptsFolder.ensureFileFromRelativePath(this.entry);
mainJsFile.setContent(result.outputFiles[0].text, IFile_1.FileUpdateType.regularEdit);
await mainJsFile.saveContent();
}
}
catch (e) {
if (!this.isInErrorState && e) {
this._pushError(e.toString());
}
}
await me.project.creatorTools?.notifyOperationEnded(operId, "Completed script building '" + this.project.name + "'", Status_1.StatusTopic.scriptBuild, this.isInErrorState);
}
}
}
async aggregateScripts(scriptFolder) {
if (!scriptFolder.isLoaded) {
await scriptFolder.load();
}
let script = "";
for (const fileName in scriptFolder.files) {
const ext = StorageUtilities_1.default.getTypeFromName(fileName);
if (ext === "js") {
const scriptFile = scriptFolder.files[fileName];
if (scriptFile) {
if (!scriptFile.isContentLoaded) {
await scriptFile.loadContent();
}
if (scriptFile.content && typeof scriptFile.content === "string") {
script += "// " + fileName + "\n" + scriptFile.content + "\n";
}
}
}
}
for (const folderName in scriptFolder.folders) {
const childFolder = scriptFolder.folders[folderName];
if (childFolder) {
const fileScript = await this.aggregateScripts(childFolder);
script += fileScript;
}
}
return script;
}
async syncToBehaviorPack(bpTargetFolder) {
if (!this.getHasBuildableElements()) {
return;
}
const distScriptsFolder = await this.project.ensureDistBuildScriptsFolder();
const scriptsFolder = bpTargetFolder.ensureFolder("scripts");
await StorageUtilities_1.default.syncFolderTo(distScriptsFolder, scriptsFolder, true, true, false, []);
}
}
exports.default = ProjectBuild;