Problems with JSON/File Format?

I sent emails to the developer email address and never got responses. So I’ll post here in hopes that someone will have a method to figure out what’s going wrong…

On Mar 11, 2025, at 11:29 AM, Timothy Martin wrote:

I’m managing a Sketch Library that we have stored in Git and we decided to use a workflow that involves unzipping the file for storage for more efficient usage of Git, instead of relying on Git LFS.

Anyway, in that process I noticed that any update causes the entire JSON file to be replaced, and I believe that’s because they are minified. I used `js-beautify` after unzipping to create a human readable version of the JSON files, and assumed the software wouldn’t care. But if I rezip them up Sketch complains when trying to open the file with the following alert:

CleanShot 2025-03-11 at 11.28.39@2x

Furthermore, if i re-minify them it doesn’t seem to fix the error. So the process of beautifying must be doing something that Sketch isn’t happy about. I was wondering if there’s a way I could find out what’s causing this error?

Hello there and welcome to the forum,

I used `js-beautify` after unzipping to create a human readable version of the JSON files, and assumed the software wouldn’t care. But if I rezip them up Sketch complains when trying to open the file with the following alert:

This doesn’t seem right, I wonder what else in your setup/design files themselves could affect the resulting file. I’ve tried to recreate this workflow using the following Node script:

beautify-sketch.js
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const beautify = require('js-beautify');

function beautifySketchFile(inputFile) {
  const outputFile = inputFile.replace('.sketch', '-beautiful.sketch');
  const tempDir = './temp-sketch-extract';
  
  try {
    // Clean up any existing temp directory
    if (fs.existsSync(tempDir)) {
      fs.rmSync(tempDir, { recursive: true, force: true });
    }
    
    console.log('Extracting Sketch file...');
    fs.mkdirSync(tempDir, { recursive: true });
    
    // Unzip the sketch file
    execSync(`unzip -q "${inputFile}" -d "${tempDir}"`);
    
    console.log('Beautifying JSON files...');
    
    // Find all JSON files recursively
    function findJSONFiles(dir) {
      const files = [];
      const items = fs.readdirSync(dir, { withFileTypes: true });
      
      for (const item of items) {
        const fullPath = path.join(dir, item.name);
        if (item.isDirectory()) {
          files.push(...findJSONFiles(fullPath));
        } else if (item.isFile() && item.name.endsWith('.json')) {
          files.push(fullPath);
        }
      }
      
      return files;
    }
    
    const jsonFiles = findJSONFiles(tempDir);
    
    // Beautify each JSON file
    for (const jsonFile of jsonFiles) {
      try {
        const content = fs.readFileSync(jsonFile, 'utf8');
        const beautified = beautify(content, {
          indent_size: 2,
          space_in_empty_paren: true
        });
        fs.writeFileSync(jsonFile, beautified, 'utf8');
        console.log(`Beautified: ${path.relative(tempDir, jsonFile)}`);
      } catch (error) {
        console.warn(`Warning: Could not beautify ${jsonFile}: ${error.message}`);
      }
    }
    
    console.log('Repackaging Sketch file...');
    
    // Change to temp directory and zip contents
    process.chdir(tempDir);
    execSync(`zip -r "../${outputFile}" .`);
    process.chdir('..');
    
    // Clean up temp directory
    fs.rmSync(tempDir, { recursive: true, force: true });
    
    console.log(`Created beautified Sketch file: ${outputFile}`);
    
  } catch (error) {
    console.error('Error:', error.message);
    
    // Clean up on error
    if (fs.existsSync(tempDir)) {
      fs.rmSync(tempDir, { recursive: true, force: true });
    }
    
    process.exit(1);
  }
}

// Check if input file is provided
const inputFile = process.argv[2] || 'document.sketch';

if (!fs.existsSync(inputFile)) {
  console.error(`File not found: ${inputFile}`);
  process.exit(1);
}

if (!inputFile.endsWith('.sketch')) {
  console.error('Input file must be a .sketch file');
  process.exit(1);
}

console.log(`Beautifying Sketch file: ${inputFile}`);
beautifySketchFile(inputFile);

Calling it with

node beautify-sketch.js document.sketch

produces a valid Sketch document with beautified internals that opens without issues for me.