diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76c76fd2e..89221024a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,10 +17,11 @@ If you want to contribute Blockbench translations, you can visit [blockbench.net ## Source code contributions -Blockbench, the program itself, is mostly just coded by me. But sometimes, code contributions can be helpful! +Blockbench, the program itself, is mostly just coded by me. But third party contributions are welcome! -If you want to contribute to the Blockbench code, please contact me (@Jannis) on [Discord](https://discord.gg/sGkj78W) (e.g. in #bb-feedback) *before* to discuss whether a change is necessary in the base program and how it can be approached. -Some changes make sense in Blockbench itself, while others could work better as a plugin. +Bug fixes can be submitted via pull request. + +If you want to add a feature or change functionality, I recommend opening a discussion on Discord before to talk about if and where it fits in. You can do so in the channel [#bb-feedback](https://discord.gg/kZBmCwvBFw). Some features may be out of scope and work better as plugins, or I might have additional tips on how to approach it. The timing of features being integrated also depends on the release cycle, new features should go through beta testing before being shipped. Minor fixes should be targeting the `patch` branch, new features and fixes that require additional testing should generally target the `next` branch. diff --git a/css/general.css b/css/general.css index 61d8ef5b5..8730a3381 100644 --- a/css/general.css +++ b/css/general.css @@ -687,7 +687,10 @@ } .tool.side_menu_tool i.icon.action_more_options { display: inline-block; - width: 19px; + width: 20px; + height: 100%; + margin-top: 0; + padding-top: 4px; color: var(--color-text); margin-left: 0; } @@ -702,6 +705,7 @@ text-align: center; width: 100%; margin-top: 0px; + padding-top: 0px; } /*(Context-)Menu*/ diff --git a/css/panels.css b/css/panels.css index 72012b7af..826390c0e 100644 --- a/css/panels.css +++ b/css/panels.css @@ -1120,6 +1120,7 @@ } .texture_layer > label { flex-grow: 1; + overflow: hidden; } .texture_layer i.toggle_disabled { color: var(--color-subtle_text); @@ -1773,7 +1774,7 @@ } #timeline_vue.graph_editor .channel_head { flex-wrap: wrap; - justify-content: flex-end; + justify-content: flex-start; } .drag_hover[order]::before { z-index: 7; diff --git a/js/animations/animation_mode.js b/js/animations/animation_mode.js index 1fd1a6b80..9fe50d2ab 100644 --- a/js/animations/animation_mode.js +++ b/js/animations/animation_mode.js @@ -81,9 +81,9 @@ export const Animator = { Timeline.pause() Animator.open = false; - scene.remove(WinterskyScene.space); - scene.remove(Animator.motion_trail); - scene.remove(Animator.onion_skin_object); + Canvas.scene.remove(WinterskyScene.space); + Canvas.scene.remove(Animator.motion_trail); + Canvas.scene.remove(Animator.onion_skin_object); Animator.resetParticles(true); three_grid.position.z = three_grid.position.x; @@ -113,7 +113,7 @@ export const Animator = { } } Blockbench.dispatchEvent('display_default_pose', {reduced_updates}); - if (!reduced_updates) scene.updateMatrixWorld() + if (!reduced_updates) Canvas.scene.updateMatrixWorld() }, resetParticles(optimized) { for (var path in Animator.particle_effects) { diff --git a/js/animations/molang.js b/js/animations/molang.js index fa5b4cdf8..a56b2bd78 100644 --- a/js/animations/molang.js +++ b/js/animations/molang.js @@ -237,6 +237,9 @@ new ValidatorCheck('molang_syntax', { if (clear_string.match(/^[+*/.,?=&<>|]/)) { issues.push('Expression starts with an invalid character') } + if (clear_string.endsWith(';') && !clear_string.includes('return ')) { + issues.push('Complex expression with no return value. Remove the semicolon or add a return statement') + } if ( (clear_string.match(/[\w.]\s+[\w.]/) && !keywords.find((k) => clear_string.includes(k))) || diff --git a/js/auto_backup.ts b/js/auto_backup.ts index 640469e3d..b119c27ad 100644 --- a/js/auto_backup.ts +++ b/js/auto_backup.ts @@ -119,7 +119,12 @@ export const AutoBackup = { // Confirm selection if (confirm_selection && projects.length > 1) { - let form: Record = {}; + let form: Record = { + info: { + text: 'โš  Recovering models is only a backup. Please remember to always save your work to your device.', + type: 'info' + } + }; let keys: UUID[] = []; projects.sort((a, b) => (b.date??0) - (a.date??0)); @@ -155,7 +160,7 @@ export const AutoBackup = { } projects = await new Promise((resolve, reject) => { - new Dialog({ + let dialog = new Dialog({ id: 'recover_backup', title: 'message.recover_backup.title', form, @@ -171,6 +176,10 @@ export const AutoBackup = { resolve(to_open); } }).show(); + let content = dialog.object.querySelector('.dialog_content') as HTMLElement; + if (content) { + content.style.maxHeight = (window.innerHeight - 150) + 'px'; + } }) } diff --git a/js/desktop.js b/js/desktop.js index f3fcb2523..009a22f72 100644 --- a/js/desktop.js +++ b/js/desktop.js @@ -88,7 +88,7 @@ export function initializeDesktopApp() { //Load Model export function loadOpenWithBlockbenchFile() { function load(path) { - if (!path || path.length < 7 || !path.match(/\w\.\w+$/)) return; + if (!path || path.length < 7 || path.startsWith('--') || !path.match(/.\.\w+$/)) return; var extension = pathToExtension(path); if (extension == 'png') { Blockbench.read([path], {readtype: 'image'}, (files) => { diff --git a/js/formats/bedrock/bedrock_voxel_shape.ts b/js/formats/bedrock/bedrock_voxel_shape.ts index 9187e4637..9838c89ef 100644 --- a/js/formats/bedrock/bedrock_voxel_shape.ts +++ b/js/formats/bedrock/bedrock_voxel_shape.ts @@ -189,7 +189,32 @@ BARS.defineActions(function() { size: bb.size() } }); - if (type == 'selection_box') box_data.length = 1; + if (type == 'selection_box') { + let { origin, size } = box_data[0]; + let minX = origin[0]; + let minY = origin[1]; + let minZ = origin[2]; + let maxX = origin[0] + size[0]; + let maxY = origin[1] + size[1]; + let maxZ = origin[2] + size[2]; + for (let i = 1; i < box_data.length; i++) { + const { origin, size } = box_data[i]; + minX = Math.min(minX, origin[0]); + minY = Math.min(minY, origin[1]); + minZ = Math.min(minZ, origin[2]); + maxX = Math.max(maxX, origin[0] + size[0]); + maxY = Math.max(maxY, origin[1] + size[1]); + maxZ = Math.max(maxZ, origin[2] + size[2]); + } + box_data = [{ + origin: [minX, minY, minZ], + size: [ + maxX - minX, + maxY - minY, + maxZ - minZ + ] + }] + }; let data = box_data as any; if (box_data.length == 1 && box_data[0].origin.equals([-8, 0, -8]) && box_data[0].size.equals([16, 16, 16])) { data = true; diff --git a/js/formats/minecraft/skin.ts b/js/formats/minecraft/skin.ts index 93787a424..4820992fa 100644 --- a/js/formats/minecraft/skin.ts +++ b/js/formats/minecraft/skin.ts @@ -847,6 +847,8 @@ Interface.definePanels(function() { // Source: https://github.com/Mojang/bedrock-samples/, licensed under the Minecraft EULA // With modifications for usability +// Clipbench.setText(compileJSON(Codecs.skin_model.compile({raw: false})).replace(/\n/g, '\n\t')) + skin_presets.steve = { display_name: 'Player - Wide', pose: true, @@ -6873,7 +6875,7 @@ skin_presets.panda_baby = { }; skin_presets.parrot = { display_name: 'Parrot', - model: `{ + model_bedrock: `{ "name": "parrot", "external_textures": ["entity/parrot/parrot_red_blue.png"], "texturewidth": 32, @@ -6939,6 +6941,73 @@ skin_presets.parrot = { ] } ] + }`, + model_java: `{ + "name": "parrot", + "external_textures": ["entity/parrot/parrot_red_blue.png"], + "texturewidth": 32, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 7.5, -3], + "rotation": [25, 0, 0], + "cubes": [ + {"origin": [-1.5, 1.5, -4.5], "size": [3, 6, 3], "uv": [2, 8]} + ] + }, + { + "name": "wing0", + "parent": "body", + "pivot": [1.5, 7.1, -2.8], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [1, 2.1, -4.3], "size": [1, 5, 3], "uv": [19, 8]} + ] + }, + { + "name": "wing1", + "parent": "body", + "pivot": [-1.5, 7.1, -2.8], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-2, 2.1, -4.3], "size": [1, 5, 3], "uv": [19, 8]} + ] + }, + { + "name": "head", + "pivot": [0, 8.3, -2.8], + "cubes": [ + {"origin": [-1, 6.8, -3.8], "size": [2, 3, 2], "uv": [2, 2]}, + {"origin": [-1, 9.8, -5.8], "size": [2, 1, 4], "uv": [10, 0]}, + {"origin": [-0.5, 7.8, -4.7], "size": [1, 2, 1], "uv": [11, 7]}, + {"origin": [-0.5, 8.035, -5.64], "size": [1, 2.025, 1], "uv": [16, 7]}, + {"origin": [0, 9.1, -4.9], "size": [0, 5, 4], "uv": [2, 18]} + ] + }, + { + "name": "tail", + "pivot": [0, 2.9, 1.2], + "rotation": [50, 0, 0], + "cubes": [ + {"origin": [-1.5, -0.1, 0.2], "size": [3, 4, 1], "uv": [22, 1]} + ] + }, + { + "name": "leg0", + "pivot": [1.5, 1, -0.5], + "cubes": [ + {"origin": [0.5, -0.5, -1.5], "size": [1, 2, 1], "uv": [14, 18]} + ] + }, + { + "name": "leg1", + "pivot": [-0.5, 1, -0.5], + "cubes": [ + {"origin": [-1.5, -0.5, -1.5], "size": [1, 2, 1], "uv": [14, 18]} + ] + } + ] }` }; skin_presets.phantom = { @@ -10500,7 +10569,6 @@ skin_presets.zombie = { pose: true, model_java: `{ "name": "zombie", - "external_textures": ["entity/zombie/zombie.png"], "texturewidth": 64, "textureheight": 64, "eyes": [ diff --git a/js/interface/about.ts b/js/interface/about.ts index 29967c738..93fdbc9a8 100644 --- a/js/interface/about.ts +++ b/js/interface/about.ts @@ -7,9 +7,11 @@ BARS.defineActions(() => { icon: 'info', category: 'blockbench', click: function () { + let date = new Date(); const data = { isApp, - version_label: Blockbench.version + version_label: Blockbench.version, + ann: date.dayOfYear() == 95 && date.getFullYear() == 2026, c: 0, link: Blockbench.openLink }; jQuery.ajax({ url: 'https://api.github.com/repos/JannisX11/blockbench/releases/latest', @@ -140,6 +142,7 @@ BARS.defineActions(() => {

Released under the GPL 3.0 license

Privacy Policy

+ egg ` } diff --git a/js/interface/actions.ts b/js/interface/actions.ts index 4e8ed177a..2fe0435b5 100644 --- a/js/interface/actions.ts +++ b/js/interface/actions.ts @@ -1150,7 +1150,7 @@ export class NumSlider extends Widget { this.node.classList.add('is_colored'); } - //this.addLabel(data.label); + this.addLabel(); this.jq_inner .on('mousedown touchstart', async (event) => { diff --git a/js/modeling/mirror_modeling.ts b/js/modeling/mirror_modeling.ts index 260ce7460..aa8193192 100644 --- a/js/modeling/mirror_modeling.ts +++ b/js/modeling/mirror_modeling.ts @@ -82,7 +82,7 @@ export const MirrorModeling = { let parent = child.parent; if (parent instanceof OutlinerNode == false) return 'root'; - if ('origin' in parent && parent.origin[0] == center && MirrorModeling.isParentTreeSymmetrical(child, {center})) { + if ('origin' in parent && Math.epsilon(parent.origin[0], center) && MirrorModeling.isParentTreeSymmetrical(child, {center})) { return parent; } else { let mirror_group_parent = getParentMirror(parent) as OutlinerNode & OutlinerNodeParentTraits; @@ -185,8 +185,8 @@ export const MirrorModeling = { parents.push(subject) } return parents.allAre(parent => { - if (parent.rotation && off_axes.some(axis => parent.rotation[axis])) return false; - if (parent.origin && !symmetry_axes.allAre(axis => parent.origin[axis] == center)) return false; + if (parent.rotation && off_axes.some(axis => !Math.epsilon(parent.rotation[axis], 0))) return false; + if (parent.origin && !symmetry_axes.allAre(axis => Math.epsilon(parent.origin[axis], center))) return false; return true; }) }, @@ -245,7 +245,10 @@ export const MirrorModeling = { // post if (!before_snapshop) undo_aspects.outliner = true; if (!undo_aspects.groups) undo_aspects.groups = []; - undo_aspects.groups.safePush(group); + if (!undo_aspects.groups.includes(group)) { + // Must be new array so we don't accidentally change the undo input array + undo_aspects.groups = [...undo_aspects.groups, group]; + } }, element_types: {} as Record, registerElementType(type_class: any, options: MirrorModelingElementTypeOptions) { @@ -310,7 +313,7 @@ Blockbench.on('init_edit', (args) => { aspects.outliner = true; selected_groups.forEach(group => { - if (group.origin[0] == (Format.centered_grid ? 0 : 8)) return; + if (Math.epsilon(group.origin[0], (Format.centered_grid ? 0 : 8))) return; let mirror_group = Group.all.find(g => { if ( @@ -366,13 +369,17 @@ Blockbench.on('finish_edit', ({aspects}) => { if (aspects.group || aspects.groups || aspects.outliner) { Canvas.updateAllBones(); } - } else if (aspects.group || aspects.groups) { + } + if (aspects.group || aspects.groups) { let selected_groups = aspects.groups ?? [aspects.group]; selected_groups.forEach(group => { let mirror_group = MirrorModeling.cached_elements[group.uuid]?.counterpart; if (mirror_group && Group.all.includes(mirror_group)) { + let before_snapshot = mirror_group.getChildlessCopy(); + before_snapshot.uuid = mirror_group.uuid; MirrorModeling.updateParentNodeCounterpart(mirror_group, group); + MirrorModeling.insertGroupIntoUndo(mirror_group, aspects, before_snapshot); } }) @@ -421,7 +428,8 @@ MirrorModeling.registerElementType(Cube, { !off_axes.some(axis => !Math.epsilon(element.to[axis], element2.to[axis], e)) && !symmetry_axes.some(axis => !Math.epsilon(element.size(axis), element2.size(axis), e)) && !symmetry_axes.some(axis => !Math.epsilon(element.to[axis]-center, center-element2.from[axis], e)) && - isOppositeEuler(element.rotation, element2.rotation) + isOppositeEuler(element.rotation, element2.rotation) && + element2.getDepth() == element.getDepth() ) { return element2; } @@ -469,7 +477,8 @@ MirrorModeling.registerElementType(Mesh, { symmetry_axes.find(axis => !Math.epsilon(this_center[axis]-center, center-other_center[axis], ep)) == undefined && off_axes.find(axis => !Math.epsilon(element.origin[axis], element2.origin[axis], e)) == undefined && off_axes.find(axis => !Math.epsilon(this_center[axis], other_center[axis], ep)) == undefined && - isOppositeEuler(element.rotation, element2.rotation) + isOppositeEuler(element.rotation, element2.rotation) && + element2.getDepth() == element.getDepth() ) { return element2; } @@ -698,7 +707,8 @@ MirrorModeling.registerElementType(ArmatureBone, { if ( isOppositeVector(element.position, element2.position, center) && isOppositeEuler(element.rotation, element2.rotation) && - MirrorModeling.isParentTreeOpposite(element, element2) + MirrorModeling.isParentTreeOpposite(element, element2) && + element2.getDepth() == element.getDepth() ) { return element2; } @@ -737,7 +747,8 @@ MirrorModeling.registerElementType(Billboard, { for (let element2 of (Billboard.all as Billboard[])) { if (element == element2) continue; if ( - isOppositeVector(element.position, element2.position, center) + isOppositeVector(element.position, element2.position, center) && + element2.getDepth() == element.getDepth() ) { return element2; } @@ -766,7 +777,7 @@ export function symmetrizeArmature(armature: Armature, mesh: Mesh, affected_vkey // For each vkey, copy its value on each bone to the other side for (let vkey in mesh.vertices) { let position = mesh.vertices[vkey]; - if (position[0] == 0) continue; + if (!Math.epsilon(position[0], 0)) continue; if (affected_vkeys.has(vkey) == false) continue; let opposite = getOppositeMeshVertex(mesh, vkey); if (!opposite) continue; diff --git a/js/modeling/transform.js b/js/modeling/transform.js index 46cf360c8..94d328542 100644 --- a/js/modeling/transform.js +++ b/js/modeling/transform.js @@ -520,11 +520,11 @@ function changeNodeLocalPosition(obj, vector) { if ('forEachChild' in obj && obj.getTypeBehavior('use_absolute_position')) { let difference = position_arr.slice().V3_subtract(obj.origin); obj.forEachChild(child => { - if (child instanceof Mesh) { + /*if (child instanceof Mesh) { for (let vkey in child.vertices) { child.vertices[vkey].V3_add(difference); } - } + }*/ if (child.from) child.from.V3_add(difference); if (child.to) child.to.V3_add(difference); if (child.origin) child.origin.V3_add(difference); diff --git a/js/native_apis.ts b/js/native_apis.ts index 45d8dffec..501aaed3d 100644 --- a/js/native_apis.ts +++ b/js/native_apis.ts @@ -41,7 +41,9 @@ const SAFE_APIS = [ 'string_decoder', 'querystring', 'constants', - 'buffer' + 'buffer', + 'stream', + 'perf_hooks' ]; const REQUESTABLE_APIS = [ 'fs', @@ -214,7 +216,7 @@ delete window.require; /** * Revoke the permissions of a plugin - * @param plugin + * @param plugin * @returns List of revoked permissions * @private */ diff --git a/js/outliner/outliner.js b/js/outliner/outliner.js index be88a5db3..97b4f8482 100644 --- a/js/outliner/outliner.js +++ b/js/outliner/outliner.js @@ -433,7 +433,7 @@ export function moveOutlinerSelectionTo(item, target, order = 0, options = {}) { return; } if (duplicate) { - Undo.initEdit({elements: [], outliner: true, selection: true}, options.amended); + Undo.initEdit({elements: [], groups: [], outliner: true, selection: true}, options.amended); Outliner.selected.empty(); } else { Undo.initEdit({ @@ -453,6 +453,9 @@ export function moveOutlinerSelectionTo(item, target, order = 0, options = {}) { item.preview_controller.updateFaces(item); } } + if (item.preview_controller.updateGeometry) { + item.preview_controller.updateGeometry(item); + } } let matrix1 = new THREE.Matrix4(); let matrix2 = new THREE.Matrix4(); @@ -527,7 +530,7 @@ export function moveOutlinerSelectionTo(item, target, order = 0, options = {}) { } updateSelection(); if (duplicate) { - Undo.finishEdit('Duplicate selection', {elements: Outliner.selected, outliner: true, selection: true, groups: Group.selected}) + Undo.finishEdit('Duplicate selection', {elements: Outliner.selected, outliner: true, selection: true, groups: Group.all.filter(g => g.selected)}) } else { Undo.finishEdit('Move elements in outliner') } @@ -736,7 +739,6 @@ SharedActions.add('duplicate', { condition: () => Modes.edit && Group.first_selected, priority: -1, run() { - let cubes_before = elements.length; Undo.initEdit({outliner: true, elements: [], groups: [], selection: true}); let all_original = []; for (let group of Group.multi_selected) { @@ -745,10 +747,12 @@ SharedActions.add('duplicate', { let all_new = []; let new_groups = []; - let old_selected_groups = Group.multi_selected.slice(); + let groups_to_duplicate = Group.selected.filter(g => g.parent.selected == false); Group.multi_selected.empty(); - for (let group of old_selected_groups) { - group.selected = false; + for (let group of Group.all) { + if (group.selected) group.selected = false; + } + for (let group of groups_to_duplicate) { let new_group = group.duplicate(); new_group.forEachChild(g => all_new.push(g), Group, true); new_group.multiSelect(); @@ -756,7 +760,12 @@ SharedActions.add('duplicate', { } updateSelection(); - Undo.finishEdit('Duplicate group', {outliner: true, elements: elements.slice().slice(cubes_before), groups: new_groups, selection: true}); + Undo.finishEdit('Duplicate group', { + outliner: true, + elements: Outliner.selected, + groups: Group.all.filter(g => g.selected), + selection: true + }); if (Animation.all.length) { let affected_anims = Animation.all.filter(a => all_original.find(bone => a.animators[bone.uuid]?.keyframes.length)); @@ -1392,7 +1401,7 @@ Interface.definePanels(function() { node[key] = value; }) // Update - Canvas.updateVisibility(); + Canvas.updateView({elements: affected, element_aspects: {visibility: true}}); } else if (!affected.includes(node) && (!node.locked || key == 'locked' || key == 'visibility')) { let new_affected = [node]; @@ -1414,7 +1423,9 @@ Interface.definePanels(function() { if (key == 'mirror_uv' && node.preview_controller.updateUV) node.preview_controller.updateUV(node); }) // Update - if (key == 'visibility') Canvas.updateVisibility(); + if (key == 'visibility') { + Canvas.updateView({elements: affected, element_aspects: {visibility: true}}); + } if (key == 'locked') updateSelection(); } } @@ -1519,10 +1530,12 @@ Interface.definePanels(function() { Interface.createElement('label', {}, item.name) ]); - if (item instanceof Group == false && Outliner.selected.length > 1) { + let all_nodes = Outliner.selected.concat(Group.selected); + let count = all_nodes.filter(node => node.parent == Outliner.ROOT || node.parent.selected == false).length; + if (count > 1) { let counter = document.createElement('div'); counter.classList.add('outliner_drag_number'); - counter.textContent = Outliner.selected.length.toString(); + counter.textContent = count.toString(); helper.append(counter); } document.body.append(helper); diff --git a/js/outliner/types/group.js b/js/outliner/types/group.js index 7fdcc953c..317d8eab1 100644 --- a/js/outliner/types/group.js +++ b/js/outliner/types/group.js @@ -299,7 +299,7 @@ export class Group extends OutlinerNode { } this.remove(false); if (undo) { - all_groups.empty(); + all_groups.remove(this); Undo.finishEdit('Resolve group'); } return array; @@ -909,19 +909,22 @@ BARS.defineActions(function() { condition: {modes: ['edit'], method: () => Group.first_selected}, click() { let all_elements = []; + let all_groups = []; for (let group of Group.multi_selected) { + all_groups.push(group); group.forEachChild(obj => { if (obj instanceof Group == false) { all_elements.safePush(obj); + } else { + all_groups.push(obj); } }) } - let affected_groups = Group.multi_selected.slice(); - Undo.initEdit({outliner: true, elements: all_elements, groups: affected_groups}) - for (let group of affected_groups) { + Undo.initEdit({outliner: true, elements: all_elements, groups: all_groups}) + for (let group of Group.multi_selected.slice()) { group.resolve(false); + all_groups.remove(group); } - affected_groups.empty(); Undo.finishEdit('Resolve group'); } }) diff --git a/js/outliner/types/mesh.js b/js/outliner/types/mesh.js index 30e36571a..c6c6292c4 100644 --- a/js/outliner/types/mesh.js +++ b/js/outliner/types/mesh.js @@ -134,7 +134,7 @@ export class MeshFace extends Face { face.uv[vkey][0] * factor_x, face.uv[vkey][1] * factor_y, ]; - if (pointInRectangle(uv_a, ...px_rect)) { + if (pointInRectangle(uv_a, px_rect[0], px_rect[1])) { inside = true; break; } let vkey_b = sorted_vertices[i+1] || sorted_vertices[0]; @@ -143,7 +143,7 @@ export class MeshFace extends Face { face.uv[vkey_b][0] * factor_x, face.uv[vkey_b][1] * factor_y, ]; - if (lineIntersectsReactangle(uv_a, uv_b, ...px_rect)) { + if (lineIntersectsReactangle(uv_a, uv_b, px_rect[0], px_rect[1])) { inside = true; break; } i++; @@ -160,10 +160,19 @@ export class MeshFace extends Face { getUVIsland(max_depth = 4096) { let keys = [this.getFaceKey()]; let epsilon = 0.2; + let vkey_fkey_map = {}; + let faces = this.mesh.faces; + for (let fkey in faces) { + let face = faces[fkey]; + for (let vkey of face.vertices) { + vkey_fkey_map[vkey] ??= []; + vkey_fkey_map[vkey].push(fkey); + } + } function crawl(face, depth) { if (depth >= max_depth) return; for (let i = 0; i < face.vertices.length; i++) { - let adjacent = face.getAdjacentFace(i); + let adjacent = face.getAdjacentFace(i, vkey_fkey_map); if (!adjacent) continue; if (keys.includes(adjacent.key)) continue; let uv_a1 = adjacent.face.uv[adjacent.edge[0]]; @@ -267,7 +276,7 @@ export class MeshFace extends Face { return []; } } - getAdjacentFace(side_index = 0) { + getAdjacentFace(side_index = 0, vkey_fkey_map) { let vertices = this.getSortedVertices(); side_index = side_index % this.vertices.length; let side_vertices = [ @@ -275,7 +284,8 @@ export class MeshFace extends Face { vertices[side_index+1] || vertices[0] ] let faces = this.mesh.faces; - for (let fkey in faces) { + let fkeys = vkey_fkey_map ? vkey_fkey_map[side_vertices[0]] : Object.keys(faces); + for (let fkey of fkeys) { let face = faces[fkey]; if (face === this) continue; if (face.vertices.includes(side_vertices[0]) && face.vertices.includes(side_vertices[1])) { @@ -1138,7 +1148,7 @@ new NodePreviewController(Mesh, { } } } - if (Modes.animate && vertex_offsets) { + if (vertex_offsets) { for (let key in faces) { let face = faces[key]; if (face.vertices.length <= 2) continue; diff --git a/js/plugin_loader.ts b/js/plugin_loader.ts index a67408830..bdfec726d 100644 --- a/js/plugin_loader.ts +++ b/js/plugin_loader.ts @@ -25,7 +25,7 @@ export const Plugins = { */ installed: [] as PluginInstallation[], json: undefined, - download_stats: {}, + download_stats: {} as Record, /** * All loaded plugins, including plugins from the store that are not installed */ @@ -684,10 +684,10 @@ export class Plugin { } }); }) - + } else if (isApp) { file_content = fs.readFileSync(path, {encoding: 'utf-8'}); - + } else { throw 'Failed to load plugin: Unknown URL format' } @@ -728,10 +728,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) { @@ -889,7 +889,7 @@ export class Plugin { } static selected: Plugin|null = null - + static menu = new Menu([ new MenuSeparator('general'), { @@ -1024,7 +1024,7 @@ Plugins.loading_promise = new Promise((resolve, reject) => { dataType: 'json', success(data) { Plugins.json = data; - + resolve(); Plugins.loading_promise = null; }, @@ -1128,7 +1128,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)) @@ -1152,7 +1152,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 { @@ -1170,7 +1170,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); @@ -1632,7 +1632,7 @@ BARS.defineActions(function() {
  • {{ number+1 }}
  • - +
    arrow_back_ios @@ -1788,7 +1788,7 @@ BARS.defineActions(function() { - +
    - +
    • {{ type.name }}

      @@ -1849,15 +1849,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.

    +

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

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

    - +

    {{row.title}}

      @@ -1872,7 +1872,7 @@ BARS.defineActions(function() {
    - + ` } @@ -1940,7 +1940,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/preview.js b/js/preview/preview.js index 9c706923d..47c2bcdc8 100644 --- a/js/preview/preview.js +++ b/js/preview/preview.js @@ -421,31 +421,32 @@ export class Preview { raycast(event, options = Toolbox.selected.raycast_options) { if (!options) options = 0; convertTouchEvent(event); - var canvas_offset = $(this.canvas).offset() + let canvas_offset = this.canvas.getBoundingClientRect(); this.mouse.x = ((event.clientX - canvas_offset.left) / this.width) * 2 - 1; this.mouse.y = - ((event.clientY - canvas_offset.top) / this.height) * 2 + 1; this.raycaster.setFromCamera( this.mouse, this.camera ); var objects = [] Outliner.elements.forEach(element => { - if (element.visibility === false || element.locked === true || (element.mesh && element.mesh.visible == false)) return; - if (element.mesh && element.mesh.geometry) { - objects.push(element.mesh); + let mesh = element.mesh; + if (element.visibility === false || element.locked === true || (mesh && mesh.visible == false)) return; + if (mesh && mesh.geometry) { + objects.push(mesh); if (Modes.edit && element.selected) { - if (element.mesh.vertex_points && (element.mesh.vertex_points.visible || options.vertices)) { - objects.push(element.mesh.vertex_points); + if (mesh.vertex_points && (mesh.vertex_points.visible || options.vertices)) { + objects.push(mesh.vertex_points); } - if (element instanceof Mesh && ((element.mesh.outline.visible && BarItems.selection_mode.value == 'edge') || options.edges)) { - objects.push(element.mesh.outline); + if (element instanceof Mesh && ((mesh.outline.visible && BarItems.selection_mode.value == 'edge') || options.edges)) { + objects.push(mesh.outline); } } else if (element instanceof SplineMesh && element.render_mode !== "mesh") { - objects.push(element.mesh.pathLine); + objects.push(mesh.pathLine); } } else if (element instanceof Locator) { - objects.push(element.mesh.sprite); + objects.push(mesh.sprite); } else if (element instanceof ArmatureBone) { if (Toolbox.selected.id == 'weight_brush' && !(event.altKey || Pressing.overrides.alt)) return; - objects.push(element.mesh.children[0]); + objects.push(mesh.children[0]); } }) for (let group of Group.multi_selected) { @@ -596,7 +597,7 @@ export class Preview { render() { this.controls.update() this.renderer.render( - scene, + Canvas.scene, this.camera ) } @@ -2457,7 +2458,7 @@ BARS.defineActions(function() { click(event = 0) { if (!Project) return; let zoom = this.keybind.additionalModifierTriggered(event, 'zoom'); - if (Prop.active_panel == 'uv') { + if (Prop.active_panel == 'uv' || document.querySelector('#UVEditor:hover')) { UVEditor.focusOnSelection(zoom) } else { diff --git a/js/preview/screenshot.js b/js/preview/screenshot.js index 6d81837e7..1a58f8979 100644 --- a/js/preview/screenshot.js +++ b/js/preview/screenshot.js @@ -257,7 +257,6 @@ export const Screencam = { let render_viewport = options.anti_aliasing == 'msaa' ? MediaPreview : Screencam.NoAAPreview; let sample_factor = options.anti_aliasing == 'ssaa' ? 4 : 1; - render_viewport.resize(options.resolution[0] * sample_factor, options.resolution[1] * sample_factor); if (options.angle_preset == 'view') { render_viewport.copyView(preview); } else { @@ -266,6 +265,8 @@ export const Screencam = { : JSON.parse(localStorage.getItem('camera_presets'))[parseInt(options.angle_preset)]; render_viewport.loadAnglePreset(preset); } + render_viewport.resize(options.resolution[0] * sample_factor, options.resolution[1] * sample_factor); + if (options.zoom) { if (!render_viewport.isOrtho) { render_viewport.camera.setFocalLength(options.zoom); diff --git a/js/texturing/layers.js b/js/texturing/layers.js index 8d0640b20..347e65775 100644 --- a/js/texturing/layers.js +++ b/js/texturing/layers.js @@ -410,9 +410,10 @@ SharedActions.add('duplicate', { let original = texture.getActiveLayer(); let copy = original.getUndoCopy(true); copy.name += '-copy'; - Undo.initEdit({textures: [texture]}); + Undo.initEdit({textures: [texture], bitmap: true}); let layer = new TextureLayer(copy, texture); layer.addForEditing(); + texture.updateLayerChanges(true); Undo.finishEdit('Duplicate layer'); } }) diff --git a/js/texturing/painter.js b/js/texturing/painter.js index d27cac1c6..46c6d1037 100644 --- a/js/texturing/painter.js +++ b/js/texturing/painter.js @@ -195,7 +195,9 @@ export const Painter = { } if (!PointerTarget.requestTarget(PointerTarget.types.paint)) { Painter.paint_stroke_canceled = true; - return; + if (Toolbox.selected != BarItems.copy_brush || !event.ctrlOrCmd) { + return; + } } if (Toolbox.selected.brush && Toolbox.selected.brush.onStrokeStart) { let result = Toolbox.selected.brush.onStrokeStart({texture, x, y, uv: uvTag, event, raycast_data: data}); @@ -2361,7 +2363,7 @@ BARS.defineActions(function() { three_grid.visible = false; }, onUnselect: () => { - Canvas.updateAllBones() + Animator.showDefaultPose(); Outliner.elements.forEach(cube => { if (cube.preview_controller.updatePixelGrid) cube.preview_controller.updatePixelGrid(cube); }) diff --git a/js/texturing/textures.js b/js/texturing/textures.js index 64315677b..65df8975a 100644 --- a/js/texturing/textures.js +++ b/js/texturing/textures.js @@ -174,7 +174,7 @@ export class Texture { cancel: 1 }, function(result) { if (result === 0) { - setProjectResolution(img.naturalWidth, img.naturalHeight) + UVSizeUtil.adjustProjectResolution(img.naturalWidth, img.naturalHeight); if (selected.length) { UVEditor.loadData() } diff --git a/js/util/scoped_fs.ts b/js/util/scoped_fs.ts index fb49b7c5f..a43912036 100644 --- a/js/util/scoped_fs.ts +++ b/js/util/scoped_fs.ts @@ -118,11 +118,23 @@ export function createScopedFS(scope?: string) { checkPath(path); return fs.statSync(path, options); }, + watchFile(path: string, options, listener) { + checkPath(path); + return fs.watchFile(path, options, listener); + }, + unwatchFile(path: string, listener) { + checkPath(path); + return fs.unwatchFile(path, listener); + }, + watch(path: string, options, listener) { + checkPath(path); + return fs.watch(path, options, listener); + }, promises: { access(path: string, mode) { checkPath(path); - return fs.access(path, mode); + return fs.promises.access(path, mode); }, copyFile(src: string, dest: string, mode) { checkPath(src); @@ -169,6 +181,10 @@ export function createScopedFS(scope?: string) { stat(path: string, options) { checkPath(path); return fs.promises.stat(path, options); + }, + watch(path: string, options) { + checkPath(path); + return fs.promises.watch(path, options); } } } diff --git a/js/uv/uv.js b/js/uv/uv.js index 61c43787c..9caaaf54f 100644 --- a/js/uv/uv.js +++ b/js/uv/uv.js @@ -358,6 +358,7 @@ export const UVEditor = { zoom = BarItems.focus_on_selection.keybind.additionalModifierTriggered(zoom, 'zoom'); } let [min_x, min_y, max_x, max_y] = this.vue.getSelectedUVBoundingBox(); + if (min_x == Infinity) return; if (zoom) { let width = (max_x-min_x) / UVEditor.getUVWidth(); let height = (max_y-min_y) / UVEditor.getUVHeight(); @@ -1035,9 +1036,18 @@ export const UVEditor = { let selected_faces = mesh.getSelectedFaces(true); if (face_key && mesh && mesh.faces[face_key]) { if (selected_faces.length == 1) { + let vkey_fkey_map = {}; + let faces = mesh.faces; + for (let fkey in faces) { + let face = faces[fkey]; + for (let vkey of face.vertices) { + vkey_fkey_map[vkey] ??= []; + vkey_fkey_map[vkey].push(fkey); + } + } function crawl(face) { for (let i = 0; i < face.vertices.length; i++) { - let adjacent = face.getAdjacentFace(i); + let adjacent = face.getAdjacentFace(i, vkey_fkey_map); if (!adjacent) continue; if (selected_faces.includes(adjacent.key)) continue; let epsilon = 0.2; @@ -4716,13 +4726,26 @@ Interface.definePanels(function() { let value = this.mappable_elements[0].faces[key].texture === null; Undo.initEdit({elements: Cube.selected, uv_only: true}) UVEditor.forCubes(obj => { - UVEditor.getFaces(obj, event).forEach(function(side) { - if (value) { - if (obj.faces[side].texture === null) obj.faces[side].texture = false; - } else { + let faces = UVEditor.getFaces(obj, event); + if (!faces.includes(key)) { + faces = [key]; + } + for (let side of faces) { + if (!value) { obj.faces[side].texture = null; + + } else if (obj.faces[side].texture === null) { + let value = false; + for (let fkey in obj.faces) { + let face = obj.faces[fkey]; + if (fkey != side && face.texture) { + value = face.texture; + break; + } + } + obj.faces[side].texture = value; } - }) + } obj.preview_controller.updateFaces(obj); }) UVEditor.loadData() diff --git a/js/uv/uv_size.ts b/js/uv/uv_size.ts index b9864a7bc..2f23ff5d0 100644 --- a/js/uv/uv_size.ts +++ b/js/uv/uv_size.ts @@ -1,5 +1,5 @@ -export function setProjectResolution(width: number, height: number, modify_uv: boolean = false) { +function adjustProjectResolution(width: number, height: number, modify_uv: boolean = false) { if (Project.texture_width / width != Project.texture_width / height) { modify_uv = false; } @@ -35,7 +35,7 @@ export function setProjectResolution(width: number, height: number, modify_uv: b } } -export function adjustElementUVToResolution(multiplier: ArrayVector2, elements = Outliner.elements, textures?: Texture[]) { +function adjustElementUVToResolution(multiplier: ArrayVector2, elements = Outliner.elements, textures?: Texture[]) { for (let element of elements) { if ('faces' in element == false) continue; if (element instanceof Mesh) { @@ -231,4 +231,17 @@ export function editUVSizeDialog(options: {texture?: Texture, project?: boolean} updateSelection(); } }).show(); -} \ No newline at end of file +} + +export const UVSizeUtil = { + adjustProjectResolution, + adjustElementUVToResolution, + editUVSizeDialog +} +const global = { + UVSizeUtil +}; +declare global { + const UVSizeUtil: typeof global.UVSizeUtil +} +Object.assign(window, global); diff --git a/package-lock.json b/package-lock.json index 8efcfc0fd..72d0e6e8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Blockbench", - "version": "5.1.1", + "version": "5.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Blockbench", - "version": "5.1.1", + "version": "5.1.2", "license": "GPL-3.0-or-later", "dependencies": { "@electron/remote": "^2.1.2", @@ -21,6 +21,8 @@ "@types/spectrum": "^1.8.7", "@types/three": "^0.129.2", "@types/tinycolor2": "^1.4.6", + "chalk": "^5.6.2", + "chokidar": "^5.0.0", "command-line-args": "^6.0.1", "concurrently": "^9.1.2", "dompurify": "^3.3.1", @@ -41,6 +43,8 @@ "strip-json-comments": "^5.0.3", "three": "^0.129.0", "tinycolor2": "^1.6.0", + "tscw-config": "^1.1.2", + "tsx": "^4.21.0", "typedoc": "^0.28.14", "typedoc-plugin-missing-exports": "^4.1.2", "typescript": "^5.8.3", @@ -114,7 +118,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", @@ -1720,7 +1723,6 @@ "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1792,6 +1794,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", @@ -2124,6 +2143,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -2145,6 +2165,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2161,6 +2182,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -2175,6 +2197,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -3645,6 +3668,23 @@ "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==", + "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": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/@vue/component-compiler/-/component-compiler-4.2.4.tgz", @@ -3725,6 +3765,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", @@ -3788,7 +3845,6 @@ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -4305,7 +4361,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -4396,6 +4451,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", @@ -4599,16 +4671,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" @@ -4626,17 +4695,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/" @@ -4880,6 +4948,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", @@ -4980,7 +5078,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", @@ -5234,7 +5333,6 @@ "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", @@ -5427,7 +5525,6 @@ "integrity": "sha512-MH6LK4xM6VVmmtz0nRE0Fe8l2jTKSYTvH1t0ZfbNLw3o6dlBCVTRqQha6uL8ZQVoMy74JyLguGwK7dU7rCKIhw==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", @@ -5479,6 +5576,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", @@ -5543,6 +5657,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", @@ -5655,6 +5786,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -5675,6 +5807,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -5892,7 +6025,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -6382,6 +6514,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", @@ -7201,6 +7346,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", @@ -7549,6 +7711,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", @@ -8221,6 +8400,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", @@ -8441,7 +8637,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -8814,6 +9009,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -8831,27 +9027,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==", - "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/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -9175,14 +9355,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", @@ -9340,6 +9519,16 @@ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" }, + "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", @@ -9390,6 +9579,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -9420,7 +9610,6 @@ "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -9502,17 +9691,49 @@ "@parcel/watcher": "^2.4.1" } }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/sdp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", - "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==", - "dev": true, - "license": "MIT" + "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", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/sdp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", + "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==", + "dev": true, + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -10140,6 +10361,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -10212,6 +10434,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -10347,7 +10570,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -10426,6 +10648,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", @@ -10433,6 +10671,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", @@ -10511,7 +11253,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10772,7 +11513,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 943ce0d03..3d4a389bf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "Blockbench", "description": "Low-poly modeling and animation software", - "version": "5.1.2", + "version": "5.1.3", "license": "GPL-3.0-or-later", "author": { "name": "JannisX11", @@ -144,7 +144,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" }, @@ -159,6 +159,8 @@ "@types/spectrum": "^1.8.7", "@types/three": "^0.129.2", "@types/tinycolor2": "^1.4.6", + "chalk": "^5.6.2", + "chokidar": "^5.0.0", "command-line-args": "^6.0.1", "concurrently": "^9.1.2", "dompurify": "^3.3.1", @@ -168,6 +170,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", "file-saver": "^2.0.5", "gifenc": "^1.0.3", "jquery": "^3.7.1", 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/desktop.d.ts b/types/custom/desktop.d.ts index 8ebfd5862..129086f5c 100644 --- a/types/custom/desktop.d.ts +++ b/types/custom/desktop.d.ts @@ -10,7 +10,9 @@ declare function openDefaultTexturePath(): void declare function createBackup(init: any): void declare function closeBlockbenchWindow(): any -type ScopedFS = Pick & { promises: Pick } interface RequireDialogOptions { @@ -61,6 +68,8 @@ declare function requireNativeModule(module: 'zlib'): typeof import("node:zlib") declare function requireNativeModule(module: 'timers'): typeof import("node:timers"); declare function requireNativeModule(module: 'url'): typeof import("node:url"); declare function requireNativeModule(module: 'string_decoder'): typeof import("node:string_decoder"); +declare function requireNativeModule(module: 'stream'): typeof import("node:stream"); +declare function requireNativeModule(module: 'perf_hooks'): typeof import("node:perf_hooks"); declare function requireNativeModule(module: 'querystring'): typeof import("node:querystring"); declare function requireNativeModule(module: 'child_process', options?: RequireDialogOptions): (typeof import("node:child_process")) | undefined; declare function requireNativeModule(module: 'electron', options?: RequireDialogOptions): (typeof import("node:electron")) | undefined; @@ -71,3 +80,4 @@ declare function requireNativeModule(module: 'util', options?: RequireDialogOpti declare function requireNativeModule(module: 'os', options?: RequireDialogOptions): (typeof import("node:os")) | undefined; declare function requireNativeModule(module: 'v8', options?: RequireDialogOptions): (typeof import("node:v8")) | undefined; declare function requireNativeModule(module: 'clipboard', options?: RequireDialogOptions): (import('electron').Clipboard) | undefined; +declare function requireNativeModule(module: 'shell', options?: RequireDialogOptions): (import('electron').Shell) | undefined; 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 +}