File size: 5,823 Bytes
884b387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env node
/* split-src.mjs β€” μ•„ν‹°νŒ©νŠΈλ₯Ό 마컀 κΈ°μ€€μœΌλ‘œ 잘라 <unit>.src/ 파트 + manifest.txt λ₯Ό λ§Œλ“ λ‹€.
   Usage: node tools/split-src.mjs engine|app|all
   컷은 μ€„λ²ˆν˜Έκ°€ μ•„λ‹ˆλΌ **파일 μ•ˆμ—μ„œ μœ μΌν•œ 마컀 λ¬Έμžμ—΄**둜 작고, λ§ˆμ»€κ°€ μžˆλŠ” μ€„μ˜
   머리(byte offset)μ—μ„œ 자λ₯Έλ‹€. λ§ˆμ»€κ°€ 0νšŒκ±°λ‚˜ 2회 이상이면, λ˜λŠ” 파일 μˆœμ„œλŒ€λ‘œ
   μ¦κ°€ν•˜μ§€ μ•ŠμœΌλ©΄ ν•˜λ“œ μ‹€νŒ¨ν•œλ‹€ β€” 쑰용히 μ—‰λš±ν•œ 데λ₯Ό 자λ₯΄λŠ” 것보닀 λ‚«λ‹€.
   λ°”μ΄νŠΈ κ³΅κ°„μ—μ„œλ§Œ 닀룬닀(Buffer.indexOf): ν•œκΈ€ 주석이 λ§ˆμ»€μ— 듀어와도 UTF-16
   μ½”λ“œμœ λ‹› μ˜€ν”„μ…‹κ³Ό λ°”μ΄νŠΈ μ˜€ν”„μ…‹μ΄ μ–΄κΈ‹λ‚˜μ§€ μ•Šκ²Œ. */
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');

const SPEC = {
  engine: {
    out: 'engine.js',
    dir: 'engine.src',
    head: '000-shared-engine-body.js',
    cuts: [
      ['010-stones.js', '/* ============ STONES FIELD MODULE'],
      ['020-toll.js', '/* ============ TOLL FIELD MODULE'],
      ['030-downed.js', '/* ============ DOWNED FIELD MODULE'],
      ['040-log.js', '/* ============ LOG FIELD MODULE'],
      ['050-shared-removed-five.js', '/* ============ FIVE FIELD MODULES LEFT HERE'],
      ['060-statue.js', '/* ============ STATUE FIELD MODULE'],
      ['070-flood.js', '/* ============ FLOOD FIELD MODULE'],
      ['080-carry.js', '/* ============ CARRY FIELD MODULE'],
      ['090-ledge.js', '/* ============ LEDGE FIELD MODULE'],
      ['100-relay.js', '/* ============ RELAY FIELD MODULE'],
      ['110-fire.js', '/* ============ FIRE FIELD MODULE'],
      ['120-tower.js', '/* ============ TOWER FIELD MODULE'],
      ['130-bomb.js', '/* ============ BOMB FIELD MODULE'],
      ['140-shared-removed-bomb2.js', '/* ============ BOMB2 (y22) LEFT ON'],
      ['150-lantern.js', '/* ============ LANTERN FIELD MODULE'],
      ['160-yield.js', '/* ============ YIELD FIELD MODULE'],
      ['170-siege.js', '/* ============ SIEGE FIELD MODULE'],
      ['180-escape.js', '/* ============ ESCAPE FIELD MODULE'],
      ['190-alley.js', '/* ============ ALLEY FIELD MODULE'],
      ['200-beacon.js', '/* ============ BEACON FIELD MODULE'],
      ['210-burst.js', '/* ============ BURST FIELD MODULE'],
      ['220-shared-removed-shifter.js', '/* ============ SHIFTER (y54) LEFT ON'],
      ['230-road.js', '/* ============ ROAD FIELD MODULE'],
      ['240-plaza.js', '/* ============ PLAZA FIELD MODULE'],
      ['250-shared-exports-tail.js', '/* ================================ EXPORTS =========='],
    ],
  },
  app: {
    out: 'app.js',
    dir: 'app.src',
    head: '000-shared-app-body.js',
    cuts: [
      ['010-stones.js', '// y12 STONES FIELD LAYER'],
      ['020-toll.js', '// y14 TOLL FIELD LAYER'],
      ['030-downed.js', '// y3 DOWNED FIELD LAYER'],
      ['040-log.js', '// y8 ROLLING-LOG FIELD LAYER'],
      ['050-alley-bull.js', '// THE BULL FIELD LAYER'],
      ['060-statue.js', '// y29 STATUE FIELD LAYER'],
      ['070-relay.js', '// y31 RELAY FIELD LAYER'],
      ['080-flood.js', '// y10 RISING-WATER FIELD LAYER'],
      ['090-shared-post-registry.js', '// WHY A SECOND REGISTRY RATHER THAN A FLAG ON THE FIRST'],
      ['100-lantern.js', '// y24 LANTERN FIELD LAYER'],
      ['110-statue-live.js', '// y29 THE GLOW AND THE POST'],
      ['120-siege.js', '// ---- y46 v2 THE FOUR SEATS'],
      ['130-alley.js', '// y50 ALLEY FIELD LAYER'],
      ['140-escape.js', '// ---- y51 ESCAPE: the two glyph primitives'],
      ['150-beacon.js', '/* y53 BEACON FIELD LAYER'],
      ['160-burst.js', '/* y52 BURST FIELD LAYER'],
      ['170-shared-removed-shifter.js', '/* y54 SHIFTER FIELD LAYER'],
      ['180-carry.js', '// y16 CARRY FIELD LAYER'],
      ['190-ledge.js', '// y26 LEDGE FIELD LAYER'],
      ['200-fire.js', '// y17 FIRE FIELD LAYER'],
      ['210-tower.js', '// y19 TOWER FIELD LAYER'],
      ['220-bomb.js', '// y20 BOMB FIELD LAYER'],
      ['230-flood-storm.js', '// y23 STORM FIELD LAYER'],
      ['240-yield.js', '// y33 YIELD FIELD LAYER'],
      ['250-road.js', '/* y58 흐λ₯΄λŠ” λ„λ‘œ FIELD LAYER'],
      ['260-plaza.js', '/* y59 PLAZA FIELD LAYER'],
      ['270-shared-app-tail.js', '// P13 PUSH VERB LAYER'],
    ],
  },
};

