I have integrated krzysztofzablocki/Inject into my new SwiftUI Project and it was astonishing.

I don’t know how exactly working inside the box, but Inject drove me a feeling like developing a React application(or any other hot-reloadable framework?).

I wrote this post for sharing my script to inject the code snippets for each swift file and View required by Inject.

Happy Coding! XD

#!/usr/bin/env zx  
/* eslint-disable max-len */  
// region ZX Util  
import { glob, path, fs } from 'zx';  
  
const filename = path.basename(__filename);  
const _printTag = '' || filename;  
  
function printSuccess (...args) {  
  echo(chalk.bold.bgBlue(`[${_printTag}]`, ...args));  
}  
  
// endregion  
  
async function main () {  
  const projectRoot = './pill_mate';  
  const swiftFiles = await glob(`${projectRoot}/**/*.swift`);  
  
  for (const filepath of swiftFiles) {  
    const filename = path.basename(filepath);  
    const content = await fs.readFile(filepath, 'utf8');  
  
    // Skip if not a SwiftUI View  
    if (!content.includes(': View {') || content.includes('no-inject')) {  
      // print(`Skipping: ${filename} (No ': View {' found)`);  
      continue;  
    }  
  
    let modified = content;  
    let changed = false;  
  
    // 2. Add `@ObserveInjection var inject` if missing  
    {  
      const lines = modified.split('\n');  
      let changedThisFile = false;  
  
      for (let i = 0; i < lines.length; i++) {  
        if (/struct\s+\w+.*?:\s*View\s*{/s.test(lines[i])) {  
          let braceCount = 0;  
          let blockStart = i;  
          let blockEnd = -1;  
  
          for (let j = i; j < lines.length; j++) {  
            const open = (lines[j].match(/{/g) || []).length;  
            const close = (lines[j].match(/}/g) || []).length;  
            braceCount += open - close;  
  
            if (braceCount === 0) {  
              blockEnd = j;  
              break;  
            }  
          }  
  
          if (blockEnd !== -1) {  
            const blockLines = lines.slice(blockStart, blockEnd + 1);  
            const hasInject = blockLines.some(line => line.includes('@ObserveInjection var inject'));  
  
            if (!hasInject) {  
              lines.splice(blockStart + 1, 0, '    @ObserveInjection var inject');  
              changedThisFile = true;  
              i = blockEnd + 1;  
            }  
          }  
        }  
      }  
      if (changedThisFile) {  
        modified = lines.join('\n');  
        changed = true;  
      }  
    }  
  
    // 3. Add `.enableInjection()` before closing brace of `var body`  
    {  
      const lines = modified.split('\n');  
      let changedThisFile = false;  
  
      for (let i = 0; i < lines.length; i++) {  
        if (  
          /var\s+[_\w\d]+\s*:\s*some\s+View\s*{/.test(lines[i]) ||  
          /->\s*some\s+View\s*{/.test(lines[i])  
        ) {  
          let braceCount = 0;  
          let bodyEndIdx = -1;  
  
          for (let j = i; j < lines.length; j++) {  
            const open = (lines[j].match(/{/g) || []).length;  
            const close = (lines[j].match(/}/g) || []).length;  
            braceCount += open - close;  
  
            if (braceCount === 0) {  
              bodyEndIdx = j;  
              break;  
            }  
          }  
  
          if (bodyEndIdx !== -1) {  
            const blockLines = lines.slice(i, bodyEndIdx + 1);  
            if (!blockLines.some(line => line.includes('.enableInjection()'))) {  
              lines.splice(bodyEndIdx, 0, '        .enableInjection()');  
              changedThisFile = true;  
              i = bodyEndIdx + 1;  
            }  
          }  
        }  
      }  
      if (changedThisFile) {  
        modified = lines.join('\n');  
        changed = true;  
      }  
    }  
  
    // Overwrite file if modified  
    if (changed) {  
      await fs.writeFile(filepath, modified);  
      printSuccess(`Modified: ${filename}`);  
    } else {  
      // console.log(`No changes for: ${filename}`);  
    }  
  }  
  printSuccess('Inject modification script completed.');  
};  
main();

Categories:

Updated:

Comments