@funkai/cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +15 -16
- package/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/.turbo/turbo-test$colon$coverage.log +0 -36
- package/.turbo/turbo-test.log +0 -26
- package/.turbo/turbo-typecheck.log +0 -4
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/commands/create.ts.html +0 -208
- package/coverage/lcov-report/commands/generate.ts.html +0 -388
- package/coverage/lcov-report/commands/index.html +0 -161
- package/coverage/lcov-report/commands/lint.ts.html +0 -331
- package/coverage/lcov-report/commands/setup.ts.html +0 -493
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/lib/codegen.ts.html +0 -805
- package/coverage/lcov-report/lib/extract-variables.ts.html +0 -181
- package/coverage/lcov-report/lib/flatten.ts.html +0 -385
- package/coverage/lcov-report/lib/frontmatter.ts.html +0 -487
- package/coverage/lcov-report/lib/index.html +0 -191
- package/coverage/lcov-report/lib/lint.ts.html +0 -307
- package/coverage/lcov-report/lib/paths.ts.html +0 -487
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -749
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<!doctype html>
|
|
3
|
-
<html lang="en">
|
|
4
|
-
|
|
5
|
-
<head>
|
|
6
|
-
<title>Code coverage report for lib/extract-variables.ts</title>
|
|
7
|
-
<meta charset="utf-8" />
|
|
8
|
-
<link rel="stylesheet" href="../prettify.css" />
|
|
9
|
-
<link rel="stylesheet" href="../base.css" />
|
|
10
|
-
<link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
|
|
11
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
-
<style type='text/css'>
|
|
13
|
-
.coverage-summary .sorter {
|
|
14
|
-
background-image: url(../sort-arrow-sprite.png);
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
17
|
-
</head>
|
|
18
|
-
|
|
19
|
-
<body>
|
|
20
|
-
<div class='wrapper'>
|
|
21
|
-
<div class='pad1'>
|
|
22
|
-
<h1><a href="../index.html">All files</a> / <a href="index.html">lib</a> extract-variables.ts</h1>
|
|
23
|
-
<div class='clearfix'>
|
|
24
|
-
|
|
25
|
-
<div class='fl pad1y space-right2'>
|
|
26
|
-
<span class="strong">100% </span>
|
|
27
|
-
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>10/10</span>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<div class='fl pad1y space-right2'>
|
|
33
|
-
<span class="strong">75% </span>
|
|
34
|
-
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>3/4</span>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<div class='fl pad1y space-right2'>
|
|
40
|
-
<span class="strong">100% </span>
|
|
41
|
-
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>2/2</span>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<div class='fl pad1y space-right2'>
|
|
47
|
-
<span class="strong">100% </span>
|
|
48
|
-
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>10/10</span>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</div>
|
|
54
|
-
<p class="quiet">
|
|
55
|
-
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
-
</p>
|
|
57
|
-
<template id="filterTemplate">
|
|
58
|
-
<div class="quiet">
|
|
59
|
-
Filter:
|
|
60
|
-
<input type="search" id="fileSearch">
|
|
61
|
-
</div>
|
|
62
|
-
</template>
|
|
63
|
-
</div>
|
|
64
|
-
<div class='status-line high'></div>
|
|
65
|
-
<pre><table class="coverage">
|
|
66
|
-
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
-
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
-
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
-
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
-
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
-
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
-
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
-
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
-
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
-
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
-
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
-
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
-
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
-
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
-
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
-
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
-
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
-
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
-
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
-
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
-
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
-
<a name='L22'></a><a href='#L22'>22</a>
|
|
88
|
-
<a name='L23'></a><a href='#L23'>23</a>
|
|
89
|
-
<a name='L24'></a><a href='#L24'>24</a>
|
|
90
|
-
<a name='L25'></a><a href='#L25'>25</a>
|
|
91
|
-
<a name='L26'></a><a href='#L26'>26</a>
|
|
92
|
-
<a name='L27'></a><a href='#L27'>27</a>
|
|
93
|
-
<a name='L28'></a><a href='#L28'>28</a>
|
|
94
|
-
<a name='L29'></a><a href='#L29'>29</a>
|
|
95
|
-
<a name='L30'></a><a href='#L30'>30</a>
|
|
96
|
-
<a name='L31'></a><a href='#L31'>31</a>
|
|
97
|
-
<a name='L32'></a><a href='#L32'>32</a>
|
|
98
|
-
<a name='L33'></a><a href='#L33'>33</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
99
|
-
<span class="cline-any cline-neutral"> </span>
|
|
100
|
-
<span class="cline-any cline-yes">1x</span>
|
|
101
|
-
<span class="cline-any cline-neutral"> </span>
|
|
102
|
-
<span class="cline-any cline-neutral"> </span>
|
|
103
|
-
<span class="cline-any cline-neutral"> </span>
|
|
104
|
-
<span class="cline-any cline-neutral"> </span>
|
|
105
|
-
<span class="cline-any cline-neutral"> </span>
|
|
106
|
-
<span class="cline-any cline-neutral"> </span>
|
|
107
|
-
<span class="cline-any cline-neutral"> </span>
|
|
108
|
-
<span class="cline-any cline-neutral"> </span>
|
|
109
|
-
<span class="cline-any cline-neutral"> </span>
|
|
110
|
-
<span class="cline-any cline-neutral"> </span>
|
|
111
|
-
<span class="cline-any cline-neutral"> </span>
|
|
112
|
-
<span class="cline-any cline-yes">11x</span>
|
|
113
|
-
<span class="cline-any cline-yes">11x</span>
|
|
114
|
-
<span class="cline-any cline-yes">11x</span>
|
|
115
|
-
<span class="cline-any cline-neutral"> </span>
|
|
116
|
-
<span class="cline-any cline-yes">11x</span>
|
|
117
|
-
<span class="cline-any cline-neutral"> </span>
|
|
118
|
-
<span class="cline-any cline-yes">12x</span>
|
|
119
|
-
<span class="cline-any cline-neutral"> </span>
|
|
120
|
-
<span class="cline-any cline-yes">12x</span>
|
|
121
|
-
<span class="cline-any cline-yes">3x</span>
|
|
122
|
-
<span class="cline-any cline-neutral"> </span>
|
|
123
|
-
<span class="cline-any cline-neutral"> </span>
|
|
124
|
-
<span class="cline-any cline-yes">9x</span>
|
|
125
|
-
<span class="cline-any cline-neutral"> </span>
|
|
126
|
-
<span class="cline-any cline-neutral"> </span>
|
|
127
|
-
<span class="cline-any cline-neutral"> </span>
|
|
128
|
-
<span class="cline-any cline-yes">11x</span>
|
|
129
|
-
<span class="cline-any cline-neutral"> </span>
|
|
130
|
-
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">import { Liquid } from "liquidjs";
|
|
131
|
-
|
|
132
|
-
const DANGEROUS_NAMES = new Set(["constructor", "__proto__", "prototype"]);
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Extract top-level variable names from a Liquid template string.
|
|
136
|
-
*
|
|
137
|
-
* Uses LiquidJS's built-in `variablesSync` to parse the template AST
|
|
138
|
-
* and extract all referenced variable names. Only returns the root
|
|
139
|
-
* variable name (e.g. `user` from `{{ user.name }}`).
|
|
140
|
-
*
|
|
141
|
-
* @throws {Error} If a variable name is dangerous (e.g. `__proto__`)
|
|
142
|
-
*/
|
|
143
|
-
export function extractVariables(template: string): string[] {
|
|
144
|
-
const engine = new Liquid();
|
|
145
|
-
const parsed = engine.parse(template);
|
|
146
|
-
const variables = engine.variablesSync(parsed);
|
|
147
|
-
|
|
148
|
-
const roots = new Set(
|
|
149
|
-
variables.map((variable) => {
|
|
150
|
-
const root = Array.isArray(variable) ? <span class="branch-0 cbranch-no" title="branch not covered" >String(variable[0]) : S</span>tring(variable);
|
|
151
|
-
|
|
152
|
-
if (DANGEROUS_NAMES.has(root)) {
|
|
153
|
-
throw new Error(`Dangerous variable name "${root}" is not allowed in prompt templates`);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return root;
|
|
157
|
-
}),
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
return [...roots].toSorted();
|
|
161
|
-
}
|
|
162
|
-
</pre></td></tr></table></pre>
|
|
163
|
-
|
|
164
|
-
<div class='push'></div><!-- for sticky footer -->
|
|
165
|
-
</div><!-- /wrapper -->
|
|
166
|
-
<div class='footer quiet pad2 space-top1 center small'>
|
|
167
|
-
Code coverage generated by
|
|
168
|
-
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
169
|
-
at 2026-03-13T00:28:56.897Z
|
|
170
|
-
</div>
|
|
171
|
-
<script src="../prettify.js"></script>
|
|
172
|
-
<script>
|
|
173
|
-
window.onload = function () {
|
|
174
|
-
prettyPrint();
|
|
175
|
-
};
|
|
176
|
-
</script>
|
|
177
|
-
<script src="../sorter.js"></script>
|
|
178
|
-
<script src="../block-navigation.js"></script>
|
|
179
|
-
</body>
|
|
180
|
-
</html>
|
|
181
|
-
|
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
<!doctype html>
|
|
3
|
-
<html lang="en">
|
|
4
|
-
|
|
5
|
-
<head>
|
|
6
|
-
<title>Code coverage report for lib/flatten.ts</title>
|
|
7
|
-
<meta charset="utf-8" />
|
|
8
|
-
<link rel="stylesheet" href="../prettify.css" />
|
|
9
|
-
<link rel="stylesheet" href="../base.css" />
|
|
10
|
-
<link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
|
|
11
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
-
<style type='text/css'>
|
|
13
|
-
.coverage-summary .sorter {
|
|
14
|
-
background-image: url(../sort-arrow-sprite.png);
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
17
|
-
</head>
|
|
18
|
-
|
|
19
|
-
<body>
|
|
20
|
-
<div class='wrapper'>
|
|
21
|
-
<div class='pad1'>
|
|
22
|
-
<h1><a href="../index.html">All files</a> / <a href="index.html">lib</a> flatten.ts</h1>
|
|
23
|
-
<div class='clearfix'>
|
|
24
|
-
|
|
25
|
-
<div class='fl pad1y space-right2'>
|
|
26
|
-
<span class="strong">100% </span>
|
|
27
|
-
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>34/34</span>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<div class='fl pad1y space-right2'>
|
|
33
|
-
<span class="strong">100% </span>
|
|
34
|
-
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>4/4</span>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<div class='fl pad1y space-right2'>
|
|
40
|
-
<span class="strong">100% </span>
|
|
41
|
-
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>11/11</span>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<div class='fl pad1y space-right2'>
|
|
47
|
-
<span class="strong">100% </span>
|
|
48
|
-
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>32/32</span>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</div>
|
|
54
|
-
<p class="quiet">
|
|
55
|
-
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
-
</p>
|
|
57
|
-
<template id="filterTemplate">
|
|
58
|
-
<div class="quiet">
|
|
59
|
-
Filter:
|
|
60
|
-
<input type="search" id="fileSearch">
|
|
61
|
-
</div>
|
|
62
|
-
</template>
|
|
63
|
-
</div>
|
|
64
|
-
<div class='status-line high'></div>
|
|
65
|
-
<pre><table class="coverage">
|
|
66
|
-
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
-
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
-
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
-
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
-
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
-
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
-
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
-
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
-
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
-
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
-
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
-
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
-
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
-
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
-
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
-
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
-
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
-
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
-
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
-
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
-
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
-
<a name='L22'></a><a href='#L22'>22</a>
|
|
88
|
-
<a name='L23'></a><a href='#L23'>23</a>
|
|
89
|
-
<a name='L24'></a><a href='#L24'>24</a>
|
|
90
|
-
<a name='L25'></a><a href='#L25'>25</a>
|
|
91
|
-
<a name='L26'></a><a href='#L26'>26</a>
|
|
92
|
-
<a name='L27'></a><a href='#L27'>27</a>
|
|
93
|
-
<a name='L28'></a><a href='#L28'>28</a>
|
|
94
|
-
<a name='L29'></a><a href='#L29'>29</a>
|
|
95
|
-
<a name='L30'></a><a href='#L30'>30</a>
|
|
96
|
-
<a name='L31'></a><a href='#L31'>31</a>
|
|
97
|
-
<a name='L32'></a><a href='#L32'>32</a>
|
|
98
|
-
<a name='L33'></a><a href='#L33'>33</a>
|
|
99
|
-
<a name='L34'></a><a href='#L34'>34</a>
|
|
100
|
-
<a name='L35'></a><a href='#L35'>35</a>
|
|
101
|
-
<a name='L36'></a><a href='#L36'>36</a>
|
|
102
|
-
<a name='L37'></a><a href='#L37'>37</a>
|
|
103
|
-
<a name='L38'></a><a href='#L38'>38</a>
|
|
104
|
-
<a name='L39'></a><a href='#L39'>39</a>
|
|
105
|
-
<a name='L40'></a><a href='#L40'>40</a>
|
|
106
|
-
<a name='L41'></a><a href='#L41'>41</a>
|
|
107
|
-
<a name='L42'></a><a href='#L42'>42</a>
|
|
108
|
-
<a name='L43'></a><a href='#L43'>43</a>
|
|
109
|
-
<a name='L44'></a><a href='#L44'>44</a>
|
|
110
|
-
<a name='L45'></a><a href='#L45'>45</a>
|
|
111
|
-
<a name='L46'></a><a href='#L46'>46</a>
|
|
112
|
-
<a name='L47'></a><a href='#L47'>47</a>
|
|
113
|
-
<a name='L48'></a><a href='#L48'>48</a>
|
|
114
|
-
<a name='L49'></a><a href='#L49'>49</a>
|
|
115
|
-
<a name='L50'></a><a href='#L50'>50</a>
|
|
116
|
-
<a name='L51'></a><a href='#L51'>51</a>
|
|
117
|
-
<a name='L52'></a><a href='#L52'>52</a>
|
|
118
|
-
<a name='L53'></a><a href='#L53'>53</a>
|
|
119
|
-
<a name='L54'></a><a href='#L54'>54</a>
|
|
120
|
-
<a name='L55'></a><a href='#L55'>55</a>
|
|
121
|
-
<a name='L56'></a><a href='#L56'>56</a>
|
|
122
|
-
<a name='L57'></a><a href='#L57'>57</a>
|
|
123
|
-
<a name='L58'></a><a href='#L58'>58</a>
|
|
124
|
-
<a name='L59'></a><a href='#L59'>59</a>
|
|
125
|
-
<a name='L60'></a><a href='#L60'>60</a>
|
|
126
|
-
<a name='L61'></a><a href='#L61'>61</a>
|
|
127
|
-
<a name='L62'></a><a href='#L62'>62</a>
|
|
128
|
-
<a name='L63'></a><a href='#L63'>63</a>
|
|
129
|
-
<a name='L64'></a><a href='#L64'>64</a>
|
|
130
|
-
<a name='L65'></a><a href='#L65'>65</a>
|
|
131
|
-
<a name='L66'></a><a href='#L66'>66</a>
|
|
132
|
-
<a name='L67'></a><a href='#L67'>67</a>
|
|
133
|
-
<a name='L68'></a><a href='#L68'>68</a>
|
|
134
|
-
<a name='L69'></a><a href='#L69'>69</a>
|
|
135
|
-
<a name='L70'></a><a href='#L70'>70</a>
|
|
136
|
-
<a name='L71'></a><a href='#L71'>71</a>
|
|
137
|
-
<a name='L72'></a><a href='#L72'>72</a>
|
|
138
|
-
<a name='L73'></a><a href='#L73'>73</a>
|
|
139
|
-
<a name='L74'></a><a href='#L74'>74</a>
|
|
140
|
-
<a name='L75'></a><a href='#L75'>75</a>
|
|
141
|
-
<a name='L76'></a><a href='#L76'>76</a>
|
|
142
|
-
<a name='L77'></a><a href='#L77'>77</a>
|
|
143
|
-
<a name='L78'></a><a href='#L78'>78</a>
|
|
144
|
-
<a name='L79'></a><a href='#L79'>79</a>
|
|
145
|
-
<a name='L80'></a><a href='#L80'>80</a>
|
|
146
|
-
<a name='L81'></a><a href='#L81'>81</a>
|
|
147
|
-
<a name='L82'></a><a href='#L82'>82</a>
|
|
148
|
-
<a name='L83'></a><a href='#L83'>83</a>
|
|
149
|
-
<a name='L84'></a><a href='#L84'>84</a>
|
|
150
|
-
<a name='L85'></a><a href='#L85'>85</a>
|
|
151
|
-
<a name='L86'></a><a href='#L86'>86</a>
|
|
152
|
-
<a name='L87'></a><a href='#L87'>87</a>
|
|
153
|
-
<a name='L88'></a><a href='#L88'>88</a>
|
|
154
|
-
<a name='L89'></a><a href='#L89'>89</a>
|
|
155
|
-
<a name='L90'></a><a href='#L90'>90</a>
|
|
156
|
-
<a name='L91'></a><a href='#L91'>91</a>
|
|
157
|
-
<a name='L92'></a><a href='#L92'>92</a>
|
|
158
|
-
<a name='L93'></a><a href='#L93'>93</a>
|
|
159
|
-
<a name='L94'></a><a href='#L94'>94</a>
|
|
160
|
-
<a name='L95'></a><a href='#L95'>95</a>
|
|
161
|
-
<a name='L96'></a><a href='#L96'>96</a>
|
|
162
|
-
<a name='L97'></a><a href='#L97'>97</a>
|
|
163
|
-
<a name='L98'></a><a href='#L98'>98</a>
|
|
164
|
-
<a name='L99'></a><a href='#L99'>99</a>
|
|
165
|
-
<a name='L100'></a><a href='#L100'>100</a>
|
|
166
|
-
<a name='L101'></a><a href='#L101'>101</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
167
|
-
<span class="cline-any cline-neutral"> </span>
|
|
168
|
-
<span class="cline-any cline-neutral"> </span>
|
|
169
|
-
<span class="cline-any cline-neutral"> </span>
|
|
170
|
-
<span class="cline-any cline-yes">1x</span>
|
|
171
|
-
<span class="cline-any cline-yes">1x</span>
|
|
172
|
-
<span class="cline-any cline-neutral"> </span>
|
|
173
|
-
<span class="cline-any cline-neutral"> </span>
|
|
174
|
-
<span class="cline-any cline-neutral"> </span>
|
|
175
|
-
<span class="cline-any cline-neutral"> </span>
|
|
176
|
-
<span class="cline-any cline-neutral"> </span>
|
|
177
|
-
<span class="cline-any cline-neutral"> </span>
|
|
178
|
-
<span class="cline-any cline-neutral"> </span>
|
|
179
|
-
<span class="cline-any cline-neutral"> </span>
|
|
180
|
-
<span class="cline-any cline-neutral"> </span>
|
|
181
|
-
<span class="cline-any cline-neutral"> </span>
|
|
182
|
-
<span class="cline-any cline-neutral"> </span>
|
|
183
|
-
<span class="cline-any cline-neutral"> </span>
|
|
184
|
-
<span class="cline-any cline-neutral"> </span>
|
|
185
|
-
<span class="cline-any cline-neutral"> </span>
|
|
186
|
-
<span class="cline-any cline-yes">18x</span>
|
|
187
|
-
<span class="cline-any cline-yes">18x</span>
|
|
188
|
-
<span class="cline-any cline-neutral"> </span>
|
|
189
|
-
<span class="cline-any cline-yes">35x</span>
|
|
190
|
-
<span class="cline-any cline-neutral"> </span>
|
|
191
|
-
<span class="cline-any cline-yes">18x</span>
|
|
192
|
-
<span class="cline-any cline-yes">46x</span>
|
|
193
|
-
<span class="cline-any cline-yes">33x</span>
|
|
194
|
-
<span class="cline-any cline-yes">3x</span>
|
|
195
|
-
<span class="cline-any cline-neutral"> </span>
|
|
196
|
-
<span class="cline-any cline-neutral"> </span>
|
|
197
|
-
<span class="cline-any cline-neutral"> </span>
|
|
198
|
-
<span class="cline-any cline-neutral"> </span>
|
|
199
|
-
<span class="cline-any cline-neutral"> </span>
|
|
200
|
-
<span class="cline-any cline-yes">30x</span>
|
|
201
|
-
<span class="cline-any cline-neutral"> </span>
|
|
202
|
-
<span class="cline-any cline-neutral"> </span>
|
|
203
|
-
<span class="cline-any cline-yes">15x</span>
|
|
204
|
-
<span class="cline-any cline-neutral"> </span>
|
|
205
|
-
<span class="cline-any cline-neutral"> </span>
|
|
206
|
-
<span class="cline-any cline-neutral"> </span>
|
|
207
|
-
<span class="cline-any cline-neutral"> </span>
|
|
208
|
-
<span class="cline-any cline-neutral"> </span>
|
|
209
|
-
<span class="cline-any cline-neutral"> </span>
|
|
210
|
-
<span class="cline-any cline-yes">27x</span>
|
|
211
|
-
<span class="cline-any cline-neutral"> </span>
|
|
212
|
-
<span class="cline-any cline-yes">27x</span>
|
|
213
|
-
<span class="cline-any cline-yes">22x</span>
|
|
214
|
-
<span class="cline-any cline-yes">22x</span>
|
|
215
|
-
<span class="cline-any cline-yes">22x</span>
|
|
216
|
-
<span class="cline-any cline-yes">18x</span>
|
|
217
|
-
<span class="cline-any cline-yes">4x</span>
|
|
218
|
-
<span class="cline-any cline-yes">22x</span>
|
|
219
|
-
<span class="cline-any cline-yes">18x</span>
|
|
220
|
-
<span class="cline-any cline-yes">4x</span>
|
|
221
|
-
<span class="cline-any cline-neutral"> </span>
|
|
222
|
-
<span class="cline-any cline-yes">22x</span>
|
|
223
|
-
<span class="cline-any cline-neutral"> </span>
|
|
224
|
-
<span class="cline-any cline-neutral"> </span>
|
|
225
|
-
<span class="cline-any cline-yes">24x</span>
|
|
226
|
-
<span class="cline-any cline-neutral"> </span>
|
|
227
|
-
<span class="cline-any cline-neutral"> </span>
|
|
228
|
-
<span class="cline-any cline-neutral"> </span>
|
|
229
|
-
<span class="cline-any cline-neutral"> </span>
|
|
230
|
-
<span class="cline-any cline-neutral"> </span>
|
|
231
|
-
<span class="cline-any cline-neutral"> </span>
|
|
232
|
-
<span class="cline-any cline-neutral"> </span>
|
|
233
|
-
<span class="cline-any cline-neutral"> </span>
|
|
234
|
-
<span class="cline-any cline-neutral"> </span>
|
|
235
|
-
<span class="cline-any cline-neutral"> </span>
|
|
236
|
-
<span class="cline-any cline-neutral"> </span>
|
|
237
|
-
<span class="cline-any cline-neutral"> </span>
|
|
238
|
-
<span class="cline-any cline-neutral"> </span>
|
|
239
|
-
<span class="cline-any cline-neutral"> </span>
|
|
240
|
-
<span class="cline-any cline-neutral"> </span>
|
|
241
|
-
<span class="cline-any cline-neutral"> </span>
|
|
242
|
-
<span class="cline-any cline-neutral"> </span>
|
|
243
|
-
<span class="cline-any cline-yes">27x</span>
|
|
244
|
-
<span class="cline-any cline-yes">27x</span>
|
|
245
|
-
<span class="cline-any cline-yes">6x</span>
|
|
246
|
-
<span class="cline-any cline-neutral"> </span>
|
|
247
|
-
<span class="cline-any cline-neutral"> </span>
|
|
248
|
-
<span class="cline-any cline-yes">18x</span>
|
|
249
|
-
<span class="cline-any cline-neutral"> </span>
|
|
250
|
-
<span class="cline-any cline-neutral"> </span>
|
|
251
|
-
<span class="cline-any cline-neutral"> </span>
|
|
252
|
-
<span class="cline-any cline-neutral"> </span>
|
|
253
|
-
<span class="cline-any cline-neutral"> </span>
|
|
254
|
-
<span class="cline-any cline-yes">18x</span>
|
|
255
|
-
<span class="cline-any cline-yes">19x</span>
|
|
256
|
-
<span class="cline-any cline-neutral"> </span>
|
|
257
|
-
<span class="cline-any cline-yes">29x</span>
|
|
258
|
-
<span class="cline-any cline-neutral"> </span>
|
|
259
|
-
<span class="cline-any cline-neutral"> </span>
|
|
260
|
-
<span class="cline-any cline-neutral"> </span>
|
|
261
|
-
<span class="cline-any cline-yes">19x</span>
|
|
262
|
-
<span class="cline-any cline-neutral"> </span>
|
|
263
|
-
<span class="cline-any cline-neutral"> </span>
|
|
264
|
-
<span class="cline-any cline-yes">18x</span>
|
|
265
|
-
<span class="cline-any cline-neutral"> </span>
|
|
266
|
-
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">import { Liquid } from "liquidjs";
|
|
267
|
-
import { match } from "ts-pattern";
|
|
268
|
-
|
|
269
|
-
// oxlint-disable-next-line security/detect-unsafe-regex -- template parsing, not adversarial input
|
|
270
|
-
const RENDER_TAG_RE = /\{%-?\s*render\s+'([^']+)'(?:\s*,\s*(.*?))?\s*-?%\}/g;
|
|
271
|
-
const LITERAL_PARAM_RE = /(\w+)\s*:\s*'([^']*)'/g;
|
|
272
|
-
|
|
273
|
-
interface RenderTag {
|
|
274
|
-
fullMatch: string;
|
|
275
|
-
partialName: string;
|
|
276
|
-
params: Record<string, string>;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Parse literal string parameters from a render tag's param string.
|
|
281
|
-
*
|
|
282
|
-
* Only supports literal string values (e.g. `role: 'Bot'`).
|
|
283
|
-
* Throws if a parameter value is a variable reference.
|
|
284
|
-
*/
|
|
285
|
-
function parseParams(raw: string, partialName: string): Record<string, string> {
|
|
286
|
-
const params: Record<string, string> = {};
|
|
287
|
-
const literalMatches = [...raw.matchAll(LITERAL_PARAM_RE)];
|
|
288
|
-
|
|
289
|
-
const allParamNames = [...raw.matchAll(/(\w+)\s*:/g)].map((m) => m[1]);
|
|
290
|
-
|
|
291
|
-
for (const name of allParamNames) {
|
|
292
|
-
const literal = literalMatches.find((m) => m[1] === name);
|
|
293
|
-
if (!literal) {
|
|
294
|
-
throw new Error(
|
|
295
|
-
`Cannot flatten {% render '${partialName}' %}: parameter "${name}" uses a variable reference. ` +
|
|
296
|
-
"Only literal string values are supported at codegen time.",
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
// oxlint-disable-next-line security/detect-object-injection -- safe: name extracted from regex match on template literal
|
|
300
|
-
params[name] = literal[2];
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return params;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Find all `{% render %}` tags in a template string.
|
|
308
|
-
*/
|
|
309
|
-
function parseRenderTags(template: string): RenderTag[] {
|
|
310
|
-
const tags: RenderTag[] = [];
|
|
311
|
-
|
|
312
|
-
for (const m of template.matchAll(RENDER_TAG_RE)) {
|
|
313
|
-
const fullMatch = m[0];
|
|
314
|
-
const partialName = m[1];
|
|
315
|
-
const rawParams = match(m[2] != null)
|
|
316
|
-
.with(true, () => m[2].trim())
|
|
317
|
-
.otherwise(() => "");
|
|
318
|
-
const params = match(rawParams.length > 0)
|
|
319
|
-
.with(true, () => parseParams(rawParams, partialName))
|
|
320
|
-
.otherwise(() => ({}));
|
|
321
|
-
|
|
322
|
-
tags.push({ fullMatch, partialName, params });
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return tags;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Flatten `{% render %}` partial tags in a template at codegen time.
|
|
330
|
-
*
|
|
331
|
-
* Finds all `{% render 'name', key: 'value' %}` tags, reads the
|
|
332
|
-
* corresponding partial file, renders it with the literal parameters,
|
|
333
|
-
* and replaces the tag with the rendered output.
|
|
334
|
-
*
|
|
335
|
-
* All other Liquid expressions (`{{ var }}`, `{% if %}`, `{% for %}`)
|
|
336
|
-
* are preserved for runtime rendering.
|
|
337
|
-
*
|
|
338
|
-
* @param template - Template string (frontmatter already stripped).
|
|
339
|
-
* @param partialsDirs - Directories to search for partial `.prompt` files.
|
|
340
|
-
* @returns Flattened template with all render tags resolved.
|
|
341
|
-
*/
|
|
342
|
-
export function flattenPartials(template: string, partialsDirs: string[]): string {
|
|
343
|
-
const tags = parseRenderTags(template);
|
|
344
|
-
if (tags.length === 0) {
|
|
345
|
-
return template;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const engine = new Liquid({
|
|
349
|
-
root: partialsDirs,
|
|
350
|
-
partials: partialsDirs,
|
|
351
|
-
extname: ".prompt",
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
const result = tags.reduce((acc, tag) => {
|
|
355
|
-
const rendered = engine.parseAndRenderSync(
|
|
356
|
-
`{% render '${tag.partialName}' ${Object.entries(tag.params)
|
|
357
|
-
.map(([k, v]) => `${k}: '${v}'`)
|
|
358
|
-
.join(", ")} %}`,
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
return acc.replace(tag.fullMatch, rendered);
|
|
362
|
-
}, template);
|
|
363
|
-
|
|
364
|
-
return result;
|
|
365
|
-
}
|
|
366
|
-
</pre></td></tr></table></pre>
|
|
367
|
-
|
|
368
|
-
<div class='push'></div><!-- for sticky footer -->
|
|
369
|
-
</div><!-- /wrapper -->
|
|
370
|
-
<div class='footer quiet pad2 space-top1 center small'>
|
|
371
|
-
Code coverage generated by
|
|
372
|
-
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
373
|
-
at 2026-03-13T00:28:56.897Z
|
|
374
|
-
</div>
|
|
375
|
-
<script src="../prettify.js"></script>
|
|
376
|
-
<script>
|
|
377
|
-
window.onload = function () {
|
|
378
|
-
prettyPrint();
|
|
379
|
-
};
|
|
380
|
-
</script>
|
|
381
|
-
<script src="../sorter.js"></script>
|
|
382
|
-
<script src="../block-navigation.js"></script>
|
|
383
|
-
</body>
|
|
384
|
-
</html>
|
|
385
|
-
|