// @ts-check /** * PromptJS v1.0.0 — Compiler Codegen Utilities / Utilitas Codegen Kompilator * ============================================================================ * * v0.5 additions: * - VLQ encoding for source map generation * - generateSourceMap() — produces Source Map V3 JSON * * Basic codegen utilities separated from the main compiler. * Utilitas codegen dasar dipisah dari compiler utama. */ 'use strict'; /** * Context codegen — reference ke instance PromptJSCompiler. * * @typedef {Object} CodegenContext * @property {string[]} output - Array baris kode yang sedang di-emit * @property {number} indent - Level indentasi saat ini (0 = top-level) * @property {number} varCounter - Counter untuk generate nama variabel unik */ /** * Emit satu baris kode ke `ctx.output` dengan indentasi yang sesuai. * * Indentasi: 2 spasi per level (`ctx.indent`). * * @param {CodegenContext} ctx - Context compiler (instance PromptJSCompiler) * @param {string} code - Kode yang akan di-emit * @returns {void} */ function emit(ctx, code) { const spacing = ' '.repeat(ctx.indent || 0); ctx.output.push(spacing + code); } /** * Generate nama variabel unik dengan format `___`. * * Counter diincrement di `ctx.varCounter` setiap pemanggilan, sehingga * nama yang dihasilkan selalu unik dalam satu sesi kompilasi. * * @param {CodegenContext} ctx - Context compiler * @param {string} [prefix='v'] - Prefix nama variabel (mis. 'v', 'el', 'cb') * @returns {string} Nama variabel unik (mis. `__v_1`, `__el_2`) */ function genVar(ctx, prefix) { prefix = prefix || 'v'; ctx.varCounter = (ctx.varCounter || 0) + 1; return `__${prefix}_${ctx.varCounter}`; } /** * Escape nilai menjadi string literal JavaScript yang aman (dengan quote). * * Memakai `JSON.stringify` untuk konsistensi penanganan escape * (newlines, tabs, unicode, dll.), lalu memperketat dua celah yang TIDAK * ditangani `JSON.stringify` saat hasilnya disisipkan ke dalam sumber JS: * * 1. **U+2028 / U+2029** (LINE/PARAGRAPH SEPARATOR) — di-emit mentah oleh * `JSON.stringify`. Pada parser/bundler pra-ES2019 keduanya adalah * terminator baris dan akan memecah string literal. Di-escape menjadi * `\u2028` / `\u2029` agar aman di semua target. * 2. **`` HTML, substring `` menutup blok script lebih awal * (XSS klasik). Backslash disisipkan setelah `<` (`<\/script`, `<\!--`) * tanpa mengubah nilai string saat runtime. * * Fondasi keamanan bersama: dipakai ulang oleh guard auth (S-1) dan jalur * emit HTML (S-3) agar tidak ada nilai mentah yang dijahit ke output. * * @param {*} value - Nilai yang akan di-escape (akan dikonversi ke String dulu) * @returns {string} String literal JavaScript (mis. `"hello\nworld"`) */ function escapeString(value) { return JSON.stringify(String(value)) .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029') .replace(/<\/(script)/gi, '<\\/$1') .replace(/