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
//! Substituting consumer values into a crate-owned asset template.
//!
//! Two kinds of asset in this module are templates rather than fixed files —
//! the Codex hook-plugin manifests ([`super::codex_app`]) and pi's gateway
//! extension ([`super::pi`]) — and they share one substitution rule because
//! the property they need is the same one: a rendered consumer value must
//! land in the output as *data*, never as syntax.
//!
//! Both templates spell a slot as a quoted placeholder, `"__TAPES_NAME__"`,
//! and [`render_slots`] replaces the placeholder *including its quotes* with a
//! complete escaped string literal. JSON and TypeScript agree on string
//! literal syntax closely enough for one escaper to serve both: JSON's grammar
//! (RFC 8259 §7) is a subset of ECMAScript's, so a valid JSON string literal
//! is a valid TypeScript string literal with the same value. That is why
//! [`string_literal`] is written once here instead of once per asset kind.
/// Replace every quoted slot occurrence with its escaped value, in one pass
/// over the template.
///
/// Substitution targets `"__SLOT__"` including its quotes and emits a
/// complete string literal, so escaping cannot be forgotten and a slot can
/// never be half-replaced inside a larger value. Single-pass is load-bearing,
/// not a micro-optimisation: only *template* text is ever scanned for slots,
/// and substituted values go straight to the output. A sequential per-slot
/// `replace` re-scans earlier insertions, so a value that merely *contains*
/// another slot's placeholder — pathological but consumer-controlled — would
/// itself get substituted. Here such a value passes through verbatim
/// (escaped), like every other value byte.
pub
/// `value` as a complete double-quoted string literal, quotes included.
///
/// Hand-rolled rather than `serde_json::to_string` because that API returns a
/// `Result` this crate would have to pretend can fail; for a `&str` it cannot,
/// and the escaping rules (RFC 8259 §7: `"` and `\` escaped, control
/// characters as `\u00XX`) are small enough to state directly.
///
/// The output is deliberately conservative for the TypeScript use: a backtick
/// or a `${` in a value is *not* escaped, and does not need to be, because a
/// double-quoted literal is not a template literal — inside these quotes both
/// are ordinary characters. What would break out is a bare `"`, a trailing
/// `\`, or a raw newline, and those are exactly what is escaped here.
pub