···11const Radix3 = Ant.require('./radix3.cjs');
22const router = new Radix3();
3344+function html(strings, ...values) {
55+ let result = '';
66+ for (let i = 0; i < strings.length; i++) {
77+ result = result + strings[i];
88+ if (i < values.length) {
99+ let escaped = values[i];
1010+ result = result + escaped;
1111+ }
1212+ }
1313+ return result;
1414+}
1515+416router.insert('/', c => {
517 return c.res.body(`Welcome to Ant HTTP Server with Radix3 Router!
618···4052});
41534254router.insert('/files/*path', async c => {
4343- return c.res.html(c.params.path);
5555+ return c.res.html(html`<div>${c.params.path}</div>`);
4456});
45574658router.printTree();
+261
tests/tagged_templates.cjs
···11+// Comprehensive Tagged Template Literal Tests
22+Ant.println("=== Tagged Template Literal Tests ===\n");
33+44+// Test 1: Basic tagged template with one substitution
55+Ant.println("Test 1: Basic tagged template");
66+function tag1(strings, ...values) {
77+ Ant.println(" โ strings.length:", strings.length);
88+ Ant.println(" โ strings[0]:", strings[0]);
99+ Ant.println(" โ strings[1]:", strings[1]);
1010+ Ant.println(" โ values.length:", values.length);
1111+ Ant.println(" โ values[0]:", values[0]);
1212+ return "result1";
1313+}
1414+1515+let name = "World";
1616+let result1 = tag1`Hello ${name}!`;
1717+Ant.println(" โ Result:", result1);
1818+Ant.println("");
1919+2020+// Test 2: Building a string from parts
2121+Ant.println("Test 2: Building a string from tagged template");
2222+function build(strings, ...values) {
2323+ let result = "";
2424+ for (let i = 0; i < strings.length; i++) {
2525+ result = result + strings[i];
2626+ if (i < values.length) {
2727+ result = result + values[i];
2828+ }
2929+ }
3030+ return result;
3131+}
3232+3333+let greeting = build`Hello ${name}!`;
3434+Ant.println(" โ Result:", greeting);
3535+Ant.println("");
3636+3737+// Test 3: Multiple substitutions
3838+Ant.println("Test 3: Multiple substitutions");
3939+function multi(strings, ...values) {
4040+ Ant.println(" โ values.length:", values.length);
4141+ Ant.println(" โ First value:", values[0]);
4242+ Ant.println(" โ Second value:", values[1]);
4343+ return values[0] + values[1];
4444+}
4545+4646+let a = 10;
4747+let b = 20;
4848+let sum = multi`Adding ${a} and ${b}`;
4949+Ant.println(" โ Sum:", sum);
5050+Ant.println("");
5151+5252+// Test 4: No substitutions
5353+Ant.println("Test 4: No substitutions");
5454+function noSub(strings) {
5555+ Ant.println(" โ strings.length:", strings.length);
5656+ Ant.println(" โ strings[0]:", strings[0]);
5757+ return "no-substitutions";
5858+}
5959+6060+let result4 = noSub`Just a plain string`;
6161+Ant.println(" โ Result:", result4);
6262+Ant.println("");
6363+6464+// Test 5: Expression in substitution
6565+Ant.println("Test 5: Expression in substitution");
6666+function expr(strings, ...values) {
6767+ return values[0] * 2;
6868+}
6969+7070+let x = 5;
7171+let doubled = expr`Double ${x + 3}`;
7272+Ant.println(" โ Result:", doubled);
7373+Ant.println("");
7474+7575+// Test 6: Conditional in substitution
7676+Ant.println("Test 6: Conditional in substitution");
7777+function cond(strings, ...values) {
7878+ return values[0];
7979+}
8080+8181+let score = 85;
8282+let grade = cond`Grade: ${score > 80 ? "A" : "B"}`;
8383+Ant.println(" โ Result:", grade);
8484+Ant.println("");
8585+8686+// Test 7: Object property access
8787+Ant.println("Test 7: Object property access");
8888+function objAccess(strings, ...values) {
8989+ return values[0];
9090+}
9191+9292+let person = { name: "Alice", age: 25 };
9393+let info = objAccess`Name: ${person.name}`;
9494+Ant.println(" โ Result:", info);
9595+Ant.println("");
9696+9797+// Test 8: Array indexing
9898+Ant.println("Test 8: Array indexing");
9999+function arrAccess(strings, ...values) {
100100+ return values[0];
101101+}
102102+103103+let colors = ["red", "green", "blue"];
104104+let color = arrAccess`First color: ${colors[0]}`;
105105+Ant.println(" โ Result:", color);
106106+Ant.println("");
107107+108108+// Test 9: Returning different types
109109+Ant.println("Test 9: Returning different types");
110110+function retNum(strings) {
111111+ return 42;
112112+}
113113+114114+function retBool(strings) {
115115+ return true;
116116+}
117117+118118+let num = retNum`test`;
119119+let bool = retBool`test`;
120120+Ant.println(" โ Number:", num);
121121+Ant.println(" โ Boolean:", bool);
122122+Ant.println("");
123123+124124+// Test 10: Using result with string methods
125125+Ant.println("Test 10: Using result with string methods");
126126+function makeString(strings, ...values) {
127127+ return strings[0] + values[0] + strings[1];
128128+}
129129+130130+let text = makeString`Hello ${name}!`;
131131+Ant.println(" โ Text:", text);
132132+Ant.println(" โ Includes 'World':", text.includes("World"));
133133+Ant.println(" โ Starts with 'Hello':", text.startsWith("Hello"));
134134+Ant.println("");
135135+136136+// Test 11: Rest params with many values
137137+Ant.println("Test 11: Rest params with many values");
138138+function manyValues(strings, ...values) {
139139+ Ant.println(" โ strings.length:", strings.length);
140140+ Ant.println(" โ values.length:", values.length);
141141+ let result = "";
142142+ for (let i = 0; i < strings.length; i++) {
143143+ result = result + strings[i];
144144+ if (i < values.length) {
145145+ result = result + values[i];
146146+ }
147147+ }
148148+ return result;
149149+}
150150+151151+let v1 = "A";
152152+let v2 = "B";
153153+let v3 = "C";
154154+let v4 = "D";
155155+let assembled = manyValues`${v1}-${v2}-${v3}-${v4}`;
156156+Ant.println(" โ Result:", assembled);
157157+Ant.println("");
158158+159159+// Test 12: Nested function calls
160160+Ant.println("Test 12: Nested expressions");
161161+function nested(strings, ...values) {
162162+ return values[0] + values[1];
163163+}
164164+165165+function double(n) {
166166+ return n * 2;
167167+}
168168+169169+let nested_result = nested`${double(5)} + ${double(10)}`;
170170+Ant.println(" โ Result:", nested_result);
171171+Ant.println("");
172172+173173+// Test 13: Empty strings between substitutions
174174+Ant.println("Test 13: Adjacent substitutions");
175175+function adjacent(strings, ...values) {
176176+ Ant.println(" โ strings:", strings);
177177+ Ant.println(" โ values:", values);
178178+ return values[0] + values[1];
179179+}
180180+181181+let adj = adjacent`${10}${20}`;
182182+Ant.println(" โ Result:", adj);
183183+Ant.println("");
184184+185185+// Test 14: SQL-style template (common use case)
186186+Ant.println("Test 14: SQL-style builder");
187187+function sql(strings, ...values) {
188188+ let query = "";
189189+ for (let i = 0; i < strings.length; i++) {
190190+ query = query + strings[i];
191191+ if (i < values.length) {
192192+ query = query + "$" + (i + 1);
193193+ }
194194+ }
195195+ return { query: query, values: values };
196196+}
197197+198198+let userId = 42;
199199+let userName = "Alice";
200200+let sqlResult = sql`SELECT * FROM users WHERE id = ${userId} AND name = ${userName}`;
201201+Ant.println(" โ Query:", sqlResult.query);
202202+Ant.println(" โ Values:", sqlResult.values);
203203+Ant.println("");
204204+205205+// Test 15: HTML escaping (another common use case)
206206+Ant.println("Test 15: HTML builder");
207207+function html(strings, ...values) {
208208+ let result = "";
209209+ for (let i = 0; i < strings.length; i++) {
210210+ result = result + strings[i];
211211+ if (i < values.length) {
212212+ let escaped = values[i];
213213+ result = result + escaped;
214214+ }
215215+ }
216216+ return result;
217217+}
218218+219219+let title = "My Page";
220220+let content = "Hello World";
221221+let htmlResult = html`<html><head><title>${title}</title></head><body>${content}</body></html>`;
222222+Ant.println(" โ HTML:", htmlResult);
223223+Ant.println("");
224224+225225+// Test 16: Using closure instead of this
226226+Ant.println("Test 16: Tag function with closure");
227227+function makeTag(prefix) {
228228+ return function(strings, ...values) {
229229+ return prefix + values[0];
230230+ };
231231+}
232232+233233+let prefixTag = makeTag(">>>");
234234+let prefixed = prefixTag`Value: ${123}`;
235235+Ant.println(" โ Result:", prefixed);
236236+Ant.println("");
237237+238238+// Test 17: Empty template
239239+Ant.println("Test 17: Empty template");
240240+function empty(strings) {
241241+ return strings[0];
242242+}
243243+244244+let emptyResult = empty``;
245245+Ant.println(" โ Result:", emptyResult);
246246+Ant.println("");
247247+248248+// Test 18: Only substitutions, no strings
249249+Ant.println("Test 18: Template starting and ending with substitution");
250250+function allSubs(strings, ...values) {
251251+ Ant.println(" โ strings.length:", strings.length);
252252+ Ant.println(" โ First string is empty:", strings[0] == "");
253253+ Ant.println(" โ Last string is empty:", strings[strings.length - 1] == "");
254254+ return values.length;
255255+}
256256+257257+let count = allSubs`${1}${2}${3}`;
258258+Ant.println(" โ Count:", count);
259259+Ant.println("");
260260+261261+Ant.println("=== All 18 tests completed successfully! ===");