function split(key) {
  const unit = SPEC[key];
  const src = fs.readFileSync(path.join(ROOT, unit.out));
  const bounds = [];
  let prev = 0;
  for (const [name, marker] of unit.cuts) {
    const m = Buffer.from(marker, 'utf8');
    const i = src.indexOf(m);
    if (i < 0) throw new Error(`[${key}] 마컀λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€: ${marker}`);
    if (i !== src.lastIndexOf(m)) throw new Error(`[${key}] λ§ˆμ»€κ°€ μœ μΌν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€: ${marker}`);
    const start = src.lastIndexOf(0x0a, i) + 1;   // 쀄 λ¨Έλ¦¬μ—μ„œ 자λ₯Έλ‹€
    if (start <= prev) throw new Error(`[${key}] 마컀 μˆœμ„œκ°€ 파일 μˆœμ„œμ™€ μ–΄κΈ‹λ‚©λ‹ˆλ‹€: ${marker}`);
    bounds.push([name, start]);
    prev = start;
  }
  const dir = path.join(ROOT, unit.dir);
  fs.mkdirSync(dir, { recursive: true });
  const names = [unit.head, ...bounds.map(([n]) => n)];
  const offs = [0, ...bounds.map(([, s]) => s), src.length];
  for (let k = 0; k < names.length; k++) {
    fs.writeFileSync(path.join(dir, names[k]), src.subarray(offs[k], offs[k + 1]));
  }
  fs.writeFileSync(path.join(dir, 'manifest.txt'), names.join('\n') + '\n');
  const total = names.reduce((a, n) => a + fs.statSync(path.join(dir, n)).size, 0);
  console.log(`${unit.dir}: ${names.length} parts, ${total} bytes (artifact ${src.length} bytes)`);
  if (total !== src.length) throw new Error(`[${key}] 파트 합계가 μ•„ν‹°νŒ©νŠΈμ™€ λ‹€λ¦…λ‹ˆλ‹€`);
}

const arg = process.argv[2] || 'all';
for (const key of arg === 'all' ? Object.keys(SPEC) : [arg]) split(key);