@cododel/alto 0.1.5 → 0.1.6

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.
Files changed (56) hide show
  1. package/dist/default/default/extensions/filters/comment.ts +9 -0
  2. package/dist/default/default/extensions/filters/contains.ts +8 -0
  3. package/dist/default/default/extensions/filters/directus.ts +336 -0
  4. package/dist/default/default/extensions/filters/drop_first.ts +8 -0
  5. package/dist/default/default/extensions/filters/entries.ts +13 -0
  6. package/dist/default/default/extensions/filters/falsey.ts +17 -0
  7. package/dist/default/default/extensions/filters/indent.ts +6 -0
  8. package/dist/default/default/extensions/filters/inflections.ts +25 -0
  9. package/dist/default/default/extensions/filters/json.ts +10 -0
  10. package/dist/default/default/extensions/filters/log.ts +5 -0
  11. package/dist/default/default/extensions/filters/object_set.ts +11 -0
  12. package/dist/default/default/extensions/filters/push.ts +10 -0
  13. package/dist/default/default/extensions/filters/quote.ts +19 -0
  14. package/dist/default/default/extensions/filters/regex_replace.ts +10 -0
  15. package/dist/default/default/extensions/filters/splice.ts +13 -0
  16. package/dist/default/default/extensions/filters/split.ts +9 -0
  17. package/dist/default/default/extensions/filters/string_cases.ts +72 -0
  18. package/dist/default/default/extensions/filters/truthy.ts +17 -0
  19. package/dist/default/default/extensions/filters/typescript.ts +10 -0
  20. package/dist/default/default/extensions/filters/unshift.ts +10 -0
  21. package/dist/default/default/extensions/filters/wrap.ts +10 -0
  22. package/dist/default/default/extensions/tags/.gitkeep +0 -0
  23. package/dist/default/default/includes/typescript/get-field-jsdoc.liquid +11 -0
  24. package/dist/default/default/includes/typescript/get-field-type.liquid +121 -0
  25. package/dist/default/default/macros/typescript/types.njk +1 -0
  26. package/dist/default/default/templates/default/client.ts.njk +518 -0
  27. package/dist/default/default/templates/default/types.ts.njk +134 -0
  28. package/dist/default/extensions/filters/comment.ts +9 -0
  29. package/dist/default/extensions/filters/contains.ts +8 -0
  30. package/dist/default/extensions/filters/directus.ts +336 -0
  31. package/dist/default/extensions/filters/drop_first.ts +8 -0
  32. package/dist/default/extensions/filters/entries.ts +13 -0
  33. package/dist/default/extensions/filters/falsey.ts +17 -0
  34. package/dist/default/extensions/filters/indent.ts +6 -0
  35. package/dist/default/extensions/filters/inflections.ts +25 -0
  36. package/dist/default/extensions/filters/json.ts +10 -0
  37. package/dist/default/extensions/filters/log.ts +5 -0
  38. package/dist/default/extensions/filters/object_set.ts +11 -0
  39. package/dist/default/extensions/filters/push.ts +10 -0
  40. package/dist/default/extensions/filters/quote.ts +19 -0
  41. package/dist/default/extensions/filters/regex_replace.ts +10 -0
  42. package/dist/default/extensions/filters/splice.ts +13 -0
  43. package/dist/default/extensions/filters/split.ts +9 -0
  44. package/dist/default/extensions/filters/string_cases.ts +72 -0
  45. package/dist/default/extensions/filters/truthy.ts +17 -0
  46. package/dist/default/extensions/filters/typescript.ts +10 -0
  47. package/dist/default/extensions/filters/unshift.ts +10 -0
  48. package/dist/default/extensions/filters/wrap.ts +10 -0
  49. package/dist/default/extensions/tags/.gitkeep +0 -0
  50. package/dist/default/includes/typescript/get-field-jsdoc.liquid +11 -0
  51. package/dist/default/includes/typescript/get-field-type.liquid +121 -0
  52. package/dist/default/macros/typescript/types.njk +1 -0
  53. package/dist/default/templates/default/client.ts.njk +518 -0
  54. package/dist/default/templates/default/types.ts.njk +134 -0
  55. package/dist/index.js +163 -164
  56. package/package.json +3 -3
