diff --git a/js/animations/animation.js b/js/animations/animation.js index eef553524..14bd3dc2f 100644 --- a/js/animations/animation.js +++ b/js/animations/animation.js @@ -2,7 +2,6 @@ import { Blockbench } from "../api"; import { Filesystem } from "../file_system"; import { openMolangEditor } from "./molang_editor"; import { clipboard, currentwindow, dialog, fs, ipcRenderer } from "../native_apis"; -import { invertMolang } from "../util/molang"; import { ScopeColors } from "../multi_file_editing"; export class AnimationItem { diff --git a/js/animations/timeline_animators.js b/js/animations/timeline_animators.js index 1f697d742..0be596108 100644 --- a/js/animations/timeline_animators.js +++ b/js/animations/timeline_animators.js @@ -195,7 +195,7 @@ GeneralAnimator.addChannel = function(channel, options) { max_data_points: options.max_data_points || 0, displayFrame: options.displayFrame } - ModelProject.all.forEach(project => { + Blockbench.ModelProject.all.forEach(project => { if (!project.animations) project.animations.forEach(animation => { animation.animators.forEach(animator => { diff --git a/js/api.ts b/js/api.ts index 9697e3697..0b4bf8233 100644 --- a/js/api.ts +++ b/js/api.ts @@ -1,11 +1,17 @@ import { FormElementOptions } from "./interface/form"; -import { ModelFormat } from "./io/format"; +import type { ModelFormat } from "./io/format"; import { Prop } from "./misc"; import { EventSystem } from "./util/event_system"; import VersionUtil from './util/version_util'; import { Filesystem } from "./file_system"; import { MessageBoxOptions } from "./interface/dialog"; import { currentwindow, electron, shell, SystemInfo } from "./native_apis"; +import type { SplineCurve, SplineHandle, SplineMesh } from "./outliner/types/spline_mesh"; +import type { BillboardFace } from "./outliner/types/billboard"; +import type { Keyframe } from "./animations/keyframe"; +import type { ModelProject } from "./io/project"; +import type { ModelLoader } from "./io/model_loader"; +import type { Plugin } from "./plugin_loader"; declare const appVersion: string; declare let Format: ModelFormat @@ -29,7 +35,7 @@ interface ToastNotificationOptions { */ color?: string /** - * Method to run on click. + * Method to run on click. * @returns Return `true` to close toast */ click?: (event: Event) => boolean @@ -39,33 +45,33 @@ export const LastVersion = localStorage.getItem('last_version') || localStorage. // @ts-ignore // const previous_data = window.Blockbench as {}; -export const Blockbench = { +export class Blockbench { //...previous_data, - isWeb: !isApp, - isMobile: (window.innerWidth <= 960 || window.innerHeight <= 500) && 'ontouchend' in document, - isLandscape: window.innerWidth > window.innerHeight, - isTouch: 'ontouchend' in document, - get isPWA() { + static isWeb = !isApp + static isMobile = (window.innerWidth <= 960 || window.innerHeight <= 500) && 'ontouchend' in document + static isLandscape = window.innerWidth > window.innerHeight + static isTouch = 'ontouchend' in document + static get isPWA() { return 'standalone' in navigator || window.matchMedia('(display-mode: standalone)').matches; - }, - version: appVersion, - operating_system: '', - platform: 'web', - flags: [], - drag_handlers: {}, - events: {}, - openTime: new Date(), - setup_successful: null as null | true, - argv: isApp ? electron.process?.argv?.slice() : null, + } + static version = appVersion + static operating_system = '' + static platform = 'web' + static flags = [] + static drag_handlers = {} + static events: Record = {} + static openTime = new Date() + static setup_successful: null | true = null + static argv = isApp ? electron.process?.argv?.slice() : null /** * @deprecated Use Undo.initEdit and Undo.finishEdit instead */ - edit(aspects: UndoAspects, cb: () => void) { + static edit(aspects: UndoAspects, cb: () => void) { Undo.initEdit(aspects) cb(); Undo.finishEdit('Edit') - }, - reload() { + } + static reload() { if (isApp) { Blockbench.setProgress(0) Blockbench.addFlag('allow_closing') @@ -74,18 +80,18 @@ export const Blockbench = { } else { location.reload() } - }, - isNewerThan(version: string): boolean { + } + static isNewerThan(version: string): boolean { return VersionUtil.compare(Blockbench.version, '>', version); - }, - isOlderThan(version: string): boolean { + } + static isOlderThan(version: string): boolean { return VersionUtil.compare(Blockbench.version, '<', version); - }, - registerEdit() { + } + static registerEdit() { console.warn('Blockbench.registerEdit is outdated. Please use Undo.initEdit and Undo.finishEdit') - }, + } //Interface - getIconNode(icon: IconString | boolean | HTMLElement | (() => (IconString | boolean | HTMLElement)), color?: string): HTMLElement { + static getIconNode(icon: IconString | boolean | HTMLElement | (() => (IconString | boolean | HTMLElement)), color?: string): HTMLElement { let node; if (typeof icon === 'function') { icon = icon() @@ -108,7 +114,7 @@ export const Blockbench = { //Node node = document.createElement('i'); node.classList.add('fa_big', 'icon'); - + } else if (icon.match(/^(fa[.-])|(fa[rsb]\.)/)) { //Font Awesome node = document.createElement('i'); @@ -151,8 +157,8 @@ export const Blockbench = { } } return node - }, - showQuickMessage(message, time = 1000) { + } + static showQuickMessage(message, time = 1000) { document.getElementById('quick_message_box')?.remove(); let quick_message_box = Interface.createElement('div', {id: 'quick_message_box'}, tl(message)); document.body.append(quick_message_box); @@ -160,9 +166,9 @@ export const Blockbench = { setTimeout(function() { quick_message_box.remove() }, time); - }, + } - showToastNotification(options: ToastNotificationOptions) { + static showToastNotification(options: ToastNotificationOptions) { let notification = document.createElement('li'); notification.className = 'toast_notification'; if (options.icon) { @@ -209,43 +215,43 @@ export const Blockbench = { } } return new deletableToast(notification); - }, - setCursorTooltip(text?: string): void {}, - setProgress(progress: number, time: number = 0, bar?: string): void {}, - showStatusMessage(message: string, time: number = 800) { + } + static setCursorTooltip(text?: string): void {} + static setProgress(progress: number, time: number = 0, bar?: string): void {} + static showStatusMessage(message: string, time: number = 800) { Blockbench.setStatusBarText(tl(message)) setTimeout(function() { Blockbench.setStatusBarText() }, time); - }, - setStatusBarText(text?: string) { + } + static setStatusBarText(text?: string) { if (text !== undefined) { Prop.file_name = text } else { Prop.file_name = Prop.file_name_alt||'' } - }, - showMessage(message, location) { + } + static showMessage(message, location) { if (location === 'status_bar') { Blockbench.showStatusMessage(message) } else if (location === 'center') { Blockbench.showQuickMessage(message) } - }, - showMessageBox(options: MessageBoxOptions, cb?: (button: number | string, result?: Record, event?: Event) => void) { + } + static showMessageBox(options: MessageBoxOptions, cb?: (button: number | string, result?: Record, event?: Event) => void) { return new MessageBox(options, cb).show(); - }, + } /** - * - * @param {*} title - * @param {*} value - * @param {*} callback + * + * @param {*} title + * @param {*} value + * @param {*} callback * @param {object} options Options * @param {string} options.info Info text * @param {string} options.description Description for the text input * @returns {Promise} Input value */ - async textPrompt(title: string, value: string, callback: (text: string) => void, options: {placeholder?: string, description?: string, info?: string} = {}) { + static async textPrompt(title: string, value: string, callback: (text: string) => void, options: {placeholder?: string, description?: string, info?: string} = {}) { if (typeof options == 'string') { options = {placeholder: options}; console.warn('textPrompt: 4th argument is expected to be an object'); @@ -274,25 +280,25 @@ export const Blockbench = { }).show(); }); return answer; - }, - addMenuEntry(name: string, icon: IconString, click) { + } + static addMenuEntry(name: string, icon: IconString, click) { console.warn('Blockbench.addMenuEntry is deprecated. Please use Actions instead.') let id = name.replace(/\s/g, '').toLowerCase(); var action = new Action(id, {icon: icon, name: name, click: click}) MenuBar.addAction(action, 'tools') - }, - removeMenuEntry(name: string) { + } + static removeMenuEntry(name: string) { let id = name.replace(/\s/g, '').toLowerCase(); MenuBar.removeAction('tools.'+id); - }, - openLink(link: string) { + } + static openLink(link: string) { if (isApp) { shell.openExternal(link) } else { window.open(link) } - }, - notification(title: string, text: string, icon?: string) { + } + static notification(title: string, text: string, icon?: string) { Notification.requestPermission().then(status => { if (status == 'granted') { let n = new Notification(title, {body: text, icon: icon||'favicon.png'}) @@ -306,9 +312,9 @@ export const Blockbench = { } } }) - }, + } //CSS - addCSS(css: string, layer: string = 'plugin'): Deletable { + static addCSS(css: string, layer: string = 'plugin'): Deletable { let style_node = document.createElement('style'); style_node.setAttribute('type', 'text/css'); if (layer != '') css = `@layer ${layer} {${css}}`; @@ -320,20 +326,20 @@ export const Blockbench = { } } return new deletableStyle(style_node); - }, + } //Flags - addFlag(flag: string): void { + static addFlag(flag: string): void { this.flags[flag] = true; - }, - removeFlag(flag: string): void { + } + static removeFlag(flag: string): void { delete this.flags[flag]; - }, - hasFlag(flag: string): boolean | undefined { + } + static hasFlag(flag: string): boolean | undefined { return this.flags[flag]; - }, + } //Events - dispatchEvent(event_name: T, data: D): any[] { - let list = this.events[event_name]; + static dispatchEvent(event_name: T, data: D): any[] { + let list = Blockbench.events[event_name]; let results: any[]; if (list) { results = []; @@ -348,44 +354,123 @@ export const Blockbench = { Validator.validate(event_name); } return results; - }, - on(event_name: T, cb: (data: D) => any): Deletable { + } + static on(event_name: T, cb: (data: D) => any): Deletable { return EventSystem.prototype.on.call(this, event_name, cb); - }, - once(event_name: T, cb: (data: D) => any): Deletable { + } + static once(event_name: T, cb: (data: D) => any): Deletable { return EventSystem.prototype.once.call(this, event_name, cb); - }, - addListener(event_name: T, cb: (data: D) => any): Deletable { + } + static addListener(event_name: T, cb: (data: D) => any): Deletable { return EventSystem.prototype.addListener.call(this, event_name, cb); - }, - removeListener(event_name: T, cb: (data: D) => any): void { + } + static removeListener(event_name: T, cb: (data: D) => any): void { return EventSystem.prototype.removeListener.call(this, event_name, cb); - }, + } // Update - onUpdateTo(version, callback) { + static onUpdateTo(version, callback) { if (LastVersion && VersionUtil.compare(version, '>', LastVersion) && !Blockbench.isOlderThan(version)) { callback(LastVersion); } - }, + } + // Globals - Format: 0 as (ModelFormat | number), - Project: 0 as (ModelProject | number), - get Undo() { - return Blockbench.Project instanceof ModelProject ? Blockbench.Project.undo : undefined; - }, + static Format: (ModelFormat | number) = 0 + static Project: (ModelProject | number) = 0 + static get Undo() { + return Blockbench.Project instanceof Blockbench.ModelProject ? Blockbench.Project.undo : undefined; + } // File System - import: Filesystem.importFile, - importFile: Filesystem.importFile, - pickDirectory: Filesystem.pickDirectory, - read: Filesystem.readFile, - readFile: Filesystem.readFile, - export: Filesystem.exportFile, - exportFile: Filesystem.exportFile, - writeFile: Filesystem.writeFile, - findFileFromContent: Filesystem.findFileFromContent, - addDragHandler: Filesystem.addDragHandler, - removeDragHandler: Filesystem.removeDragHandler, -}; + static import = Filesystem.importFile + static importFile = Filesystem.importFile + static pickDirectory = Filesystem.pickDirectory + static read = Filesystem.readFile + static readFile = Filesystem.readFile + static export = Filesystem.exportFile + static exportFile = Filesystem.exportFile + static writeFile = Filesystem.writeFile + static findFileFromContent = Filesystem.findFileFromContent + static addDragHandler = Filesystem.addDragHandler + static removeDragHandler = Filesystem.removeDragHandler + + static Outliner: typeof Outliner + static OutlinerNode: typeof OutlinerNode + static OutlinerElement: typeof OutlinerElement + static Group: typeof Group + static Cube: typeof Cube + static Mesh: typeof Mesh + static Locator: typeof Locator + static NullObject: typeof NullObject + static TextureMesh: typeof TextureMesh + static SplineMesh: typeof SplineMesh + + static Face: typeof Face + static CubeFace: typeof CubeFace + static MeshFace: typeof MeshFace + static BillboardFace: typeof BillboardFace + static SplineHandle: typeof SplineHandle + static SplineCurve: typeof SplineCurve + static NodePreviewController: typeof NodePreviewController + + static Animator: typeof Animator + static Timeline: typeof Timeline + static AnimationItem: typeof AnimationItem + static Animation: typeof _Animation + static AnimationController: typeof AnimationController + static AnimationControllerState: typeof AnimationControllerState + static Keyframe: typeof Keyframe + static KeyframeDataPoint: typeof KeyframeDataPoint + static BoneAnimator: typeof BoneAnimator + static NullObjectAnimator: typeof NullObjectAnimator + static EffectAnimator: typeof EffectAnimator + static TimelineMarker: typeof TimelineMarker + + static Panel: typeof Panel + static Mode: typeof Mode + static Dialog: typeof Dialog + static ShapelessDialog: typeof ShapelessDialog + static ToolConfig: typeof ToolConfig + static InputForm: typeof InputForm + static Setting: typeof Setting + static Plugin: typeof Plugin + static Preview: typeof Preview + static Toolbar: typeof Toolbar + + static Language: typeof Language + static Painter: typeof Painter + static Screencam: typeof Screencam + static Settings: typeof Settings + static TextureAnimator: typeof TextureAnimator + static Toolbox: typeof Toolbox + static BarItems: typeof BarItems + + static BarItem: typeof BarItem + static Action: typeof Action + static Tool: typeof Tool + static Toggle: typeof Toggle + static Widget: typeof Widget + static BarSelect: typeof BarSelect + static BarSlider: typeof BarSlider + static BarText: typeof BarText + static NumSlider: typeof NumSlider + static ColorPicker: typeof ColorPicker + static Keybind: typeof Keybind + static KeybindItem: typeof KeybindItem + static Menu: typeof Menu + static BarMenu: typeof BarMenu + static ResizeLine: typeof ResizeLine + + static ModelProject: typeof ModelProject + static ModelFormat: typeof ModelFormat + static ModelLoader: typeof ModelLoader + static Codec: typeof Codec + static DisplaySlot: typeof DisplaySlot + static Reusable: typeof Reusable + + static Texture: typeof Texture + static TextureLayer: typeof TextureLayer + static SharedActions: typeof SharedActions +} (function() { if (!LastVersion || LastVersion.replace(/.\d+$/, '') != appVersion.replace(/.\d+$/, '')) { @@ -411,12 +496,6 @@ if (isApp) { if (Blockbench.platform.includes('win32') === true) window.osfs = '\\'; } -declare global { - interface window { - Blockbench: typeof Blockbench - } -} - const global = { LastVersion, Blockbench, diff --git a/js/desktop.js b/js/desktop.js index 9220596d9..11a9415fc 100644 --- a/js/desktop.js +++ b/js/desktop.js @@ -115,7 +115,7 @@ export function loadOpenWithBlockbenchFile() { Interface.page_wrapper.classList.toggle('accept_detached_tab', value); }) ipcRenderer.on('close-detached-project', (event, uuid) => { - let tab = ModelProject.all.find(project => project.uuid == uuid && project.detached); + let tab = Blockbench.ModelProject.all.find(project => project.uuid == uuid && project.detached); if (tab) tab.close(true); }) if (electron.process.argv.length >= 2) { @@ -652,7 +652,7 @@ window.onbeforeunload = function (event) { } } catch (err) {} - } else if (ModelProject.all.find(project => !project.saved)) { + } else if (Blockbench.ModelProject.all.find(project => !project.saved)) { let ul = Interface.createElement('ul', {class: 'list unsaved_models_list'}); let dialog; @@ -667,7 +667,7 @@ window.onbeforeunload = function (event) { } } - ModelProject.all.forEach(project => { + Blockbench.ModelProject.all.forEach(project => { if (project.saved) return; let li = Interface.createElement('li', {class: 'unsaved_model'}, [ Blockbench.getIconNode(project.format?.icon), @@ -700,7 +700,7 @@ window.onbeforeunload = function (event) { cancel_on_click_outside: false, onButton: async (button) => { if (button == 0) { - for (let project of ModelProject.all.slice()) { + for (let project of Blockbench.ModelProject.all.slice()) { await saveProject(project); if (!project.saved) return; } @@ -726,7 +726,7 @@ window.onbeforeunload = function (event) { } async function closeBlockbenchWindow() { - for (let project of ModelProject.all.slice()) { + for (let project of Blockbench.ModelProject.all.slice()) { project.closeOnQuit(); } AutoBackup.removeAllBackups(); diff --git a/js/edit_sessions.js b/js/edit_sessions.js index 06d2ee506..9820ab3ba 100644 --- a/js/edit_sessions.js +++ b/js/edit_sessions.js @@ -137,7 +137,7 @@ export class EditSession { } else { this.host.close() } - ModelProject.all.forEach(project => { + Blockbench.ModelProject.all.forEach(project => { if (project.EditSession == this) { delete project.EditSession; } diff --git a/js/formats/bbmodel.js b/js/formats/bbmodel.js index 471617049..2b628fcfa 100644 --- a/js/formats/bbmodel.js +++ b/js/formats/bbmodel.js @@ -2,6 +2,7 @@ import { invertMolang } from '../util/molang'; import LZUTF8 from '../lib/lzutf8' import { fs } from '../native_apis'; import VersionUtil from '../util/version_util'; +import { ModelProject } from '../io/project'; const FORMATV = '5.0'; diff --git a/js/formats/bedrock/bedrock.js b/js/formats/bedrock/bedrock.js index 189f69851..2a98dcb3b 100644 --- a/js/formats/bedrock/bedrock.js +++ b/js/formats/bedrock/bedrock.js @@ -5,6 +5,8 @@ import VersionUtil from '../../util/version_util' import {animation_codec} from "./bedrock_animation" import "./animation_controller_codec" import { loadBedrockCollisionFromJSON } from "./bedrock_voxel_shape"; +import { ModelProject } from '../../io/project'; +import { ModelFormat } from "../../io/format"; if (isApp) { window.BedrockEntityManager = class BedrockEntityManager { diff --git a/js/formats/bedrock/bedrock_animation.js b/js/formats/bedrock/bedrock_animation.js index 1f7d76839..ce26846c6 100644 --- a/js/formats/bedrock/bedrock_animation.js +++ b/js/formats/bedrock/bedrock_animation.js @@ -1,4 +1,5 @@ import { fs } from "../../native_apis" +import { invertMolang } from '../../util/molang' export const animation_codec = new AnimationCodec('bedrock', { diff --git a/js/formats/bedrock/bedrock_old.js b/js/formats/bedrock/bedrock_old.js index 1cec23b5d..a2fe8d5e4 100644 --- a/js/formats/bedrock/bedrock_old.js +++ b/js/formats/bedrock/bedrock_old.js @@ -1,4 +1,6 @@ import { currentwindow, dialog, electron, fs } from "../../native_apis"; +import { ModelProject } from '../../io/project'; +import { ModelFormat } from "../../io/format"; export function parseGeometry(data, args) { let geometry_name = data.name.replace(/^geometry\./, ''); diff --git a/js/formats/generic.ts b/js/formats/generic.ts index f92fe9222..6974fea25 100644 --- a/js/formats/generic.ts +++ b/js/formats/generic.ts @@ -1,3 +1,5 @@ +import { ModelFormat } from "../io/format"; + new ModelFormat('free', { icon: 'icon-format_free', category: 'general', diff --git a/js/formats/image.js b/js/formats/image.js index 2c60b875a..f24a48436 100644 --- a/js/formats/image.js +++ b/js/formats/image.js @@ -1,4 +1,5 @@ import { applyPalette, quantize } from "../util/gif"; +import { ModelFormat } from "../io/format"; let codec = new Codec('image', { name: tl('format.image'), diff --git a/js/formats/java/java_block.js b/js/formats/java/java_block.js index 43eb9ddcd..bc28e17a2 100644 --- a/js/formats/java/java_block.js +++ b/js/formats/java/java_block.js @@ -1,3 +1,5 @@ +import { ModelFormat } from "../../io/format"; + let item_parents = [ 'item/generated', 'minecraft:item/generated', 'item/handheld', 'minecraft:item/handheld', diff --git a/js/formats/java/modded_entity.js b/js/formats/java/modded_entity.js index 88d81227c..16e323931 100644 --- a/js/formats/java/modded_entity.js +++ b/js/formats/java/modded_entity.js @@ -1,4 +1,5 @@ import { fs } from "../../native_apis"; +import { ModelFormat } from "../../io/format"; function F(num) { var s = trimFloatNumber(num) + ''; diff --git a/js/formats/minecraft/skin.ts b/js/formats/minecraft/skin.ts index 8fa7e160e..654157a3d 100644 --- a/js/formats/minecraft/skin.ts +++ b/js/formats/minecraft/skin.ts @@ -8,6 +8,7 @@ import { TextureGenerator } from "../../texturing/texture_generator" import { Panel, Panels } from "../../interface/panels"; import { Blockbench } from "../../api"; import { FormResultValue } from "../../interface/form"; +import { ModelFormat } from "../../io/format"; type SkinPreset = { display_name: string @@ -193,7 +194,7 @@ export const codec = new Codec('skin_model', { } group.rotation[0] *= -1; group.rotation[1] *= -1; - + group.mirror_uv = b.mirror === true group.reset = b.reset === true group.skin_original_origin = group.origin.slice() as ArrayVector3; @@ -331,7 +332,7 @@ function loadPose(pose_data: SkinPoseData) { } let offset: ArrayVector3 = group.skin_original_origin.slice().V3_subtract(group.origin); offset.V3_add(bone_data.offset); - + group.extend({rotation: bone_data.rotation}); group.origin.V3_add(offset); let child_cubes = group.children.filter(c => c instanceof Cube); @@ -636,7 +637,7 @@ BARS.defineActions(function() { let textures = Texture.all.filter(tex => tex.selected || tex.multi_selected); if (!textures.length) textures = [Texture.getDefault()] if (!textures[0]) return; - + const arm_uv_positions: [number, number][] = [ [40, 16], [40, 32], @@ -703,7 +704,7 @@ BARS.defineActions(function() { Texture.all[0].save(true); } }) - + let explode_skin_model = new Toggle('explode_skin_model', { icon: () => 'open_in_full', category: 'edit', @@ -733,7 +734,7 @@ BARS.defineActions(function() { explode_skin_model.updateEnabledState(); }) - + new Action('custom_skin_poses', { icon: 'format_list_bulleted', category: 'view', @@ -765,7 +766,7 @@ BARS.defineActions(function() { } options.push(option); }) - + options.push( '_', 'add_custom_skin_pose' @@ -1661,7 +1662,7 @@ skin_presets.banner = { skin_presets.bat = { display_name: 'Bat', pose: true, - variants: { + variants: { new: { name: 'New', model: `{ diff --git a/js/formats/optifine/optifine_jem.js b/js/formats/optifine/optifine_jem.js index 984cc0828..49b8116c8 100644 --- a/js/formats/optifine/optifine_jem.js +++ b/js/formats/optifine/optifine_jem.js @@ -1,3 +1,5 @@ +import { ModelFormat } from "../../io/format"; + var codec = new Codec('optifine_entity', { name: 'OptiFine JEM', extension: 'jem', diff --git a/js/formats/optifine/optifine_jpm.js b/js/formats/optifine/optifine_jpm.js index 50305f384..8f0c8846b 100644 --- a/js/formats/optifine/optifine_jpm.js +++ b/js/formats/optifine/optifine_jpm.js @@ -1,3 +1,4 @@ +import { ModelFormat } from "../../io/format"; var part_codec = new Codec('optifine_part', { name: 'OptiFine Part', diff --git a/js/globals.js b/js/globals.js deleted file mode 100644 index 5c7cc81ea..000000000 --- a/js/globals.js +++ /dev/null @@ -1,78 +0,0 @@ -import { Blockbench } from "./api"; - -Blockbench.Outliner = Outliner; -Blockbench.OutlinerNode = OutlinerNode; -Blockbench.OutlinerElement = OutlinerElement; -Blockbench.Group = Group; -Blockbench.Cube = Cube; -Blockbench.Mesh = Mesh; -Blockbench.Locator = Locator; -Blockbench.NullObject = NullObject; -Blockbench.TextureMesh = TextureMesh; -Blockbench.SplineMesh = SplineMesh; - -Blockbench.Face = Face; -Blockbench.CubeFace = CubeFace; -Blockbench.MeshFace = MeshFace; -Blockbench.BillboardFace = BillboardFace; -Blockbench.SplineHandle = SplineHandle; -Blockbench.SplineCurve = SplineCurve; -Blockbench.NodePreviewController = NodePreviewController; - -Blockbench.Animator = Animator; -Blockbench.Timeline = Timeline; -Blockbench.AnimationItem = AnimationItem; -Blockbench.Animation = Animation; -Blockbench.AnimationController = AnimationController; -Blockbench.AnimationControllerState = AnimationControllerState; -Blockbench.Keyframe = Keyframe; -Blockbench.KeyframeDataPoint = KeyframeDataPoint; -Blockbench.BoneAnimator = BoneAnimator; -Blockbench.NullObjectAnimator = NullObjectAnimator; -Blockbench.EffectAnimator = EffectAnimator; -Blockbench.TimelineMarker = TimelineMarker; - -Blockbench.Panel = Panel; -Blockbench.Mode = Mode; -Blockbench.Dialog = Dialog; -Blockbench.ShapelessDialog = ShapelessDialog; -Blockbench.ToolConfig = ToolConfig; -Blockbench.InputForm = InputForm; -Blockbench.Setting = Setting; -Blockbench.Plugin = Plugin; -Blockbench.Preview = Preview; -Blockbench.Toolbar = Toolbar; - -Blockbench.Language = Language; -Blockbench.Painter = Painter; -Blockbench.Screencam = Screencam; -Blockbench.Settings = Settings; -Blockbench.TextureAnimator = TextureAnimator; -Blockbench.Toolbox = Toolbox; -Blockbench.BarItems = BarItems; - -Blockbench.BarItem = BarItem; -Blockbench.Action = Action; -Blockbench.Tool = Tool; -Blockbench.Toggle = Toggle; -Blockbench.Widget = Widget; -Blockbench.BarSelect = BarSelect; -Blockbench.BarSlider = BarSlider; -Blockbench.BarText = BarText; -Blockbench.NumSlider = NumSlider; -Blockbench.ColorPicker = ColorPicker; -Blockbench.Keybind = Keybind; -Blockbench.KeybindItem = KeybindItem; -Blockbench.Menu = Menu; -Blockbench.BarMenu = BarMenu; -Blockbench.ResizeLine = ResizeLine; - -Blockbench.ModelProject = ModelProject; -Blockbench.ModelFormat = ModelFormat; -Blockbench.Codec = Codec; -Blockbench.DisplaySlot = DisplaySlot; -Blockbench.Reusable = Reusable; - -Blockbench.Texture = Texture; -Blockbench.TextureLayer = TextureLayer; -Blockbench.SharedActions = SharedActions; diff --git a/js/globals.ts b/js/globals.ts new file mode 100644 index 000000000..11ed8497f --- /dev/null +++ b/js/globals.ts @@ -0,0 +1,87 @@ +import { Animation } from './animations/animation' +import { Keyframe } from './animations/keyframe' +import { Blockbench } from './api' +import { ModelFormat } from './io/format' +import { ModelLoader } from './io/model_loader' +import { ModelProject } from './io/project' +import { BillboardFace } from './outliner/types/billboard' +import { SplineCurve, SplineHandle, SplineMesh } from './outliner/types/spline_mesh' +import { Plugin } from './plugin_loader' + +Blockbench.Outliner = Outliner +Blockbench.OutlinerNode = OutlinerNode +Blockbench.OutlinerElement = OutlinerElement +Blockbench.Group = Group +Blockbench.Cube = Cube +Blockbench.Mesh = Mesh +Blockbench.Locator = Locator +Blockbench.NullObject = NullObject +Blockbench.TextureMesh = TextureMesh +Blockbench.SplineMesh = SplineMesh + +Blockbench.Face = Face +Blockbench.CubeFace = CubeFace +Blockbench.MeshFace = MeshFace +Blockbench.BillboardFace = BillboardFace +Blockbench.SplineHandle = SplineHandle +Blockbench.SplineCurve = SplineCurve +Blockbench.NodePreviewController = NodePreviewController + +Blockbench.Animator = Animator +Blockbench.Timeline = Timeline +Blockbench.AnimationItem = AnimationItem +Blockbench.Animation = Animation as unknown as typeof _Animation +Blockbench.AnimationController = AnimationController +Blockbench.AnimationControllerState = AnimationControllerState +Blockbench.Keyframe = Keyframe +Blockbench.KeyframeDataPoint = KeyframeDataPoint +Blockbench.BoneAnimator = BoneAnimator +Blockbench.NullObjectAnimator = NullObjectAnimator +Blockbench.EffectAnimator = EffectAnimator +Blockbench.TimelineMarker = TimelineMarker + +Blockbench.Panel = Panel +Blockbench.Mode = Mode +Blockbench.Dialog = Dialog +Blockbench.ShapelessDialog = ShapelessDialog +Blockbench.ToolConfig = ToolConfig +Blockbench.InputForm = InputForm +Blockbench.Setting = Setting +Blockbench.Plugin = Plugin +Blockbench.Preview = Preview +Blockbench.Toolbar = Toolbar + +Blockbench.Language = Language +Blockbench.Painter = Painter +Blockbench.Screencam = Screencam +Blockbench.Settings = Settings +Blockbench.TextureAnimator = TextureAnimator +Blockbench.Toolbox = Toolbox +Blockbench.BarItems = BarItems + +Blockbench.BarItem = BarItem +Blockbench.Action = Action +Blockbench.Tool = Tool +Blockbench.Toggle = Toggle +Blockbench.Widget = Widget +Blockbench.BarSelect = BarSelect +Blockbench.BarSlider = BarSlider +Blockbench.BarText = BarText +Blockbench.NumSlider = NumSlider +Blockbench.ColorPicker = ColorPicker +Blockbench.Keybind = Keybind +Blockbench.KeybindItem = KeybindItem +Blockbench.Menu = Menu +Blockbench.BarMenu = BarMenu +Blockbench.ResizeLine = ResizeLine + +Blockbench.ModelProject = ModelProject +Blockbench.ModelFormat = ModelFormat +Blockbench.ModelLoader = ModelLoader +Blockbench.Codec = Codec +Blockbench.DisplaySlot = DisplaySlot +Blockbench.Reusable = Reusable + +Blockbench.Texture = Texture +Blockbench.TextureLayer = TextureLayer +Blockbench.SharedActions = SharedActions diff --git a/js/interface/action_control.js b/js/interface/action_control.js index fdbdeaadc..8f7f1ad09 100644 --- a/js/interface/action_control.js +++ b/js/interface/action_control.js @@ -59,7 +59,7 @@ export const ActionControl = { }) } else if (action.type == 'project_tab') { - ModelProject.all.find(p => p.uuid == action.uuid).select(); + Blockbench.ModelProject.all.find(p => p.uuid == action.uuid).select(); } else if (action.type == 'profile') { let profile = SettingsProfile.all.find(p => p.uuid == action.uuid); @@ -276,7 +276,7 @@ BARS.defineActions(function() { } } if (type == 'tab') { - for (let project of ModelProject.all) { + for (let project of Blockbench.ModelProject.all) { if ( search_input.length == 0 || project.name.toLowerCase().includes(search_input) || diff --git a/js/interface/dialog.ts b/js/interface/dialog.ts index e420233a5..246477713 100644 --- a/js/interface/dialog.ts +++ b/js/interface/dialog.ts @@ -78,7 +78,7 @@ function buildLines(dialog: Dialog) { function buildComponent(dialog: Dialog) { let dialog_content = $(dialog.object).find('.dialog_content').get(0); let mount: HTMLElement; - // mount_directly, if enabled, skips one layer of wrapper. Class "dialog_content" must be added the the root element of the vue component. + // @ts-expect-error - Custom property: `mount_directly`. If enabled, skips one layer of wrapper. Class "dialog_content" must be added the the root element of the vue component. if (dialog.component.mount_directly) { mount = dialog_content; } else { @@ -300,7 +300,7 @@ export interface DialogOptions { /** * Vue component */ - component?: Vue.Component + component?: Vue.ComponentOptions /** * Order that the different interface types appear in the dialog. Default is 'form', 'lines', 'component'. */ @@ -359,7 +359,7 @@ export class Dialog { id: string title: string object: HTMLElement - content_vue: Vue | null + content_vue: Vue & Record | null progress_bar?: { /** * The current progress @@ -379,10 +379,10 @@ export class Dialog { confirmIndex: number cancelIndex: number - + lines?: DialogLineOptions[] form?: InputForm - component?: Vue.Component + component?: Vue.ComponentOptions part_order?: string[] form_first?: boolean sidebar?: DialogSidebar @@ -424,7 +424,7 @@ export class Dialog { } this.id = id; this.title = options.title; - + this.lines = options.lines; this.toolbars = options.toolbars this.form_config = options.form @@ -458,7 +458,7 @@ export class Dialog { this.confirmIndex = options.confirmIndex||0; this.cancelIndex = options.cancelIndex !== undefined ? options.cancelIndex : this.buttons.length-1; this.keyboard_actions = options.keyboard_actions || {}; - + this.onConfirm = options.onConfirm; this.onCancel = options.onCancel; this.onButton = options.onButton || options.onClose; @@ -466,7 +466,7 @@ export class Dialog { this.onOpen = options.onOpen; this.onBuild = options.onBuild; this.onResize = options.onResize; - + this.object; } /** @@ -528,7 +528,7 @@ export class Dialog { let handle = document.createElement('div'); handle.className = 'dialog_handle'; this.object.append(handle); - + if (this.title_menu) { let menu_button = document.createElement('div'); menu_button.className = 'dialog_menu_button'; @@ -554,7 +554,7 @@ export class Dialog { let content = document.createElement('content'); content.className = 'dialog_content'; this.object.append(wrapper); - + if (this.sidebar) { if (window.innerWidth < 920) { @@ -650,7 +650,7 @@ export class Dialog { let move = (e2: PointerEvent) => { convertTouchEvent(e2); - + if (this.resizable && this.resizable.includes('x')) { let x_offset = (e2.clientX - start_position[0]); this.width = original_width + x_offset * 2; @@ -711,7 +711,7 @@ export class Dialog { let jq_dialog = $(this.object); document.getElementById('dialog_wrapper').append(this.object); - + if (this instanceof ShapelessDialog === false) { this.object.style.display = 'flex'; this.object.style.top = limitNumber(window.innerHeight/2-this.object.clientHeight/2, 0, 100)+'px'; @@ -770,7 +770,7 @@ export class Dialog { Dialog.stack.remove(this); Prop.active_panel = Prop._previous_active_panel; $(this.object).detach(); - + if (Dialog.stack.length) { Dialog.stack.last().focus(); } @@ -824,7 +824,7 @@ interface ShapelessDialogOptions { /** * Vue component */ - component?: Vue.Component + component?: Vue.ComponentOptions /** * Unless set to false, clicking on the darkened area outside of the dialog will cancel the dialog. */ @@ -1077,7 +1077,7 @@ export class ConfigDialog extends Dialog { show(anchor: HTMLElement) { super.show() $('#blackout').hide(); - + if (anchor instanceof HTMLElement) { let anchor_position = $(anchor).offset(); this.object.style.top = (anchor_position.top+anchor.offsetHeight) + 'px'; @@ -1105,7 +1105,7 @@ export class ConfigDialog extends Dialog { let content = document.createElement('content'); content.className = 'dialog_content'; this.object.append(wrapper); - + wrapper.append(content); this.form = new InputForm(this.form_config); diff --git a/js/interface/menu_bar.js b/js/interface/menu_bar.js index 29644a25a..1aa07e58e 100644 --- a/js/interface/menu_bar.js +++ b/js/interface/menu_bar.js @@ -158,10 +158,10 @@ export const MenuBar = { id: 'import_open_project', name: 'menu.file.import.import_open_project', icon: 'input', - condition: () => Project && ModelProject.all.length > 1, + condition: () => Project && Blockbench.ModelProject.all.length > 1, children() { let projects = []; - ModelProject.all.forEach(project => { + Blockbench.ModelProject.all.forEach(project => { if (project == Project) return; projects.push({ name: project.getDisplayName(true), @@ -584,8 +584,8 @@ export const MenuBar = { {name: 'menu.help.developer.reset_storage', icon: 'fas.fa-hdd', click: () => { factoryResetAndReload(); }}, - {name: 'menu.help.developer.unlock_projects', id: 'unlock_projects', icon: 'vpn_key', condition: () => ModelProject.all.find(project => project.locked), click() { - ModelProject.all.forEach(project => project.locked = false); + {name: 'menu.help.developer.unlock_projects', id: 'unlock_projects', icon: 'vpn_key', condition: () => Blockbench.ModelProject.all.find(project => project.locked), click() { + Blockbench.ModelProject.all.forEach(project => project.locked = false); }}, { name: 'Uncorrupt Mesh', diff --git a/js/interface/panels.ts b/js/interface/panels.ts index e72a0cae7..4abc9b8dd 100644 --- a/js/interface/panels.ts +++ b/js/interface/panels.ts @@ -51,7 +51,7 @@ interface PanelOptions { | Toolbar[] default_position?: Partial mode_positions?: Record> - component?: Vue.Component + component?: Vue.ComponentOptions form?: InputForm default_side?: 'right' | 'left' /** @@ -106,7 +106,8 @@ export class Panel extends EventSystem { tab_bar: HTMLElement form?: InputForm vue?: Vue - inside_vue?: Vue + /** Used to access the properties of the Vue component if it exists */ + inside_vue?: Vue & Record toolbars: Toolbar[] sidebar_resize_handle: HTMLElement resize_handles?: HTMLElement @@ -169,7 +170,7 @@ export class Panel extends EventSystem { this.container.classList.add('grow'); this.node.classList.add('grow'); } - + // Toolbars let toolbars = data.toolbars instanceof Array ? data.toolbars : (data.toolbars ? Object.keys(data.toolbars) : []); @@ -193,7 +194,7 @@ export class Panel extends EventSystem { } if (data.component) { - + let component_mount = Interface.createElement('div'); this.node.append(component_mount); let onmounted = data.component.mounted; @@ -360,7 +361,7 @@ export class Panel extends EventSystem { Interface.addSuggestedModifierKey('ctrl', 'modifier_actions.move_panel_without_docking'); } if (!started) return; - + this.position_data.float_position[0] = position_before[0] + e2.clientX - e1.clientX; this.position_data.float_position[1] = position_before[1] + e2.clientY - e1.clientY; @@ -390,7 +391,7 @@ export class Panel extends EventSystem { } } else if (e2.clientX > document.body.clientWidth - Math.max(Interface.right_bar_width, threshold)) { - + target_slot = 'right_bar'; for (let child of Interface.right_bar.childNodes) { if (!child.clientHeight) continue; @@ -428,7 +429,7 @@ export class Panel extends EventSystem { Interface.left_bar.classList.remove('drop_target'); Interface.right_bar.classList.remove('drop_target'); $(`.panel_container.attach_target`).removeClass('attach_target'); - + Interface.removeSuggestedModifierKey('ctrl', 'modifier_actions.move_panel_without_docking'); if (attach_to) { @@ -448,7 +449,7 @@ export class Panel extends EventSystem { setTimeout(() => { this.update(); }, 0); - + removeEventListeners(document, 'mousemove touchmove', drag); removeEventListeners(document, 'mouseup touchend', stop); } @@ -461,7 +462,7 @@ export class Panel extends EventSystem { dragPanel(e1, true); }); - } else { + } else { let close_button = Interface.createElement('div', {class: 'tool panel_control'}, Blockbench.getIconNode('clear')) this.tab_bar.append(close_button); @@ -469,7 +470,7 @@ export class Panel extends EventSystem { Interface.PanelSelectorVue.select(null); }) this.tab_bar.classList.add('single_tab'); - + addEventListeners(this.handle as HTMLElement, 'mousedown touchstart', (e1: MouseEvent) => { convertTouchEvent(e1); @@ -485,7 +486,7 @@ export class Panel extends EventSystem { if (this.folded) this.fold(); } if (!started) return; - + let sign = (Blockbench.isLandscape && settings.mobile_panel_side.value == 'left') ? -1 : 1; this.position_data.height = Math.clamp(height_before + diff * sign, this.min_height, max); @@ -497,7 +498,7 @@ export class Panel extends EventSystem { convertTouchEvent(e2); this.update(); - + removeEventListeners(document, 'mousemove touchmove', drag); removeEventListeners(document, 'mouseup touchend', stop); } @@ -516,7 +517,7 @@ export class Panel extends EventSystem { setActivePanel(this.id); this.moveToFront(); }) - + // Add to slot if (!Blockbench.isMobile && !this.attached_to) { let reference_panel = Panels[data.insert_before || data.insert_after]; @@ -720,7 +721,7 @@ export class Panel extends EventSystem { } let stop = e2 => { convertTouchEvent(e2); - + removeEventListeners(document, 'mousemove touchmove', drag); removeEventListeners(document, 'mouseup touchend', stop); this.sidebar_resize_handle?.classList.remove('dragging'); @@ -771,7 +772,7 @@ export class Panel extends EventSystem { } let stop = e2 => { convertTouchEvent(e2); - + removeEventListeners(document, 'mousemove touchmove', drag); removeEventListeners(document, 'mouseup touchend', stop); } @@ -877,7 +878,7 @@ export class Panel extends EventSystem { if (this.position_data && (this.previous_slot == 'right_bar' || this.previous_slot == 'left_bar')) { makeSidebarFilled(this.previous_slot, this); } - + this.updateSlot(); if (Panels[this.id]) { this.dispatchEvent('moved_to', {slot, ref_panel, before, previous_slot: this.previous_slot}); @@ -923,7 +924,7 @@ export class Panel extends EventSystem { this.onFold(); } } - + this.customizePosition(); this.update(); @@ -1048,7 +1049,7 @@ export class Panel extends EventSystem { panel.handle.classList.toggle('selected', this.open_attached_panel == panel); tab_amount++; } - + if (this.id == 'uv') { this.id = 'uv' } diff --git a/js/interface/settings.ts b/js/interface/settings.ts index ffddb8943..e749123fb 100644 --- a/js/interface/settings.ts +++ b/js/interface/settings.ts @@ -335,7 +335,7 @@ export class SettingsProfile { SettingsProfile.all.forEach(p => p.selected = false); this.selected = true; SettingsProfile.selected = this; - + if (update) { Settings.updateSettingsInProfiles(); Settings.saveLocalStorages(); diff --git a/js/io/format.ts b/js/io/format.ts index 5699a8585..9c62529af 100644 --- a/js/io/format.ts +++ b/js/io/format.ts @@ -9,9 +9,10 @@ import { Canvas } from "../preview/canvas"; import { DefaultCameraPresets } from "../preview/preview"; import { Property } from "../util/property"; import { SplineMesh } from "../outliner/types/spline_mesh"; +import type { ModelProject } from "./project"; export interface FormatPage { - component?: Vue.Component + component?: Vue.ComponentOptions content?: ( | { type?: 'image' | 'h2' | 'h3' | 'h4' | 'text' | 'label' | 'image' | '' @@ -55,11 +56,6 @@ export interface CubeSizeLimiter { coordinate_limits?: [number, number] } -/** - * The current format - */ -declare const Format: ModelFormat - export const Formats: Record = {}; Object.defineProperty(window, 'Format', { @@ -334,7 +330,7 @@ export class ModelFormat implements FormatOptions { onFormatPage?(): void onStart?(): void onSetup?(project: ModelProject, newModel?: boolean): void - + cube_size_limiter?: CubeSizeLimiter @@ -433,7 +429,7 @@ export class ModelFormat implements FormatOptions { // @ts-ignore Interface.status_bar.vue.Format = this; UVEditor.vue.cube_uv_rotation = this.uv_rotation; - + if (typeof this.onActivation == 'function') { Format.onActivation() } @@ -703,15 +699,14 @@ new Property(ModelFormat, 'boolean', 'texture_folder'); new Property(ModelFormat, 'boolean', 'pbr'); new Property(ModelFormat, 'enum', 'euler_order', {default: 'ZYX'}); - const global = { - ModelFormat, Formats }; declare global { - const ModelFormat: typeof global.ModelFormat - type ModelFormat = import('./format').ModelFormat - const Format: ModelFormat + /** + * The format of the currently opened project. + */ + let Format: ModelFormat const Formats: Record } diff --git a/js/io/io.js b/js/io/io.js index 2ad25114d..c6ac7e84a 100644 --- a/js/io/io.js +++ b/js/io/io.js @@ -70,7 +70,7 @@ export function setupDragHandlers() { export function loadModelFile(file, args) { - let existing_tab = isApp && ModelProject.all.find(project => ( + let existing_tab = isApp && Blockbench.ModelProject.all.find(project => ( project.save_path == file.path || project.export_path == file.path )) diff --git a/js/io/model_loader.ts b/js/io/model_loader.ts index 2f6baa55f..4a67c805e 100644 --- a/js/io/model_loader.ts +++ b/js/io/model_loader.ts @@ -1,5 +1,5 @@ import { Vue } from "../lib/libs"; -import { FormatPage } from "./format"; +import type { FormatPage } from "./format"; export interface ModelLoaderOptions { icon: string @@ -65,12 +65,3 @@ export class ModelLoader implements Deletable { } static loaders: Record = {} } - -const global = { - ModelLoader -}; -declare global { - type ModelLoader = import('./model_loader').ModelLoader - const ModelLoader: typeof global.ModelLoader -} -Object.assign(window, global); diff --git a/js/io/project.ts b/js/io/project.ts index afe478c5c..cfc481a2c 100644 --- a/js/io/project.ts +++ b/js/io/project.ts @@ -232,8 +232,8 @@ export class ModelProject { this._saved = saved; // Dispatch an event to allow other scripts to react to the change - Blockbench.dispatchEvent('saved_state_changed', { - project: this, + Blockbench.dispatchEvent('saved_state_changed', { + project: this, saved: saved }); if (Project == this) { @@ -289,7 +289,7 @@ export class ModelProject { } saveEditorState(): this { UVEditor.saveViewportOffset(); - + Preview.all.forEach(preview => { this.previews[preview.id] = { position: preview.camera.position.toArray(), @@ -437,7 +437,7 @@ export class ModelProject { this.updateThumbnail(); this.saveEditorState(); } - + Interface.tab_bar.$data.last_opened_project = this.uuid; if (Format && typeof Format.onDeactivation == 'function') { @@ -458,7 +458,7 @@ export class ModelProject { Blockbench.Project = 0; if (Modes.selected instanceof Mode) Modes.selected.unselect(); Settings.updateSettingsInProfiles(); - + // Clear spline gizmos, otherwise they force the project open and glitch out the entire app // @ts-expect-error SplineGizmos.clear(); @@ -539,7 +539,7 @@ export class ModelProject { if (this.EditSession) { this.EditSession.quit(); } - + this.unselect(true); Texture.all.forEach(tex => tex.stopWatcher()); @@ -557,7 +557,7 @@ export class ModelProject { ModelProject.all.remove(this); delete ProjectData[this.uuid]; Blockbench.Project = 0; - + await AutoBackup.removeBackup(this.uuid); if (last_selected && last_selected !== this) { @@ -751,7 +751,7 @@ export function newProject(format: ModelFormat | string): boolean { } export function selectNoProject() { setStartScreen(true); - + Blockbench.Project = 0; // Setup Data @@ -876,7 +876,7 @@ onVueSetup(() => { mouseDown(tab, e1) { convertTouchEvent(e1); e1.preventDefault(); - + if (this.thumbnail) { this.thumbnail.remove(); delete this.thumbnail; @@ -890,7 +890,7 @@ onVueSetup(() => { addEventListeners(document, 'mouseup', off, {passive: false}); return; } - + let scope = this; let active = false; let timeout; @@ -927,14 +927,14 @@ onVueSetup(() => { } } else { if (e2) e2.preventDefault(); - + tab_node.style.left = `${offset}px`; let index_offset = Math.trunc((e2.clientX - e1.clientX) / tab_node.clientWidth); scope.drag_position_index = scope.drag_target_index + index_offset; // Detach tab - let outside_tab_bar_before = outside_tab_bar; + let outside_tab_bar_before = outside_tab_bar; outside_tab_bar = isApp && Math.abs(e2.clientY - 42) > 60 || e2.clientX < 2 || e2.clientX > window.innerWidth; if (outside_tab_bar !== outside_tab_bar_before) { @@ -969,7 +969,7 @@ onVueSetup(() => { if (Blockbench.isTouch) clearTimeout(timeout); - + if (isApp && outside_tab_bar && !tab.EditSession) { let project = Codecs.project.compile({editor_state: true, history: true, uuids: true, bitmaps: true, raw: true}) let pos = currentwindow.getPosition() @@ -1074,7 +1074,7 @@ BARS.defineActions(function() { let form: Record = { format: {type: 'info', label: 'data.format', text: Format.name||'unknown', description: Format.description} } - + for (var key in ModelProject.properties) { let property = ModelProject.properties[key]; if (property.exposed === false || !Condition(property.condition)) continue; @@ -1194,7 +1194,7 @@ BARS.defineActions(function() { Canvas.updateAllUVs() updateSelection() } - + for (var key in ModelProject.properties) { if (formResult[key] != undefined && Project[key] != formResult[key] && typeof Project[key] != 'object') { was_changed = true; @@ -1225,7 +1225,7 @@ BARS.defineActions(function() { } Project.EditSession.sendAll('change_project_meta', JSON.stringify(metadata)); } - + dialog.hide() } }) @@ -1297,7 +1297,7 @@ BARS.defineActions(function() { onConfirm: function(formResult) { var format = Formats[formResult.format] if (!format || format == Format) return; - + if (formResult.create_copy) { let selected_texture_uuid = Texture.selected?.uuid let model = Codecs.project.compile({raw: true}); @@ -1306,7 +1306,7 @@ BARS.defineActions(function() { if (Project.name) Project.name += ' - Converted'; Texture.all.find(t => t.uuid == selected_texture_uuid)?.select(); } - + format.convertTo() } }) @@ -1392,11 +1392,6 @@ BARS.defineActions(function() { }) }) -/** - * Global variable and shortcut to get the currently opened project. If no project is open, or the New Tab is open, this value is falsy. - */ -declare let Project: ModelProject | null | undefined - const global = { ModelProject, ProjectData, @@ -1408,8 +1403,10 @@ const global = { setStartScreen, }; declare global { - type ModelProject = import('./project').ModelProject - const ModelProject: typeof global.ModelProject + /** + * Global variable and shortcut to get the currently opened project. If no project is open, or the New Tab is open, this value is falsy. + */ + let Project: ModelProject | null | undefined const ProjectData: typeof global.ProjectData const setupProject: typeof global.setupProject const newProject: typeof global.newProject diff --git a/js/lib/libs.ts b/js/lib/libs.ts index e4f4b5d31..d04bbdba5 100644 --- a/js/lib/libs.ts +++ b/js/lib/libs.ts @@ -49,4 +49,17 @@ const global = { APNGencoder, DOMPurify, } +declare global { + const GIFEnc: typeof global.GIFEnc + // const THREE: typeof global.THREE + // const jQuery: typeof global.jQuery + // const $: typeof global.jQuery + const FIK: typeof global.FIK + // const Vue: typeof global.Vue + const JSZip: typeof global.JSZip + const Prism: typeof global.Prism + // const marked : typeof global.marked + const APNGencoder : typeof global.APNGencoder + const DOMPurify : typeof global.DOMPurify +} Object.assign(window, global); diff --git a/js/lib/vue.d.ts b/js/lib/vue.d.ts new file mode 100644 index 000000000..80b19a4ed --- /dev/null +++ b/js/lib/vue.d.ts @@ -0,0 +1,4 @@ +declare module 'vue/dist/vue.js' { + export * from 'vue' + export { default } from 'vue' +} diff --git a/js/main.ts b/js/main.ts index 8db5b31b7..d0a9d1b3e 100644 --- a/js/main.ts +++ b/js/main.ts @@ -20,6 +20,7 @@ import "./util/util" import "./util/json" import "./util/three_custom" import "./util/math_util" +import "./util/molang" import "./util/array_util" import "./util/event_system" import "./util/property" diff --git a/js/misc.js b/js/misc.js index 1c3685355..c8e1da07c 100644 --- a/js/misc.js +++ b/js/misc.js @@ -3,8 +3,8 @@ import { currentwindow } from "./native_apis"; window.osfs = '/' window.open_dialog = false; window.open_interface = false; -window.Format = 0; -window.Project = 0; +window.Format = null; +window.Project = null; export const Pressing = { shift: false, diff --git a/js/modes.ts b/js/modes.ts index d1104a7b2..ebf8e380b 100644 --- a/js/modes.ts +++ b/js/modes.ts @@ -22,7 +22,7 @@ interface ModeOptions { hide_sidebars?: boolean hide_status_bar?: boolean condition?: ConditionResolvable - component?: Vue.Component + component?: Vue.ComponentOptions onSelect?(): void onUnselect?(): void } @@ -109,7 +109,7 @@ export class Mode extends KeybindItem { if (Interface.Panels[Prop.active_panel] && !Condition(Interface.Panels[Prop.active_panel].condition)) { Prop.active_panel = 'preview'; } - + UVEditor.beforeMoving(); if (!Blockbench.isMobile) { for (let id in Panels) { diff --git a/js/outliner/abstract/outliner_node.ts b/js/outliner/abstract/outliner_node.ts index f35d729ee..c8ed1d5c6 100644 --- a/js/outliner/abstract/outliner_node.ts +++ b/js/outliner/abstract/outliner_node.ts @@ -33,7 +33,7 @@ export abstract class OutlinerNode { this.export = true; this.locked = false; this.scope = 0; - + this._static = Object.freeze({ properties: {}, temp_data: {}, @@ -74,7 +74,7 @@ export abstract class OutlinerNode { (element.parent instanceof OutlinerNode && types.includes(element.parent.type)); if (!is_allowed) return; } - + let arr = element.getParentArray(); let index = arr.indexOf(element); if (arr.includes(this) && index > this.getParentArray().indexOf(this)) { @@ -107,7 +107,7 @@ export abstract class OutlinerNode { } } } - + if (this.getTypeBehavior('parent_types')) { let types = this.getTypeBehavior('parent_types'); let is_allowed = (target == 'root' && types.includes('root')) || @@ -353,7 +353,7 @@ export abstract class OutlinerNode { } return iterate(this.parent, 0) } - + get preview_controller(): NodePreviewController { return (this.constructor as typeof OutlinerNode).preview_controller; diff --git a/js/outliner/types/armature_bone.ts b/js/outliner/types/armature_bone.ts index e037ed91c..79ad3c511 100644 --- a/js/outliner/types/armature_bone.ts +++ b/js/outliner/types/armature_bone.ts @@ -34,7 +34,7 @@ export class ArmatureBone extends OutlinerElement { width: number connected: boolean color: number - + static preview_controller: NodePreviewController @@ -296,7 +296,7 @@ export class ArmatureBone extends OutlinerElement { } static all: ArmatureBone[] static selected: ArmatureBone[] - + public title = tl('data.armature_bone'); public type = 'armature_bone'; public icon = 'humerus'; @@ -514,7 +514,7 @@ new NodePreviewController(ArmatureBone, { bone.fix_position.copy(bone.position); bone.fix_rotation.copy(bone.rotation); - + bone.updateMatrixWorld(); if (armature?.scene_object) { bone.inverse_bind_matrix.copy(armature.scene_object.matrixWorld).invert(); @@ -580,7 +580,7 @@ BARS.defineActions(function() { }) new_instance.addTo(add_to_node) new_instance.isOpen = true - + if (Format.bone_rig) { new_instance.createUniqueName() } diff --git a/js/outliner/types/bounding_box.ts b/js/outliner/types/bounding_box.ts index 30b9584f6..9964239a3 100644 --- a/js/outliner/types/bounding_box.ts +++ b/js/outliner/types/bounding_box.ts @@ -159,7 +159,7 @@ export class BoundingBox extends OutlinerElement { } getSaveCopy() { let el: any = {}; - + for (let key in BoundingBox.properties) { BoundingBox.properties[key].copy(this, el) } @@ -216,7 +216,7 @@ export class BoundingBox extends OutlinerElement { this.from[axis] = center - (this.to[axis] - center) this.to[axis] = center - (from - center) this.origin[axis] = center - (this.origin[axis] - center) - + flipNameOnAxis(this, axis); this.preview_controller.updateTransform(this); @@ -520,7 +520,7 @@ BARS.defineActions(function() { category: 'edit', condition: {modes: ['edit'], features: ['bounding_boxes']}, click: function () { - + Undo.initEdit({outliner: true, elements: [], selection: true}); let base_bounding_box = new BoundingBox().init() let group = getCurrentGroup(); diff --git a/js/plugin_loader.ts b/js/plugin_loader.ts index 00a08cce5..573d59233 100644 --- a/js/plugin_loader.ts +++ b/js/plugin_loader.ts @@ -674,10 +674,10 @@ export class Plugin { } }); }) - + } else if (isApp) { file_content = fs.readFileSync(path, {encoding: 'utf-8'}); - + } else { throw 'Failed to load plugin: Unknown URL format' } @@ -718,10 +718,10 @@ export class Plugin { } isInstallable() { var scope = this; - var result: string | boolean = + var result: string | boolean = scope.variant === 'both' || ( - isApp === (scope.variant === 'desktop') && + isApp === (scope.variant === 'desktop') && isApp !== (scope.variant === 'web') ); if (result && scope.min_version) { @@ -879,7 +879,7 @@ export class Plugin { } static selected: Plugin|null = null - + static menu = new Menu([ new MenuSeparator('general'), { @@ -1014,7 +1014,7 @@ Plugins.loading_promise = new Promise((resolve, reject) => { dataType: 'json', success(data) { Plugins.json = data; - + resolve(); Plugins.loading_promise = null; }, @@ -1118,7 +1118,7 @@ export async function loadInstalledPlugins() { if (plugin) { plugin.installed = true; if (installation.disabled) plugin.disabled = true; - + if (isApp && ( (installation.version && plugin.version && VersionUtil.compare(plugin.version, '<=', installation.version)) || (plugin.min_version && Blockbench.isOlderThan(plugin.min_version)) @@ -1142,7 +1142,7 @@ export async function loadInstalledPlugins() { } else if (isApp && installation.source == 'store') { // Offline install store plugin - let plugin = new Plugin(installation.id); + let plugin = new Plugin(installation.id); let promise = plugin.load(false); install_promises.push(promise); } else { @@ -1160,7 +1160,7 @@ export async function loadInstalledPlugins() { console.log(`Loaded ${load_counter} plugin${pluralS(load_counter)}`) } StateMemory.save('installed_plugins') - + install_promises.forEach(promise => { promise.catch(console.error); @@ -1585,6 +1585,7 @@ BARS.defineActions(function() { tl, Condition }, + // @ts-expect-error - Custom property: `mount_directly`. If enabled, skips one layer of wrapper. Class "dialog_content" must be added the the root element of the vue component. mount_directly: true, template: ` @@ -1622,7 +1623,7 @@ BARS.defineActions(function() {
  • {{ number+1 }}
  • - +
    arrow_back_ios @@ -1778,7 +1779,7 @@ BARS.defineActions(function() { - +
    - +
    • {{ type.name }}

      @@ -1839,15 +1840,15 @@ BARS.defineActions(function() {
    - +
    - +

    Blockbench Plugins

    Plugins allow you to configure Blockbench beyond the default capabilities. Select from a list of 100 community created plugins.

    Want to write your own plugin? Check out the Plugin Documentation.

    - +

    {{row.title}}

      @@ -1862,7 +1863,7 @@ BARS.defineActions(function() {
    - + ` } @@ -1930,7 +1931,7 @@ BARS.defineActions(function() { function getList(details: boolean): string { let plugins = Plugins.all.filter(p => p.installed); if (details) { - return plugins.map(p => + return plugins.map(p => (`${p.id}@${p.version}${p.source == 'store' ? '' : ('('+p.source+')')}`) ).join(', '); } else { diff --git a/js/preview/canvas.js b/js/preview/canvas.js index 48bfd0b01..8bdef6a39 100644 --- a/js/preview/canvas.js +++ b/js/preview/canvas.js @@ -12,6 +12,7 @@ import BrushOutlineVertShader from './../shaders/brush_outline.vert.glsl' import BrushOutlineFragShader from './../shaders/brush_outline.frag.glsl' import { prepareShader } from '../shaders/shader'; import { gizmo_colors } from './preview' +import { ModelProject } from '../io/project' export const Reusable = { vec1: new THREE.Vector3(), diff --git a/js/texturing/textures.js b/js/texturing/textures.js index 2ee8fd36f..059ef3c4b 100644 --- a/js/texturing/textures.js +++ b/js/texturing/textures.js @@ -9,6 +9,7 @@ import { editUVSizeDialog } from '../uv/uv_size'; import { decodeTga, encodeTga } from '@lunapaint/tga-codec'; import { pathToExtension } from '../util/util'; import { ScopeColors } from '../multi_file_editing'; +import { ModelProject } from '../io/project'; let tex_version = 1; diff --git a/js/web.js b/js/web.js index a073210ee..c06e6db25 100644 --- a/js/web.js +++ b/js/web.js @@ -36,7 +36,7 @@ addEventListener('load', function() { window.history.pushState({}, '') }) addEventListener('popstate', e => { - if (ModelProject.all.length == 0) { + if (Blockbench.ModelProject.all.length == 0) { return; } @@ -150,7 +150,7 @@ export async function loadInfoFromURL() { //Misc window.onbeforeunload = function() { - let unsaved_projects = ModelProject.all.find(project => !project.saved); + let unsaved_projects = Blockbench.ModelProject.all.find(project => !project.saved); if (unsaved_projects) { return 'Unsaved Changes'; } else { diff --git a/package-lock.json b/package-lock.json index 50294fae4..0713fa79f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Blockbench", - "version": "5.1.0-beta.1", + "version": "5.1.0-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Blockbench", - "version": "5.1.0-beta.1", + "version": "5.1.0-beta.2", "license": "GPL-3.0-or-later", "dependencies": { "@electron/remote": "^2.1.2", @@ -36,6 +36,10 @@ "devDependencies": { "@electron/notarize": "^2.5.0", "@types/node": "^22.14.0", + "@types/prismjs": "^1.26.6", + "@types/sortablejs": "^1.15.9", + "chalk": "^5.6.2", + "chokidar": "^5.0.0", "command-line-args": "^6.0.1", "concurrently": "^9.1.2", "dotenv": "^16.5.0", @@ -44,6 +48,8 @@ "esbuild": "^0.25.8", "esbuild-plugin-glsl": "^1.2.2", "esbuild-vue": "^0.0.1", + "tscw-config": "^1.1.2", + "tsx": "^4.21.0", "typedoc": "^0.28.14", "typescript": "^5.8.3", "workbox-build": "^6.5.3" @@ -113,7 +119,6 @@ "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -1715,7 +1720,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1787,6 +1791,23 @@ "electron-fuses": "dist/bin.js" } }, + "node_modules/@electron/fuses/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@electron/fuses/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -2104,6 +2125,23 @@ "node": ">=12.13.0" } }, + "node_modules/@electron/rebuild/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@electron/rebuild/node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -2263,6 +2301,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -2284,6 +2323,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2300,6 +2340,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -2314,6 +2355,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -3592,6 +3634,13 @@ "xmlbuilder": ">=11.0.1" } }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -3615,6 +3664,13 @@ "integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==", "license": "MIT" }, + "node_modules/@types/sortablejs": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.9.tgz", + "integrity": "sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/spectrum": { "version": "1.8.7", "resolved": "https://registry.npmjs.org/@types/spectrum/-/spectrum-1.8.7.tgz", @@ -3681,6 +3737,22 @@ "prettier": "^1.18.2 || ^2.0.0" } }, + "node_modules/@vue/compiler-sfc/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@vue/component-compiler": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/@vue/component-compiler/-/component-compiler-4.2.4.tgz", @@ -3761,6 +3833,23 @@ "url": "https://opencollective.com/postcss/" } }, + "node_modules/@vue/component-compiler-utils/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@vue/component-compiler-utils/node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -3847,7 +3936,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -4276,7 +4364,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -4369,6 +4456,23 @@ "node": ">=12.0.0" } }, + "node_modules/builder-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/builder-util/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -4577,16 +4681,13 @@ "license": "CC-BY-4.0" }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -4604,17 +4705,16 @@ } }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -4868,6 +4968,36 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/concurrently/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4967,7 +5097,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -5220,7 +5351,6 @@ "integrity": "sha512-5QNSeUVetoR1W1IOIz6o8Cs0Rwea1uNJehRdY0w3+6FTc+B4avPSy6OtNAxbvmdmx53DPh0nzxIXUGngwlfAhw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.0.18", "builder-util": "26.0.17", @@ -5405,7 +5535,6 @@ "integrity": "sha512-2j/kvw7uF0H1PnzYBzw2k2Q6q16J8ToKrtQzZfsAoXbbMY0l5gQi2DLOauIZLzwp4O01n8Wt/74JhSRwG0yj9A==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", @@ -5457,6 +5586,23 @@ "electron-winstaller": "5.4.0" } }, + "node_modules/electron-builder/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/electron-builder/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -5521,6 +5667,23 @@ "mime": "^2.5.2" } }, + "node_modules/electron-publish/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/electron-publish/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -5646,6 +5809,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -5666,6 +5830,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -5883,7 +6048,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -6323,6 +6487,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/gifenc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/gifenc/-/gifenc-1.0.3.tgz", @@ -7155,6 +7332,23 @@ "node": ">=10" } }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", @@ -7496,6 +7690,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -8147,6 +8358,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -8333,7 +8561,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -8706,6 +8933,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -8723,26 +8951,11 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "license": "MIT", - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -9059,14 +9272,13 @@ } }, "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", - "optional": true, "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", @@ -9224,7 +9436,17 @@ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" }, - "node_modules/resolve-url": { + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", @@ -9307,7 +9529,6 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -9397,6 +9618,38 @@ "@parcel/watcher": "^2.4.1" } }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -10003,6 +10256,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -10075,6 +10329,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -10089,6 +10344,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -10252,6 +10508,22 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/tscw-config": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tscw-config/-/tscw-config-1.1.2.tgz", + "integrity": "sha512-mrrMxCqC6kjqjuhGc7mTOB3P7JuBebZ0ZnFQTi4e+K0K+2kT1OvTXzFygWCPBor/F8WJ1IWVRrnBLKctFhFwOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-json-comments": "^5.0.1" + }, + "bin": { + "tscw": "dist/cli.js" + }, + "peerDependencies": { + "typescript": ">=2.0.0" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -10259,6 +10531,510 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -10327,7 +11103,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10585,7 +11360,6 @@ "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" diff --git a/package.json b/package.json index c7cb5e8f6..e2a713e09 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "prepublish-web": "npm run build-web && npm run pwa && npm run generate-docs", "prepublish-beta": "node ./scripts/enable_beta.js && npm run build-web && npm run pwa && npm run generate-docs", "webapp": "git checkout gh-pages && git pull && git merge master --no-edit && git push && git checkout master", - "generate-types": "tsc --project tsconfig.json && node ./scripts/convert_types.js", + "generate-types": "tsx scripts/generate_types.ts", "publish-types": "npm publish ./types", "generate-docs": "npm run generate-types && npx typedoc --options typedoc.json" }, @@ -152,6 +152,10 @@ "devDependencies": { "@electron/notarize": "^2.5.0", "@types/node": "^22.14.0", + "@types/prismjs": "^1.26.6", + "@types/sortablejs": "^1.15.9", + "chalk": "^5.6.2", + "chokidar": "^5.0.0", "command-line-args": "^6.0.1", "concurrently": "^9.1.2", "dotenv": "^16.5.0", @@ -160,6 +164,8 @@ "esbuild": "^0.25.8", "esbuild-plugin-glsl": "^1.2.2", "esbuild-vue": "^0.0.1", + "tscw-config": "^1.1.2", + "tsx": "^4.21.0", "typedoc": "^0.28.14", "typescript": "^5.8.3", "workbox-build": "^6.5.3" diff --git a/scripts/convert_types.js b/scripts/convert_types.js deleted file mode 100644 index 3ff14606a..000000000 --- a/scripts/convert_types.js +++ /dev/null @@ -1,118 +0,0 @@ -import fs from 'fs'; -import PathModule from 'path' - -/** - * Convert all auto-generated type definitions to declare globally instead of exporting - * Removes empty files and excluded files - */ - -let file_count = 0; -let file_delete_count = 0; - -const config = JSON.parse(fs.readFileSync('./types/type_config.json', 'utf-8')); - -function isComment(line) { - return line.startsWith('/*') || line.startsWith(' *') || line.startsWith('//'); -} - -/** - * - * @param {string} content - * @param {string} path - */ -function processFile(content, path) { - if (content.match(/\ndeclare global {/)) return content; - - // TODO: Handle comments - let lines = content.split(/\r?\n/); - let output_lines = []; - let i = 0; - let global_scope = false; - let comment_stash = []; - for (let line of lines) { - if (global_scope) { - if (line.startsWith('}') || line.startsWith(' ')) { - output_lines.push(' ' + line); - } else if ((line.startsWith('export ') || line.startsWith('interface')) && !line.startsWith('export {}')) { - for (let comment of comment_stash) { - output_lines.push(' ' + comment); - } - comment_stash.length = 0; - let shorter_line = line.replace(/^export (default )?(declare )?/, ''); - output_lines.push(' ' + shorter_line); - - } else if (isComment(line)) { - // Comment - comment_stash.push(line); - } else { - output_lines.push('}'); - global_scope = false; - output_lines.push(line); - } - - } else if ((line.startsWith('export ') || line.startsWith('interface')) && !line.startsWith('export {}')) { - output_lines.push('declare global {'); - for (let comment of comment_stash) { - output_lines.push(' ' + comment); - } - comment_stash.length = 0; - let shorter_line = line.replace(/^export (default )?(declare )?/, ''); - output_lines.push(' ' + shorter_line); - global_scope = true; - - } else if (isComment(line)) { - // Comment - comment_stash.push(line); - - } else { - if (comment_stash.length) { - output_lines.push(...comment_stash); - comment_stash.length = 0; - } - if (line) output_lines.push(line); - } - i++; - } - if (output_lines.includes('export {};') == false) { - output_lines.push('export {};'); - } - output_lines = output_lines.map(line => { - return line.replace(/, }/g, ' }'); - }) - output_lines.push(''); - let result = output_lines.join('\n'); - return result; -} - -function convertDirectory(path) { - let files = fs.readdirSync(path) - for (let file_name of files) { - let file_path = PathModule.join(path, file_name) - let simple_file_path = file_path.replace(/[\\\/]/g, '/').replace(/(\.d\.ts)$/, ''); - - if (file_name.endsWith('.ts')) { - let file_content = fs.readFileSync(file_path, {encoding: 'utf-8'}); - let modified_file_content = processFile(file_content, file_path); - if ( - !modified_file_content || - modified_file_content.replace('export {};', '').length < 5 || - config.exclude.find(exclusion => simple_file_path.endsWith(exclusion)) - ) { - fs.unlinkSync(file_path); - file_delete_count++; - } else if (modified_file_content != file_content) { - fs.writeFileSync(file_path, modified_file_content, {encoding: 'utf-8'}); - console.log('Update '+file_path) - file_count++; - } - } else { - convertDirectory(file_path); - } - } -} -convertDirectory('./types/generated'); - - -console.log(`Converted ${file_count} type definition files, deleted ${file_delete_count} empty files`); - - diff --git a/scripts/generate_types.ts b/scripts/generate_types.ts new file mode 100644 index 000000000..fe1933ac5 --- /dev/null +++ b/scripts/generate_types.ts @@ -0,0 +1,206 @@ +import chalk from 'chalk' +import { spawn } from 'child_process' +import chokidar from 'chokidar' +import { readdir, readFile, rm, stat, unlink, writeFile } from 'fs/promises' +import { join } from 'path' +import config from '../types/type_config.json' with { type: 'json' } + +const GENERATED_TYPES_DIR = './types/generated' + +/** + * Convert all auto-generated type definitions to declare globally instead of exporting + * Removes empty files and excluded files + */ + +let working = false +let processedFileCount = 0 +let deletedFileCount = 0 + +function isComment(line: string) { + return line.startsWith('/*') || line.startsWith(' *') || line.startsWith('//') +} + +async function compileTypeDefinitions() { + console.log(chalk.blue('โš™๏ธ Compiling type definitions...\n')) + return new Promise((resolve, reject) => + spawn('tsc', ['--project', 'tsconfig.json'], { stdio: 'inherit' }) + .on('close', code => { + if (code !== 0) { + console.error( + chalk.red('\n๐Ÿšจ TypeScript compilation compiled with type warnings!') + ) + } else { + console.log(chalk.blue('\nโœ… Type definitions compiled successfully.\n')) + } + resolve() + }) + .on('error', error => { + console.error( + chalk.red('โš ๏ธ Unexpected error during type definition compilation:'), + error + ) + reject(error) + }) + ) +} + +function transformFileContents(content: string, path: string) { + if (content.match(/\ndeclare global {/)) return content + + // TODO: Handle comments + let lines = content.split(/\r?\n/) + let output_lines = [] + let i = 0 + let global_scope = false + let comment_stash = [] + for (let line of lines) { + if (global_scope) { + if (line.startsWith('}') || line.startsWith(' ')) { + output_lines.push(' ' + line) + } else if ( + (line.startsWith('export ') || line.startsWith('interface')) && + !line.startsWith('export {}') + ) { + for (let comment of comment_stash) { + output_lines.push(' ' + comment) + } + comment_stash.length = 0 + let shorter_line = line.replace(/^export (default )?(declare )?/, '') + output_lines.push(' ' + shorter_line) + } else if (isComment(line)) { + // Comment + comment_stash.push(line) + } else { + output_lines.push('}') + global_scope = false + output_lines.push(line) + } + } else if ( + (line.startsWith('export ') || line.startsWith('interface')) && + !line.startsWith('export {}') + ) { + output_lines.push('declare global {') + for (let comment of comment_stash) { + output_lines.push(' ' + comment) + } + comment_stash.length = 0 + let shorter_line = line.replace(/^export (default )?(declare )?/, '') + output_lines.push(' ' + shorter_line) + global_scope = true + } else if (isComment(line)) { + // Comment + comment_stash.push(line) + } else { + if (comment_stash.length) { + output_lines.push(...comment_stash) + comment_stash.length = 0 + } + if (line) output_lines.push(line) + } + i++ + } + if (output_lines.includes('export {};') == false) { + output_lines.push('export {};') + } + output_lines = output_lines.map(line => { + return line.replace(/, }/g, ' }') + }) + output_lines.push('') + let result = output_lines.join('\n') + return result +} + +function normalizePath(path: string) { + return path.replaceAll('\\', '/') +} + +function isExcluded(path: string) { + const base = path.replace(/(.d)?.ts$/, '') + return config.exclude.some(excluded => normalizePath(base).endsWith(excluded)) +} + +function dontTransform(path: string) { + const base = path.replace(/(.d)?.ts$/, '') + return config.dontTransform.some(excluded => normalizePath(base).endsWith(excluded)) +} + +async function processFile(path: string) { + if (isExcluded(path)) { + await unlink(path) + deletedFileCount++ + return + } + if (dontTransform(path)) return + + const fileContent = await readFile(path, { encoding: 'utf-8' }) + const processedContent = transformFileContents(fileContent, path) + + if (processedContent == undefined || processedContent.replace('export {};', '').length < 5) { + await unlink(path) + deletedFileCount++ + return + } + + if (processedContent != fileContent) { + await writeFile(path, processedContent, { encoding: 'utf-8' }) + processedFileCount++ + } +} + +async function processDirectoryContents(path: string) { + for (const item of await readdir(path)) { + const itemPath = join(path, item) + const stats = await stat(itemPath) + + if (stats.isDirectory()) { + await processDirectoryContents(itemPath) + } else { + await processFile(itemPath) + } + } +} + +async function convertTypes() { + processedFileCount = 0 + deletedFileCount = 0 + await compileTypeDefinitions() + await processDirectoryContents(GENERATED_TYPES_DIR) + console.log( + chalk.green( + `\nโœ… Done! ${chalk.cyan(processedFileCount)} files processed, ${chalk.red(deletedFileCount)} files deleted.` + ) + ) +} + +const onUpdate = async (path: string) => { + if (working) return // Prevent multiple simultaneous executions + working = true + + console.log(chalk.blue(`๐Ÿ“ Change detected: ${path}\n`)) + try { + await convertTypes() + } finally { + working = false + } +} + +async function main() { + // Cleanup old generated types before starting + console.log(chalk.blue('๐Ÿงน Cleaning up old generated types...')) + await rm(GENERATED_TYPES_DIR, { recursive: true, force: true }) + // Generate types for the first time + await convertTypes() + + if (process.argv.includes('--watch')) { + chokidar + .watch('./js', { ignoreInitial: true, awaitWriteFinish: true }) + .on('ready', () => { + console.log(chalk.blue('๐Ÿ‘€ Watching for changes...')) + }) + .on('change', onUpdate) + .on('add', onUpdate) + .on('unlink', onUpdate) + } +} + +void main() diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000..6632c7282 --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,23 @@ +{ + "include": ["."], + "compilerOptions": { + "outDir": "./dist/", + "noImplicitAny": true, + "module": "nodenext", + "target": "ES2022", + "moduleResolution": "nodenext", + "strict": true, + "types": ["node"], + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "allowUmdGlobalAccess": true, + "allowUnreachableCode": true, + "allowImportingTsExtensions": true, + "esModuleInterop": true, + "noEmit": true, + "verbatimModuleSyntax": true, + "isolatedModules": true, + "alwaysStrict": true, + "baseUrl": "src" + } +} diff --git a/types/README.md b/types/README.md index 1316b7ce0..0e95bf156 100644 --- a/types/README.md +++ b/types/README.md @@ -13,6 +13,8 @@ All type definitions in the /custom/ folder are manually written and are intende ## Generating types Run `npm run generate-types` from the main repo. Ensure typescript throws no errors, otherwise files won't export correctly. +Use `npm run generate-types -- --watch` to automatically regenerate types on source file changes. + ## Locally testing and using types To use these types in other projects on your local PC before they are published, run this command in your other project: diff --git a/types/custom/codec.d.ts b/types/custom/codec.d.ts index 25c7a0e97..30c8f3424 100644 --- a/types/custom/codec.d.ts +++ b/types/custom/codec.d.ts @@ -1,182 +1,185 @@ /// +import { ModelFormat } from "../io/format"; -interface LoadOptions { - import_to_current_project?: boolean - externalDataLoader?: (path: string) => any - [key: string]: unknown -} -interface CodecOptions { - name: string - load?(model: any, file: FileResult, args?: LoadOptions): void - compile?(options?: any): string | ArrayBuffer | any - parse?(data: any, path: string, args?: LoadOptions): void - export?(): void - /** - * Generate a file name to suggest when exporting - */ - fileName?(): string - startPath?(): string - write?(content: any, path: string): void - overwrite?(content: any, path: string, callback: (path: any) => void): void - afterDownload?(path: any): void - afterSave?(path: any): void - exportCollection?(collection: Collection): void - writeCollection?(collection: Collection): void +declare global { + interface LoadOptions { + import_to_current_project?: boolean + externalDataLoader?: (path: string) => any + [key: string]: unknown + } + interface CodecOptions { + name: string + load?(model: any, file: FileResult, args?: LoadOptions): void + compile?(options?: any): string | ArrayBuffer | any + parse?(data: any, path: string, args?: LoadOptions): void + export?(): void + /** + * Generate a file name to suggest when exporting + */ + fileName?(): string + startPath?(): string + write?(content: any, path: string): void + overwrite?(content: any, path: string, callback: (path: any) => void): void + afterDownload?(path: any): void + afterSave?(path: any): void + exportCollection?(collection: Collection): void + writeCollection?(collection: Collection): void - dispatchEvent?(event_name: string, data: any): void + dispatchEvent?(event_name: string, data: any): void - extension?: string - /** - * Whether to remember the models exported using this codec - */ - remember?: boolean - /** - * Whether the codec can be used to export a part of the model via a collection - */ - support_partial_export?: boolean - support_offset?: boolean - load_filter?: { - extensions: string[] - type: 'json' | 'text' - condition?: ConditionResolvable + extension?: string + /** + * Whether to remember the models exported using this codec + */ + remember?: boolean + /** + * Whether the codec can be used to export a part of the model via a collection + */ + support_partial_export?: boolean + support_offset?: boolean + load_filter?: { + extensions: string[] + type: 'json' | 'text' + condition?: ConditionResolvable + } + /** + * List of export option inputs, based on the Dialog form API + */ + export_options?: { + [key: string]: FormElementOptions + } + /** + * Default action that is used to export to the codec + */ + export_action?: Action } - /** - * List of export option inputs, based on the Dialog form API - */ - export_options?: { - [key: string]: FormElementOptions - } - /** - * Default action that is used to export to the codec - */ - export_action?: Action -} -/** - * A codec represents a specific file format that can be imported into and exported from Blockbench. The codec handles the compilation and parsing, as well as the loading and exporting logic - */ -declare class Codec extends Deletable { - plugin?: string /** - * Creates a new codec - * @param id Codec ID - * @param options Codec options + * A codec represents a specific file format that can be imported into and exported from Blockbench. The codec handles the compilation and parsing, as well as the loading and exporting logic */ - constructor(id: string, options: CodecOptions) + class Codec extends Deletable { + plugin?: string + /** + * Creates a new codec + * @param id Codec ID + * @param options Codec options + */ + constructor(id: string, options: CodecOptions) - /** - * Load a file into the program - * @param model - * @param file - * @param add - */ - load(model: any, file?: any, args?: LoadOptions): void - /** - * Compiles the file content - * @param options - */ - compile(options?: any): any - /** - * Takes the content of a file, and loads the model into the current Blockbench project - * @param data File content - * @param path File path - */ - parse?(data: any, path: string, args?: LoadOptions): void - /** - * Opens the file browser to export a file of this type - */ - export(): void - /** - * Generate a file name to suggest when exporting - */ - fileName(): string - /** - * Generates the suggested file path. This is the path that the explorer opens in when exporting this type - */ - startPath(): string - /** - * Write the content of this file to the selected location. The default method can be overwritten to achieve custom behavior - * @param content File content, as generated by compile() - * @param path The file export path - */ - write(content: any, path: string): void - overwrite(content: any, path: string, callback: (path: string) => void): void - afterDownload(path: string): void - afterSave(path: string): void - exportCollection(collection: Collection): void - writeCollection(collection: Collection): void + /** + * Load a file into the program + * @param model + * @param file + * @param add + */ + load(model: any, file?: any, args?: LoadOptions): void + /** + * Compiles the file content + * @param options + */ + compile(options?: any): any + /** + * Takes the content of a file, and loads the model into the current Blockbench project + * @param data File content + * @param path File path + */ + parse?(data: any, path: string, args?: LoadOptions): void + /** + * Opens the file browser to export a file of this type + */ + export(): void + /** + * Generate a file name to suggest when exporting + */ + fileName(): string + /** + * Generates the suggested file path. This is the path that the explorer opens in when exporting this type + */ + startPath(): string + /** + * Write the content of this file to the selected location. The default method can be overwritten to achieve custom behavior + * @param content File content, as generated by compile() + * @param path The file export path + */ + write(content: any, path: string): void + overwrite(content: any, path: string, callback: (path: string) => void): void + afterDownload(path: string): void + afterSave(path: string): void + exportCollection(collection: Collection): void + writeCollection(collection: Collection): void - /** - * Return the stored export option values of the current project - */ - getExportOptions(): { [key: string]: any } - /** - * Prompt the user to enter their preferred export settings into the dialog - */ - promptExportOptions(): Promise<{ [key: string]: any } | null> + /** + * Return the stored export option values of the current project + */ + getExportOptions(): { [key: string]: any } + /** + * Prompt the user to enter their preferred export settings into the dialog + */ + promptExportOptions(): Promise<{ [key: string]: any } | null> - /** - * Adds an event listener to the codec - * @param event_name The event type to listen for - * @param callback - */ - on(event_name: string, callback: (data: any) => void): void - /** - * Adds a single-use event listener to the codec - * @param event_name The event type to listen for - * @param callback - */ - once(event_name: string, callback: (data: any) => void): void - /** - * Removes an event listener from the codec - * @param event_name - * @param callback - */ - removeListener(event_name: string, callback: (data: any) => void): void - dispatchEvent(event_name: string, data: any): void + /** + * Adds an event listener to the codec + * @param event_name The event type to listen for + * @param callback + */ + on(event_name: string, callback: (data: any) => void): void + /** + * Adds a single-use event listener to the codec + * @param event_name The event type to listen for + * @param callback + */ + once(event_name: string, callback: (data: any) => void): void + /** + * Removes an event listener from the codec + * @param event_name + * @param callback + */ + removeListener(event_name: string, callback: (data: any) => void): void + dispatchEvent(event_name: string, data: any): void - /** - * The display name of the codec - */ - name: string - /** - * The default file extension that the codec uses - */ - extension: string - /** - * Whether to remember files that use this codec in the recent models list - */ - remember: boolean - /** - * Whether the codec can be used to export a part of the model via a collection - */ - support_partial_export: boolean - support_offset: boolean - /** - * If available, the action that is used to export files using this codec - */ - export_action?: Action + /** + * The display name of the codec + */ + name: string + /** + * The default file extension that the codec uses + */ + extension: string + /** + * Whether to remember files that use this codec in the recent models list + */ + remember: boolean + /** + * Whether the codec can be used to export a part of the model via a collection + */ + support_partial_export: boolean + support_offset: boolean + /** + * If available, the action that is used to export files using this codec + */ + export_action?: Action - /** - * List of export option inputs - */ - export_options: { - [key: string]: FormElement - } + /** + * List of export option inputs + */ + export_options: { + [key: string]: FormElement + } - /** - * Additional properties - */ - [key: string]: any + /** + * Additional properties + */ + [key: string]: any - format: ModelFormat + format: ModelFormat - /** - * Get a list of all possible extensions of all codecs - */ - static getAllExtensions(): string[] -} + /** + * Get a list of all possible extensions of all codecs + */ + static getAllExtensions(): string[] + } -declare const Codecs: { - [id: string]: Codec + const Codecs: { + [id: string]: Codec + } } diff --git a/types/custom/edit_session.d.ts b/types/custom/edit_session.d.ts index 2b74e54a7..7504f106a 100644 --- a/types/custom/edit_session.d.ts +++ b/types/custom/edit_session.d.ts @@ -12,7 +12,7 @@ declare class EditSession { client_count: number data_queue: [] chat_history: [] - Project: ModelProject | null + Project: Blockbench.ModelProject | null updateClientCound(): void start(username?: string): void diff --git a/types/custom/global.d.ts b/types/custom/global.d.ts index 7f3b24719..e4e727ac3 100644 --- a/types/custom/global.d.ts +++ b/types/custom/global.d.ts @@ -1,7 +1,6 @@ /// declare global { - // const Prism: typeof import('prismjs') /** * @deprecated Use {@link Canvas.scene} instead */ diff --git a/types/custom/interface.d.ts b/types/custom/interface.d.ts index 5c53e992c..3f224a5c7 100644 --- a/types/custom/interface.d.ts +++ b/types/custom/interface.d.ts @@ -38,7 +38,7 @@ declare namespace Interface { } const status_bar: { menu: Menu - vue: Vue.Component + vue: Vue } let tab_bar: Vue const Panels: { diff --git a/types/custom/misc.d.ts b/types/custom/misc.d.ts index 7f70e4d08..0d9d41538 100644 --- a/types/custom/misc.d.ts +++ b/types/custom/misc.d.ts @@ -1,13 +1,13 @@ /// -declare class Deletable { +declare abstract class Deletable { /** * The ID of the plugin that created the object */ - plugin?: string - delete(): void + abstract plugin?: string + abstract delete(): void } -type UUID = string +declare type UUID = string declare global { const settings: typeof settings @@ -20,10 +20,17 @@ declare const isApp: boolean declare const VuePrismEditor: Vue.Component -interface BlockbenchEventMap { - display_animation_frame: {in_loop: true} - display_default_pose: {reduced_updates: boolean} - interpolate_keyframes: {animator: BoneAnimator, t: number, time: number, use_quaternions: boolean, keyframe_before: _Keyframe, keyframe_after: _Keyframe} +declare interface BlockbenchEventMap { + display_animation_frame: { in_loop: true } + display_default_pose: { reduced_updates: boolean } + interpolate_keyframes: { + animator: BoneAnimator + t: number + time: number + use_quaternions: boolean + keyframe_before: _Keyframe + keyframe_after: _Keyframe + } before_closing: any create_session: any join_session: any @@ -39,8 +46,8 @@ interface BlockbenchEventMap { uninstalled_plugin: { plugin: BBPlugin } update_settings: any update_project_settings: Record - save_project: {model: any, options?: any} - load_project: {model: any, path: string} + save_project: { model: any; options?: any } + load_project: { model: any; path: string } new_project: any reset_project: any close_project: any @@ -64,89 +71,89 @@ interface BlockbenchEventMap { invert_selection: any canvas_select: any canvas_click: any - change_texture_path: {texture: Texture} - add_texture: {texture: Texture} + change_texture_path: { texture: Texture } + add_texture: { texture: Texture } generate_texture_template: any update_texture_selection: any - init_edit: {aspects: UndoAspects, amended: boolean, save: UndoSave} - finish_edit: {aspects: UndoAspects, message: string} - finished_edit: {aspects: UndoAspects, message: string} | {remote: true} - init_selection_change: {aspects: UndoAspects, save: UndoSelectionSave} - finish_selection_change: {aspects: UndoAspects} - finished_selection_change: {aspects: UndoAspects} - cancel_selection_change: {selection_before: UndoSelectionSave} + init_edit: { aspects: UndoAspects; amended: boolean; save: UndoSave } + finish_edit: { aspects: UndoAspects; message: string } + finished_edit: { aspects: UndoAspects; message: string } | { remote: true } + init_selection_change: { aspects: UndoAspects; save: UndoSelectionSave } + finish_selection_change: { aspects: UndoAspects } + finished_selection_change: { aspects: UndoAspects } + cancel_selection_change: { selection_before: UndoSelectionSave } undo: { entry: UndoEntry } redo: { entry: UndoEntry } - load_undo_save: {save: UndoSave, reference: UndoSave, mode: undefined | 'session'} - create_undo_save: {save: UndoSave, aspects: UndoAspects} + load_undo_save: { save: UndoSave; reference: UndoSave; mode: undefined | 'session' } + create_undo_save: { save: UndoSave; aspects: UndoAspects } drop_text: { text: string } paste_text: { text: string } change_color: any select_mode: { mode: Mode } unselect_mode: { mode: Mode } change_active_panel: any - resize_window: {event?: Event} - press_key: {input_in_focus?: HTMLElement, event: KeyboardEvent, capture: () => void} - select_format: {format: ModelFormat, project: ModelProject} - convert_format: {format: ModelFormat, old_format: ModelFormat} - construct_format: {format: ModelFormat} - delete_format: {format: ModelFormat} - select_project: { project: ModelProject } - unselect_project: { project: ModelProject } + resize_window: { event?: Event } + press_key: { input_in_focus?: HTMLElement; event: KeyboardEvent; capture: () => void } + select_format: { format: Blockbench.ModelFormat; project: Blockbench.ModelProject } + convert_format: { format: Blockbench.ModelFormat; old_format: Blockbench.ModelFormat } + construct_format: { format: Blockbench.ModelFormat } + delete_format: { format: Blockbench.ModelFormat } + select_project: { project: Blockbench.ModelProject } + unselect_project: { project: Blockbench.ModelProject } setup_project: any update_project_resolution: any merge_project: any display_model_stats: any update_view: UpdateViewOptions - update_camera_position: {preview: Preview} + update_camera_position: { preview: Preview } render_frame: any construct_model_loader: any delete_model_loader: any update_recent_project_data: any update_recent_project_thumbnail: any load_from_recent_project_data: any - edit_animation_properties: {animation: _Animation} + edit_animation_properties: { animation: _Animation } select_preview_scene: any unselect_preview_scene: any - select_animation: {animation: _Animation} - remove_animation: {animations: _Animation[]} - compile_bedrock_animation_controller_state: {state: AnimationControllerState, json: any} - select_animation_controller_state: {state: AnimationControllerState} - add_animation_controller_animation: {state: AnimationControllerState} - add_animation_controller_transition: {state: AnimationControllerState} - add_animation_controller_particle: {state: AnimationControllerState} - add_animation_controller_sound: {state: AnimationControllerState} - compile_bedrock_animation_controller: {state: AnimationController, json: any} - add_animation_controller: {state: AnimationController} - edit_animation_controller_properties: {state: AnimationController} + select_animation: { animation: _Animation } + remove_animation: { animations: _Animation[] } + compile_bedrock_animation_controller_state: { state: AnimationControllerState; json: any } + select_animation_controller_state: { state: AnimationControllerState } + add_animation_controller_animation: { state: AnimationControllerState } + add_animation_controller_transition: { state: AnimationControllerState } + add_animation_controller_particle: { state: AnimationControllerState } + add_animation_controller_sound: { state: AnimationControllerState } + compile_bedrock_animation_controller: { state: AnimationController; json: any } + add_animation_controller: { state: AnimationController } + edit_animation_controller_properties: { state: AnimationController } timeline_play: any timeline_pause: any unselect_interface: any reset_layout: any update_pressed_modifier_keys: { - before: {shift: boolean, alt: boolean, ctrl: boolean} - now: {shift: boolean, alt: boolean, ctrl: boolean} + before: { shift: boolean; alt: boolean; ctrl: boolean } + now: { shift: boolean; alt: boolean; ctrl: boolean } event: KeyboardEvent } - open_bar_menu: {menu: BarMenu} + open_bar_menu: { menu: BarMenu } unselect_all: any - get_face_texture: {face: Face, element: OutlinerElement} + get_face_texture: { face: Face; element: OutlinerElement } quick_save_model: any save_editor_state: any load_editor_state: any select_no_project: any flip_node_name: any update_scene_shading: any - edit_layer_properties: {layer: TextureLayer} - select_texture: {texture: Texture, event: Event} - compile_texture_mcmeta: {mcmeta: any} + edit_layer_properties: { layer: TextureLayer } + select_texture: { texture: Texture; event: Event } + compile_texture_mcmeta: { mcmeta: any } register_element_type: any edit_collection_properties: any } -type BlockbenchEventName = keyof BlockbenchEventMap +declare type BlockbenchEventName = keyof BlockbenchEventMap -type IconString = string +declare type IconString = string declare const osfs: '\\' | '/' @@ -174,7 +181,7 @@ declare const Pressing: { } } -type RecentProjectData = { +declare type RecentProjectData = { name: string path: string icon: string @@ -185,11 +192,6 @@ type RecentProjectData = { } declare const recent_projects: RecentProjectData[] -declare const Prop = { - active_panel: string -} -declare const Project: ModelProject - declare function updateCubeHighlights(hover_cube: Cube, force_off: boolean): void declare function getRescalingFactor(angle: number): number diff --git a/types/type_config.json b/types/type_config.json index 4decc93f9..441957d4d 100644 --- a/types/type_config.json +++ b/types/type_config.json @@ -43,5 +43,8 @@ "lib/lzutf8", "lib/VuePrismEditor", "lib/VuePrismEditor.min" + ], + "dontTransform": [ + "io/model_loader" ] -} \ No newline at end of file +}