spooder 4.3.0 → 4.3.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/README.md +14 -46
- package/package.json +1 -1
- package/src/api.ts +12 -62
package/README.md
CHANGED
|
@@ -1066,24 +1066,6 @@ const html = parse_template(template, replacements);
|
|
|
1066
1066
|
</html>
|
|
1067
1067
|
```
|
|
1068
1068
|
|
|
1069
|
-
Object properties are supported by using the dot syntax.
|
|
1070
|
-
|
|
1071
|
-
```ts
|
|
1072
|
-
const template = `<span>{$foo.bar}</span>`;
|
|
1073
|
-
|
|
1074
|
-
const replacements = {
|
|
1075
|
-
foo: {
|
|
1076
|
-
bar: 'Hello, world!';
|
|
1077
|
-
}
|
|
1078
|
-
};
|
|
1079
|
-
|
|
1080
|
-
const html = parse_template(template, replacements);
|
|
1081
|
-
```
|
|
1082
|
-
|
|
1083
|
-
```html
|
|
1084
|
-
<span>Hello, world!</span>
|
|
1085
|
-
```
|
|
1086
|
-
|
|
1087
1069
|
By default, placeholders that do not appear in the replacement object will be left as-is. Set `drop_missing` to `true` to remove them.
|
|
1088
1070
|
|
|
1089
1071
|
```ts
|
|
@@ -1125,15 +1107,16 @@ parse_template('Hello {$world}', replacer);
|
|
|
1125
1107
|
</body>
|
|
1126
1108
|
</html>
|
|
1127
1109
|
```
|
|
1110
|
+
|
|
1128
1111
|
`parse_template` supports looping arrays with the following syntax.
|
|
1129
1112
|
|
|
1130
1113
|
```html
|
|
1131
|
-
{$for:foo
|
|
1114
|
+
{$for:foo}My colour is %s{/for}
|
|
1132
1115
|
```
|
|
1133
1116
|
```ts
|
|
1134
1117
|
const template = `
|
|
1135
1118
|
<ul>
|
|
1136
|
-
{$for:foo
|
|
1119
|
+
{$for:foo}<li>%s</li>{/for}
|
|
1137
1120
|
</ul>
|
|
1138
1121
|
`;
|
|
1139
1122
|
|
|
@@ -1152,39 +1135,24 @@ const html = parse_template(template, replacements);
|
|
|
1152
1135
|
</ul>
|
|
1153
1136
|
```
|
|
1154
1137
|
|
|
1155
|
-
|
|
1138
|
+
All placeholders inside a `{$for:}` loop are substituted, but only if the loop variable exists.
|
|
1156
1139
|
|
|
1157
|
-
|
|
1158
|
-
{$for:foo as bar}My colour is {$bar.baz}{/for}
|
|
1159
|
-
```
|
|
1160
|
-
```ts
|
|
1161
|
-
const template = `
|
|
1162
|
-
<ul>
|
|
1163
|
-
{$for:foo as bar}<li>My colour is {$bar.baz}</li>{/for}
|
|
1164
|
-
</ul>
|
|
1165
|
-
`;
|
|
1166
|
-
```
|
|
1167
|
-
|
|
1168
|
-
If/else statements are supported in templates, which include blocks based on the existence/truthiness of a property.
|
|
1140
|
+
In the following example, `missing` does not exist, so `test` is not substituted inside the loop, but `test` is still substituted outside the loop.
|
|
1169
1141
|
|
|
1170
1142
|
```html
|
|
1171
|
-
{$
|
|
1172
|
-
|
|
1173
|
-
{else}
|
|
1174
|
-
Hello, Mars!
|
|
1175
|
-
{/if}
|
|
1143
|
+
<div>Hello {$test}!</div>
|
|
1144
|
+
{$for:missing}<div>Loop {$test}</div>{/for}
|
|
1176
1145
|
```
|
|
1177
1146
|
|
|
1178
|
-
|
|
1147
|
+
```ts
|
|
1148
|
+
parse_template(..., {
|
|
1149
|
+
test: 'world'
|
|
1150
|
+
});
|
|
1151
|
+
```
|
|
1179
1152
|
|
|
1180
1153
|
```html
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
Europe: {$country.name}
|
|
1184
|
-
{else}
|
|
1185
|
-
Not Europe: {$country.name}
|
|
1186
|
-
{/if}
|
|
1187
|
-
{/for}
|
|
1154
|
+
<div>Hello world!</div>
|
|
1155
|
+
{$for}Loop <div>{$test}</div>{/for}
|
|
1188
1156
|
```
|
|
1189
1157
|
|
|
1190
1158
|
<a id="api-content-generate-hash-subs"></a>
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -108,8 +108,8 @@ export async function safe(target_fn: Callable) {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
type ReplacerFn = (key: string) => string | Array<
|
|
112
|
-
type Replacements = Record<string, string | Array<
|
|
111
|
+
type ReplacerFn = (key: string) => string | Array<string> | undefined;
|
|
112
|
+
type Replacements = Record<string, string | Array<string>> | ReplacerFn;
|
|
113
113
|
|
|
114
114
|
export function parse_template(template: string, replacements: Replacements, drop_missing = false): string {
|
|
115
115
|
let result = '';
|
|
@@ -118,28 +118,6 @@ export function parse_template(template: string, replacements: Replacements, dro
|
|
|
118
118
|
|
|
119
119
|
const is_replacer_fn = typeof replacements === 'function';
|
|
120
120
|
|
|
121
|
-
function getValue(key: string): any {
|
|
122
|
-
const var_parts = key.split('.');
|
|
123
|
-
let value: any = is_replacer_fn ? replacements(var_parts[0]) : replacements[var_parts[0]];
|
|
124
|
-
|
|
125
|
-
for (let j = 1; j < var_parts.length; j++) {
|
|
126
|
-
if (value && typeof value === 'object') {
|
|
127
|
-
value = value[var_parts[j]];
|
|
128
|
-
} else {
|
|
129
|
-
value = undefined;
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return value;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function parseBlock(content: string, local_replacements: Replacements): string {
|
|
137
|
-
return parse_template(content, {
|
|
138
|
-
...replacements,
|
|
139
|
-
...local_replacements
|
|
140
|
-
}, drop_missing);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
121
|
const template_length = template.length;
|
|
144
122
|
for (let i = 0; i < template_length; i++) {
|
|
145
123
|
const char = template[i];
|
|
@@ -152,8 +130,9 @@ export function parse_template(template: string, replacements: Replacements, dro
|
|
|
152
130
|
buffer_active = false;
|
|
153
131
|
|
|
154
132
|
if (buffer.startsWith('for:')) {
|
|
155
|
-
const
|
|
156
|
-
|
|
133
|
+
const loop_key = buffer.substring(4);
|
|
134
|
+
|
|
135
|
+
const loop_entries = is_replacer_fn ? replacements(loop_key) : replacements[loop_key];
|
|
157
136
|
const loop_content_start_index = i + 1;
|
|
158
137
|
const loop_close_index = template.indexOf('{/for}', loop_content_start_index);
|
|
159
138
|
|
|
@@ -162,48 +141,19 @@ export function parse_template(template: string, replacements: Replacements, dro
|
|
|
162
141
|
result += '{$' + buffer + '}';
|
|
163
142
|
} else {
|
|
164
143
|
const loop_content = template.substring(loop_content_start_index, loop_close_index);
|
|
165
|
-
if (
|
|
166
|
-
for (const loop_entry of loop_entries)
|
|
167
|
-
|
|
144
|
+
if (loop_entries !== undefined) {
|
|
145
|
+
for (const loop_entry of loop_entries) {
|
|
146
|
+
const inner_content = loop_content.replaceAll('%s', loop_entry);
|
|
147
|
+
result += parse_template(inner_content, replacements, drop_missing);
|
|
148
|
+
}
|
|
168
149
|
} else {
|
|
169
150
|
if (!drop_missing)
|
|
170
151
|
result += '{$' + buffer + '}' + loop_content + '{/for}';
|
|
171
152
|
}
|
|
172
|
-
i
|
|
173
|
-
}
|
|
174
|
-
} else if (buffer.startsWith('if:')) {
|
|
175
|
-
const condition_key = buffer.substring(3);
|
|
176
|
-
const condition_value = getValue(condition_key);
|
|
177
|
-
const if_content_start_index = i + 1;
|
|
178
|
-
const if_close_index = template.indexOf('{/if}', if_content_start_index);
|
|
179
|
-
|
|
180
|
-
if (if_close_index === -1) {
|
|
181
|
-
if (!drop_missing)
|
|
182
|
-
result += '{$' + buffer + '}';
|
|
183
|
-
} else {
|
|
184
|
-
const if_content = template.substring(if_content_start_index, if_close_index);
|
|
185
|
-
const else_index = if_content.indexOf('{else}');
|
|
186
|
-
|
|
187
|
-
if (else_index === -1) {
|
|
188
|
-
// No else block
|
|
189
|
-
if (condition_value) {
|
|
190
|
-
result += parseBlock(if_content, {});
|
|
191
|
-
}
|
|
192
|
-
} else {
|
|
193
|
-
// Has else block
|
|
194
|
-
const true_content = if_content.substring(0, else_index);
|
|
195
|
-
const false_content = if_content.substring(else_index + 6); // +6 to move past {else}
|
|
196
|
-
|
|
197
|
-
if (condition_value)
|
|
198
|
-
result += parseBlock(true_content, {});
|
|
199
|
-
else
|
|
200
|
-
result += parseBlock(false_content, {});
|
|
201
|
-
}
|
|
202
|
-
i = if_close_index + 4; // Move past {/if}
|
|
153
|
+
i += loop_content.length + 6;
|
|
203
154
|
}
|
|
204
155
|
} else {
|
|
205
|
-
const replacement =
|
|
206
|
-
|
|
156
|
+
const replacement = is_replacer_fn ? replacements(buffer) : replacements[buffer];
|
|
207
157
|
if (replacement !== undefined)
|
|
208
158
|
result += replacement;
|
|
209
159
|
else if (!drop_missing)
|