@@ -0,0 +1,134 @@
1
+ {% block header %}
2
+ /**
3
+ * This file is automatically generated by the `@indirectus/cli` package.
4
+ * Follow the package's instruction to update this file with the latest schema.
5
+ */
6
+ {% endblock %}
7
+
8
+ {% block imports %}
9
+ import type * as Directus from "@directus/sdk";
10
+
11
+ {% endblock %}
12
+
13
+ export namespace Types {
14
+ {% block types %}
15
+ // Internal
16
+ export type Nullable<T> = T | null;
17
+ export type Optional<T> = Nullable<T>;
18
+ export type UnknownType<T> = T | unknown;
19
+ export type PrimaryKey<T> = T;
20
+
21
+ // Numbers
22
+ export type BigInteger = number;
23
+ export type Decimal = number;
24
+ export type Float = number;
25
+ export type Integer = number;
26
+ export type Number = number;
27
+
28
+ // Buffers
29
+ export type Binary = string;
30
+ export type String = string;
31
+ export type Text = string;
32
+
33
+ // Date & Time
34
+ export type Date = string | globalThis.Date;
35
+ export type DateTime = string | globalThis.Date;
36
+
37
+ // Geometry
38
+ export namespace Geometry {
39
+ export type LineString = any;
40
+ export type MultiLineString = any;
41
+ export type MultiPoint = any;
42
+ export type MultiPolygon = any;
43
+ export type Point = any;
44
+ export type Polygon = any;
45
+ }
46
+
47
+ // Complex
48
+ export type JSON = any;
49
+ export type JSONSchema = any;
50
+
51
+ // Others
52
+ export type UUID = string;
53
+ export type Boolean = boolean;
54
+ export type Enum = string;
55
+
56
+ {% endblock %}
57
+ }
58
+
59
+ /**
60
+ * All collection types.
61
+ */
62
+ export namespace Collections {
63
+
64
+ {% for collection in registry.collections | skip_collections(skipCollections) -%}
65
+ {% if collection.is_system %}
66
+
67
+ {%- set field_count = collection.fields | only_custom_fields | length -%}
68
+ {% filter comment -%}
69
+ The resolved {{ collection.name | to_collection_text }} collection type.
70
+ {% endfilter %}
71
+ export type {{ collection.name | to_collection_name }} = Directus.{{ collection.name | to_collection_name }}<System>;
72
+ {% endif %}
73
+ {% endfor %}
74
+
75
+ {% for collection in registry.collections -%}
76
+ {% if not collection.is_system %}
77
+ /**
78
+ * The {{ collection.name | space_case | lower_case }} collection.
79
+ */
80
+ export interface {{ collection.name | pascal_case }} {
81
+ {%- for field in collection.fields %}
82
+ {%- set type = field | to_ts_type -%}
83
+ {%- if type != 'never' %}
84
+ {{ field.name | to_ts_identifier }}: {{ type }};
85
+ {%- endif -%}
86
+ {%- endfor %}
87
+ }
88
+ {% endif %}
89
+ {% endfor %}
90
+ }
91
+
92
+ /**
93
+ * System schema extensions.
94
+ */
95
+
96
+ export interface System {
97
+
98
+ {% for collection in registry.collections | skip_collections(skipCollections) -%}
99
+ {% if collection.is_system %}
100
+
101
+ {% filter comment -%}
102
+ The definition for the {{ collection.name | to_collection_text }} system collection.
103
+ {% endfilter %}
104
+ {{ collection.name }}: {
105
+ {%- for field in collection.fields | only_custom_fields %}
106
+ {%- set type = field | to_ts_type -%}
107
+ {%- if type != 'never' %}
108
+ {{ field.name | to_ts_identifier }}: {{ type }};
109
+ {%- endif -%}
110
+ {%- endfor %}
111
+ }{{ "" if collection.is_singleton else "[]" }};
112
+
113
+ {% endif %}
114
+ {% endfor %}
115
+
116
+ }
117
+
118
+ /**
119
+ * Schema definition.
120
+ */
121
+ export interface Schema extends System {
122
+ {% for collection in registry.collections -%}
123
+ {% if not collection.is_system %}
124
+ {% set suffix = "" if collection.is_singleton else "[]" %}
125
+ /**
126
+ * The {{ collection.name | to_collection_text }} collection.
127
+ */
128
+ {{ collection.name | to_ts_identifier }}: Collections.{{ collection.name | pascal_case }}{{ suffix }};
129
+ {% endif %}
130
+ {% endfor %}
131
+ }
132
+
133
+
134
+
@@ -0,0 +1,9 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function comment(context: TemplateContext, str: Array<any> | string) {
4
+ if (Array.isArray(str)) {
5
+ str = str.join("\n").replace(/(^\n*)|(\n*$)/gi, "");
6
+ }
7
+ str = str.split("\n");
8
+ return `/**\n${str.map((line) => ` * ${line}`).join("\n")}\n*/`;
9
+ }
@@ -0,0 +1,8 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function contains(context: TemplateContext, arr: any, value: any) {
4
+ if (!Array.isArray(arr)) {
5
+ return false;
6
+ }
7
+ return typeof arr.find((v) => v == value) != "undefined";
8
+ }
@@ -0,0 +1,336 @@
1
+ import { Collection, Field } from "../../../types/registry";
2
+
3
+ import { json } from "./json";
4
+ import { quote, quoted } from "./quote";
5
+
6
+ import { match } from "ts-pattern";
7
+ import type { TemplateContext } from "../../../types/template";
8
+ import { drop_first } from "./drop_first";
9
+ import { regex_replace } from "./regex_replace";
10
+ import { split } from "./split";
11
+ import { lower_case, pascal_case, space_case } from "./string_cases";
12
+ import { isManyToOne, isOneToMany } from "../../../types/relationships";
13
+
14
+ export function to_collection_text(
15
+ context: TemplateContext,
16
+ value: string,
17
+ prefix: string = "",
18
+ suffix: string = "",
19
+ ) {
20
+ return `${prefix}${lower_case(context, space_case(context, value))}${suffix}`;
21
+ }
22
+
23
+ export function to_collection_string(context: TemplateContext, value: String) {
24
+ return quoted(context, value);
25
+ }
26
+
27
+ export function to_collection_name(
28
+ context: TemplateContext,
29
+ value: string,
30
+ partial = false,
31
+ ) {
32
+ value = `${value}`;
33
+ const system = context.registry.collections.find(
34
+ (c) => c.name.raw == value,
35
+ )?.is_system;
36
+ let name = pascal_case(context, value);
37
+ if (system) {
38
+ if (partial) {
39
+ name = regex_replace(
40
+ context,
41
+ pascal_case(context, drop_first(context, split(context, value, "_"))),
42
+ "s$",
43
+ "",
44
+ );
45
+ name = name == "Setting" ? "Settings" : name;
46
+ name = name == "Acces" ? "Access" : name;
47
+ } else {
48
+ name = regex_replace(context, pascal_case(context, value), "s$", "");
49
+ name = name == "DirectusSetting" ? "DirectusSettings" : name;
50
+ name = name == "DirectusAcces" ? "DirectusAccess" : name;
51
+ name = name == "DirectusComment" ? "DirectusActivity" : name;
52
+ }
53
+ }
54
+ return name;
55
+ }
56
+
57
+ export function to_ts_type(context: TemplateContext, field: Field) {
58
+ if (!field.type.is_data) {
59
+ return "never";
60
+ }
61
+
62
+ let types: string[] = [];
63
+ let schema = field.type;
64
+ let meta = field.type.raw?.meta;
65
+ let nullable = false;
66
+
67
+ let db_type = match(
68
+ field?.type?.database?.split("(", 2)[0]!.toLowerCase().trim(),
69
+ )
70
+ .returnType<string | false>()
71
+ .with("uuid", () => "Types.UUID")
72
+ .with("json", () => "Types.JSON")
73
+ .with("text", () => "Types.String")
74
+ .with("integer", () => "Types.Integer")
75
+ .with("decimal", () => "Types.Decimal")
76
+ .with("numeric", () => "Types.Number")
77
+ .with("bigint", () => "Types.BigInteger")
78
+ .with("boolean", () => "Types.Boolean")
79
+ .with("character varying", () => "Types.String")
80
+ .with("date", () => "Types.Date")
81
+ .with("time", () => "Types.DateTime")
82
+ .with("time with time zone", () => "Types.DateTime")
83
+ .with("time without time zone", () => "Types.DateTime")
84
+ .with("timestamp", () => "Types.DateTime")
85
+ .with("timestamp with time zone", () => "Types.DateTime")
86
+ .with("timestamp without time zone", () => "Types.DateTime")
87
+
88
+ // Shared
89
+ .with("boolean", () => "Types.Boolean")
90
+ .with("tinyint", () => "Types.Integer")
91
+ .with("smallint", () => "Types.Integer")
92
+ .with("mediumint", () => "Types.Integer")
93
+ .with("int", () => "Types.Integer")
94
+ .with("integer", () => "Types.Integer")
95
+ .with("serial", () => "Types.Integer")
96
+ .with("bigint", () => "Types.BigInteger")
97
+ .with("bigserial", () => "Types.BigInteger")
98
+ .with("clob", () => "Types.Text")
99
+ .with("tinytext", () => "Types.Text")
100
+ .with("mediumtext", () => "Types.Text")
101
+ .with("longtext", () => "Types.Text")
102
+ .with("text", () => "Types.Text")
103
+ .with("varchar", () => "Types.String")
104
+ .with("longvarchar", () => "Types.String")
105
+ .with("varchar2", () => "Types.String")
106
+ .with("nvarchar", () => "Types.String")
107
+ .with("image", () => "Types.Binary")
108
+ .with("ntext", () => "Types.Text")
109
+ .with("char", () => "Types.String")
110
+ .with("date", () => "Types.Date")
111
+ .with("datetime", () => "Types.DateTime")
112
+ .with("dateTime", () => "Types.DateTime")
113
+ .with("timestamp", () => "Types.DateTime")
114
+ .with("time", () => "Types.DateTime")
115
+ .with("float", () => "Types.Float")
116
+ .with("double", () => "Types.Float")
117
+ .with("double precision", () => "Types.Float")
118
+ .with("real", () => "Types.Float")
119
+ .with("decimal", () => "Types.Decimal")
120
+ .with("numeric", () => "Types.Integer")
121
+
122
+ // Geometries
123
+ .with("geometry", () => "Types.Geometry.Geometry")
124
+ .with("point", () => "Types.Geometry.Point")
125
+ .with("linestring", () => "Types.Geometry.LineString")
126
+ .with("polygon", () => "Types.Geometry.Polygon")
127
+ .with("multipoint", () => "Types.Geometry.MultiPoint")
128
+ .with("multilinestring", () => "Types.Geometry.MultiLineString")
129
+ .with("multipolygon", () => "Types.Geometry.MultiPolygon")
130
+
131
+ // MySQL
132
+ .with("string", () => "Types.Text")
133
+ .with("year", () => "Types.Integer")
134
+ .with("blob", () => "Types.Binary")
135
+ .with("mediumblob", () => "Types.Binary")
136
+ .with("int unsigned", () => "Types.Integer")
137
+ .with("tinyint unsigned", () => "Types.Integer")
138
+ .with("smallint unsigned", () => "Types.Integer")
139
+ .with("mediumint unsigned", () => "Types.Integer")
140
+ .with("bigint unsigned", () => "Types.Integer")
141
+
142
+ // MS SQL
143
+ .with("bit", () => "Types.Boolean")
144
+ .with("smallmoney", () => "Types.Float")
145
+ .with("money", () => "Types.Float")
146
+ .with("datetimeoffset", () => "Types.DateTime")
147
+ .with("datetime2", () => "Types.DateTime")
148
+ .with("smalldatetime", () => "Types.DateTime")
149
+ .with("nchar", () => "Types.Text")
150
+ .with("binary", () => "Types.Binary")
151
+ .with("varbinary", () => "Types.Binary")
152
+ .with("uniqueidentifier", () => "Types.UUID")
153
+
154
+ // Postgres
155
+ .with("json", () => "Types.JSON")
156
+ .with("jsonb", () => "Types.JSON")
157
+ .with("uuid", () => "Types.UUID")
158
+ .with("int2", () => "Types.Integer")
159
+ .with("serial4", () => "Types.Integer")
160
+ .with("int4", () => "Types.Integer")
161
+ .with("serial8", () => "Types.Integer")
162
+ .with("int8", () => "Types.Integer")
163
+ .with("bool", () => "Types.Boolean")
164
+ .with("character varying", () => "Types.String")
165
+ .with("character", () => "Types.String")
166
+ .with("interval", () => "Types.String")
167
+ .with("_varchar", () => "Types.String")
168
+ .with("bpchar", () => "Types.String")
169
+ .with("timestamptz", () => "Types.DateTime")
170
+ .with("timestamp with time zone", () => "Types.DateTime")
171
+ .with("timestamp with local time zone", () => "Types.DateTime")
172
+ .with("timestamp without time zone", () => "Types.Date")
173
+ .with("timestamp without local time zone", () => "Types.Date")
174
+ .with("timetz", () => "Types.DateTime")
175
+ .with("time with time zone", () => "Types.DateTime")
176
+ .with("time without time zone", () => "Types.DateTime")
177
+ .with("float4", () => "Types.Float")
178
+ .with("float8", () => "Types.Float")
179
+ .with("citext", () => "Types.Text")
180
+ .with("enum", () => "Types.Enum")
181
+
182
+ // Oracle
183
+ .with("number", () => "Types.Integer")
184
+ .with("sdo_geometry", () => "Types.Geometry.Geometry")
185
+
186
+ // SQLite
187
+ .with("integerfirst", () => "Types.Integer")
188
+
189
+ .otherwise(() => false);
190
+
191
+ if (db_type) {
192
+ types.push(db_type);
193
+ }
194
+
195
+ let json_type: string | false = false;
196
+ if (field.type.is_json) {
197
+ if ("json_schema" in schema) {
198
+ json_type = "Types.JSONSchema";
199
+ } else {
200
+ json_type = "Types.JSON";
201
+ }
202
+ }
203
+
204
+ switch (meta?.interface) {
205
+ case "tags":
206
+ types.unshift("Types.String[]");
207
+ break;
208
+ case "select-dropdown":
209
+ let values = (meta?.options?.choices ?? []).map((v: any) =>
210
+ quote(context, v.value),
211
+ );
212
+ for (let value of values) {
213
+ if (value == null) {
214
+ nullable = true;
215
+ } else {
216
+ types.unshift(value);
217
+ }
218
+ }
219
+ json_type = false;
220
+ break;
221
+ }
222
+
223
+ if (schema.raw?.schema?.is_nullable) {
224
+ // types.push('null')
225
+ nullable = true;
226
+ }
227
+
228
+ if (json_type != false) {
229
+ types.unshift(json_type);
230
+ }
231
+
232
+ if (field.type.is_relationship) {
233
+ //if (
234
+ // field.type.is_special("user-created") ||
235
+ // field.type.is_special("user-updated")
236
+ //) {
237
+ // types.push("Collections.DirectusUser");
238
+ //} else if (field.type.is_special("file")) {
239
+ // types.push("Collections.DirectusFile");
240
+ //} else if (field.type.is_special("files")) {
241
+ // types.push("Collections.DirectusFile[]");
242
+ //} else
243
+ if (field.is_translations) {
244
+ types.push(
245
+ `${to_collection_name(context, field.translations_collection)}[]`,
246
+ );
247
+ } else {
248
+ let suffix =
249
+ (((isManyToOne(field.type.relationship) ||
250
+ isOneToMany(field.type.relationship)) &&
251
+ field.type.relationship.many) ??
252
+ field.type.is_special("m2m"))
253
+ ? "[]"
254
+ : "";
255
+
256
+ if (field.type.relationship?.type == "o2m") {
257
+ types.push(
258
+ `Collections.${to_collection_name(
259
+ context,
260
+ field.type.relationship.ref.collection,
261
+ )}${suffix}`,
262
+ );
263
+ }
264
+ if (field.type.relationship?.type == "m2o") {
265
+ types.push(
266
+ `Collections.${to_collection_name(
267
+ context,
268
+ field.type.relationship.ref.collection,
269
+ )}${suffix}`,
270
+ );
271
+ }
272
+ if (field.type.relationship?.type == "a2o") {
273
+ field.type.relationship.refs.forEach((ref) => {
274
+ types.push(
275
+ `Collections.${to_collection_name(
276
+ context,
277
+ ref.collection,
278
+ )}${suffix}`,
279
+ );
280
+ });
281
+ }
282
+ if (field.type.relationship?.type == "unmapped") {
283
+ types.push("any");
284
+ }
285
+ }
286
+ }
287
+
288
+ if (types.length <= 0) {
289
+ let schemaStr = json(context, schema);
290
+ let metaStr = json(context, meta);
291
+ let unknown = `Types.UnknownType<{ schema: ${schemaStr}, meta: ${metaStr} }>`;
292
+ types.unshift(unknown);
293
+ }
294
+
295
+ let output = types.join(" | ");
296
+ if (nullable) {
297
+ output = `Types.Optional<${output}>`;
298
+ }
299
+
300
+ if (field.type.raw?.schema?.is_primary_key ?? false) {
301
+ output = `Types.PrimaryKey<${output}>`;
302
+ }
303
+
304
+ return output;
305
+ }
306
+
307
+ export function only_system_fields(_context: TemplateContext, fields: Field[]) {
308
+ return fields.filter((field) => field.is_system);
309
+ }
310
+
311
+ export function only_custom_fields(_context: TemplateContext, fields: Field[]) {
312
+ return fields.filter((field) => !field.is_system);
313
+ }
314
+
315
+ export function only_with_custom_fields(
316
+ _context: TemplateContext,
317
+ collections: Collection[],
318
+ ) {
319
+ return collections.filter(
320
+ (field) => field.fields.filter((field) => !field.is_system).length > 0,
321
+ );
322
+ }
323
+
324
+ export function skip_collections(
325
+ context: TemplateContext,
326
+ collections: Collection[],
327
+ skipList?: string[],
328
+ ) {
329
+ // Используем skipList из параметров или из контекста или дефолтное значение
330
+ const skipCollections = skipList ??
331
+ context.skipCollections ?? ["directus_comments"];
332
+
333
+ return collections.filter(
334
+ (collection) => !skipCollections.includes(collection.name.raw),
335
+ );
336
+ }
@@ -0,0 +1,8 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function drop_first(context: TemplateContext, arr: Array<any>) {
4
+ if (Array.isArray(arr)) {
5
+ arr.shift();
6
+ }
7
+ return arr;
8
+ }
@@ -0,0 +1,13 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function entries(
4
+ context: TemplateContext,
5
+ obj: any,
6
+ keyName?: string,
7
+ valueName?: string,
8
+ ) {
9
+ return Object.entries(obj).map(([key, value]) => ({
10
+ [keyName ?? "key"]: key,
11
+ [valueName ?? "value"]: value,
12
+ }));
13
+ }
@@ -0,0 +1,17 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function falsey(
4
+ context: TemplateContext,
5
+ condition: boolean,
6
+ falsey: any,
7
+ truthy: any,
8
+ ) {
9
+ if (!condition) {
10
+ return falsey;
11
+ } else {
12
+ if (typeof truthy != "undefined") {
13
+ return truthy;
14
+ }
15
+ }
16
+ return condition;
17
+ }
@@ -0,0 +1,6 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function indent(context: TemplateContext, value: string, size: number) {
4
+ const indent = new Array(size + 1).join(" ");
5
+ return `${indent}${value.split("\n").join(`\n${indent}`)}`;
6
+ }
@@ -0,0 +1,25 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ import $ from "pluralize";
4
+
5
+ export function to_singular(context: TemplateContext, value: any) {
6
+ if (typeof value !== "string") {
7
+ console.warn(`WARNING: trying to singularize a non-string value: ${JSON.stringify(value)}`);
8
+ return value;
9
+ }
10
+ return `${$.singular(`${value}`)}`;
11
+ }
12
+
13
+ export const singularize = to_singular;
14
+ export const singular = to_singular;
15
+
16
+ export function to_plural(context: TemplateContext, value: any) {
17
+ if (typeof value !== "string") {
18
+ console.warn(`WARNING: trying to pluralize a non-string value: ${JSON.stringify(value)}`);
19
+ return value;
20
+ }
21
+ return `${$.plural(value)}`;
22
+ }
23
+
24
+ export const pluralize = to_plural;
25
+ export const plural = to_plural;
@@ -0,0 +1,10 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function json(context: TemplateContext, v: any) {
4
+ if (typeof v == "undefined") {
5
+ return "undefined";
6
+ } else if (v === null) {
7
+ return "null";
8
+ }
9
+ return JSON.stringify(v, null, 2);
10
+ }
@@ -0,0 +1,5 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function log(context: TemplateContext, ...values: any[]) {
4
+ console.log(JSON.stringify({ values }));
5
+ }
@@ -0,0 +1,11 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function object_set(
4
+ context: TemplateContext,
5
+ obj: any,
6
+ key: string,
7
+ value: any,
8
+ ) {
9
+ obj[key] = value;
10
+ return obj;
11
+ }
@@ -0,0 +1,10 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function push(context: TemplateContext, arr: Array<any>, value: any) {
4
+ if (Array.isArray(value)) {
5
+ arr.push(...value);
6
+ } else {
7
+ arr.push(value);
8
+ }
9
+ return arr;
10
+ }
@@ -0,0 +1,19 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function quote(context: TemplateContext, value: any) {
4
+ value = `${value}`;
5
+ if (typeof value == "string") {
6
+ return JSON.stringify(value);
7
+ } else if (Array.isArray(value)) {
8
+ return value.map((e) => {
9
+ if (typeof e == "string") {
10
+ return JSON.stringify(e);
11
+ } else {
12
+ return e;
13
+ }
14
+ });
15
+ }
16
+ return value;
17
+ }
18
+
19
+ export const quoted = quote;
@@ -0,0 +1,10 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function regex_replace(
4
+ context: TemplateContext,
5
+ value: string,
6
+ regex: string,
7
+ replacement: string,
8
+ ) {
9
+ return value.replace(new RegExp(regex, "g"), replacement);
10
+ }
@@ -0,0 +1,13 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function splice(
4
+ context: TemplateContext,
5
+ arr: Array<any>,
6
+ start: number,
7
+ count: number | undefined = undefined,
8
+ ) {
9
+ if (Array.isArray(arr)) {
10
+ return arr.splice(start, count);
11
+ }
12
+ return arr;
13
+ }
@@ -0,0 +1,9 @@
1
+ import type { TemplateContext } from "../../../types/template";
2
+
3
+ export function split(
4
+ context: TemplateContext,
5
+ value: string,
6
+ splitter: string,
7
+ ) {
8
+ return `${value}`.split(splitter);
9
+ }