@saykit/config 0.0.0 → 0.1.0

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.
@@ -0,0 +1,100 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_hash = require("../../hash-CDfMT76E.cjs");
3
+ //#region src/features/messages/identifier.ts
4
+ const AUTO_INCREMENT_IDENTIFIER = Symbol("auto-increment");
5
+ function assignSequenceIdentifiers(message, sequence = { current: 0 }) {
6
+ if (message instanceof ArgumentMessage || message instanceof ElementMessage || message instanceof ChoiceMessage) {
7
+ if (message.identifier === AUTO_INCREMENT_IDENTIFIER) message.identifier = `${sequence.current++}`;
8
+ }
9
+ if (message instanceof CompositeMessage || message instanceof ElementMessage) for (const child of message.children) assignSequenceIdentifiers(child, sequence);
10
+ if (message instanceof ChoiceMessage) for (const branch of message.branches) {
11
+ if (branch.identifier === AUTO_INCREMENT_IDENTIFIER) branch.identifier = `${sequence.current++}`;
12
+ assignSequenceIdentifiers(branch.value, sequence);
13
+ }
14
+ }
15
+ //#endregion
16
+ //#region src/features/messages/types.ts
17
+ var Base = class {
18
+ toICUString() {
19
+ return convertMessageToIcu(this);
20
+ }
21
+ toHashString() {
22
+ const context = this instanceof CompositeMessage ? this.descriptor.context : void 0;
23
+ return require_hash.generateHash(this.toICUString(), context);
24
+ }
25
+ };
26
+ var LiteralMessage = class extends Base {
27
+ constructor(text) {
28
+ super();
29
+ this.text = text;
30
+ }
31
+ };
32
+ var ArgumentMessage = class extends Base {
33
+ constructor(identifier, expression) {
34
+ super();
35
+ this.identifier = identifier;
36
+ this.expression = expression;
37
+ }
38
+ };
39
+ var ElementMessage = class extends Base {
40
+ constructor(identifier, children, expression) {
41
+ super();
42
+ this.identifier = identifier;
43
+ this.children = children;
44
+ this.expression = expression;
45
+ }
46
+ };
47
+ var ChoiceMessage = class extends Base {
48
+ constructor(kind, identifier, branches, expression) {
49
+ super();
50
+ this.kind = kind;
51
+ this.identifier = identifier;
52
+ this.branches = branches;
53
+ this.expression = expression;
54
+ }
55
+ };
56
+ var CompositeMessage = class extends Base {
57
+ constructor(descriptor, comments, references, children, accessor) {
58
+ super();
59
+ this.descriptor = descriptor;
60
+ this.comments = comments;
61
+ this.references = references;
62
+ this.children = children;
63
+ this.accessor = accessor;
64
+ }
65
+ };
66
+ //#endregion
67
+ //#region src/features/messages/convert.ts
68
+ function convertMessageToIcu(message) {
69
+ function internalConvertMessageToIcu(message) {
70
+ switch (true) {
71
+ case message instanceof LiteralMessage: return String(message.text);
72
+ case message instanceof ArgumentMessage: return `{${String(message.identifier)}}`;
73
+ case message instanceof ElementMessage: {
74
+ const children = message.children.map((m) => internalConvertMessageToIcu(m)).join("");
75
+ return `<${String(message.identifier)}>${children}</${String(message.identifier)}>`;
76
+ }
77
+ case message instanceof ChoiceMessage: {
78
+ const branches = message.branches.map(({ identifier, value }) => ({
79
+ identifier: Number.isNaN(+String(identifier)) ? String(identifier) : `=${+String(identifier)}`,
80
+ value: internalConvertMessageToIcu(value)
81
+ })).map(({ identifier, value }) => ` ${identifier} {${value}}\n`).join("");
82
+ const format = message.kind === "ordinal" ? "selectordinal" : message.kind;
83
+ return `{${String(message.identifier)}, ${format},\n${branches}}`;
84
+ }
85
+ case message instanceof CompositeMessage: return Object.entries(message.children).map(([, m]) => internalConvertMessageToIcu(m)).join("");
86
+ default: throw new Error("Unknown message type", { cause: message });
87
+ }
88
+ }
89
+ return internalConvertMessageToIcu(message).trim();
90
+ }
91
+ //#endregion
92
+ exports.AUTO_INCREMENT_IDENTIFIER = AUTO_INCREMENT_IDENTIFIER;
93
+ exports.ArgumentMessage = ArgumentMessage;
94
+ exports.ChoiceMessage = ChoiceMessage;
95
+ exports.CompositeMessage = CompositeMessage;
96
+ exports.ElementMessage = ElementMessage;
97
+ exports.LiteralMessage = LiteralMessage;
98
+ exports.assignSequenceIdentifiers = assignSequenceIdentifiers;
99
+ exports.convertMessageToIcu = convertMessageToIcu;
100
+ exports.generateHash = require_hash.generateHash;
@@ -0,0 +1,62 @@
1
+ //#region src/features/messages/identifier.d.ts
2
+ declare const AUTO_INCREMENT_IDENTIFIER: unique symbol;
3
+ declare function assignSequenceIdentifiers(message: Message, sequence?: {
4
+ current: number;
5
+ }): void;
6
+ //#endregion
7
+ //#region src/features/messages/types.d.ts
8
+ declare abstract class Base {
9
+ toICUString(this: Message): string;
10
+ toHashString(this: Message): string;
11
+ }
12
+ declare class LiteralMessage extends Base {
13
+ readonly text: string;
14
+ constructor(text: string);
15
+ }
16
+ declare class ArgumentMessage extends Base {
17
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
18
+ readonly expression: any;
19
+ constructor(identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, expression: any);
20
+ }
21
+ declare class ElementMessage extends Base {
22
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
23
+ readonly children: Message[];
24
+ readonly expression: any;
25
+ constructor(identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, children: Message[], expression: any);
26
+ }
27
+ declare class ChoiceMessage extends Base {
28
+ readonly kind: string;
29
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
30
+ readonly branches: {
31
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
32
+ readonly value: Message;
33
+ }[];
34
+ readonly expression: any;
35
+ constructor(kind: string, identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, branches: {
36
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
37
+ readonly value: Message;
38
+ }[], expression: any);
39
+ }
40
+ declare class CompositeMessage extends Base {
41
+ readonly descriptor: {
42
+ id?: string;
43
+ context?: string;
44
+ };
45
+ readonly comments: string[];
46
+ readonly references: string[];
47
+ readonly children: Message[];
48
+ readonly accessor: any;
49
+ constructor(descriptor: {
50
+ id?: string;
51
+ context?: string;
52
+ }, comments: string[], references: string[], children: Message[], accessor: any);
53
+ }
54
+ type Message = LiteralMessage | ArgumentMessage | ElementMessage | ChoiceMessage | CompositeMessage;
55
+ //#endregion
56
+ //#region src/features/messages/convert.d.ts
57
+ declare function convertMessageToIcu(message: Message): string;
58
+ //#endregion
59
+ //#region src/features/messages/hash.d.ts
60
+ declare function generateHash(input: string, context?: string): string;
61
+ //#endregion
62
+ export { AUTO_INCREMENT_IDENTIFIER, ArgumentMessage, ChoiceMessage, CompositeMessage, ElementMessage, LiteralMessage, Message, assignSequenceIdentifiers, convertMessageToIcu, generateHash };
@@ -0,0 +1,62 @@
1
+ //#region src/features/messages/identifier.d.ts
2
+ declare const AUTO_INCREMENT_IDENTIFIER: unique symbol;
3
+ declare function assignSequenceIdentifiers(message: Message, sequence?: {
4
+ current: number;
5
+ }): void;
6
+ //#endregion
7
+ //#region src/features/messages/types.d.ts
8
+ declare abstract class Base {
9
+ toICUString(this: Message): string;
10
+ toHashString(this: Message): string;
11
+ }
12
+ declare class LiteralMessage extends Base {
13
+ readonly text: string;
14
+ constructor(text: string);
15
+ }
16
+ declare class ArgumentMessage extends Base {
17
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
18
+ readonly expression: any;
19
+ constructor(identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, expression: any);
20
+ }
21
+ declare class ElementMessage extends Base {
22
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
23
+ readonly children: Message[];
24
+ readonly expression: any;
25
+ constructor(identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, children: Message[], expression: any);
26
+ }
27
+ declare class ChoiceMessage extends Base {
28
+ readonly kind: string;
29
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
30
+ readonly branches: {
31
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
32
+ readonly value: Message;
33
+ }[];
34
+ readonly expression: any;
35
+ constructor(kind: string, identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, branches: {
36
+ identifier: string | typeof AUTO_INCREMENT_IDENTIFIER;
37
+ readonly value: Message;
38
+ }[], expression: any);
39
+ }
40
+ declare class CompositeMessage extends Base {
41
+ readonly descriptor: {
42
+ id?: string;
43
+ context?: string;
44
+ };
45
+ readonly comments: string[];
46
+ readonly references: string[];
47
+ readonly children: Message[];
48
+ readonly accessor: any;
49
+ constructor(descriptor: {
50
+ id?: string;
51
+ context?: string;
52
+ }, comments: string[], references: string[], children: Message[], accessor: any);
53
+ }
54
+ type Message = LiteralMessage | ArgumentMessage | ElementMessage | ChoiceMessage | CompositeMessage;
55
+ //#endregion
56
+ //#region src/features/messages/convert.d.ts
57
+ declare function convertMessageToIcu(message: Message): string;
58
+ //#endregion
59
+ //#region src/features/messages/hash.d.ts
60
+ declare function generateHash(input: string, context?: string): string;
61
+ //#endregion
62
+ export { AUTO_INCREMENT_IDENTIFIER, ArgumentMessage, ChoiceMessage, CompositeMessage, ElementMessage, LiteralMessage, Message, assignSequenceIdentifiers, convertMessageToIcu, generateHash };
@@ -0,0 +1,91 @@
1
+ import { t as generateHash } from "../../hash-Cs0dRdGf.mjs";
2
+ //#region src/features/messages/identifier.ts
3
+ const AUTO_INCREMENT_IDENTIFIER = Symbol("auto-increment");
4
+ function assignSequenceIdentifiers(message, sequence = { current: 0 }) {
5
+ if (message instanceof ArgumentMessage || message instanceof ElementMessage || message instanceof ChoiceMessage) {
6
+ if (message.identifier === AUTO_INCREMENT_IDENTIFIER) message.identifier = `${sequence.current++}`;
7
+ }
8
+ if (message instanceof CompositeMessage || message instanceof ElementMessage) for (const child of message.children) assignSequenceIdentifiers(child, sequence);
9
+ if (message instanceof ChoiceMessage) for (const branch of message.branches) {
10
+ if (branch.identifier === AUTO_INCREMENT_IDENTIFIER) branch.identifier = `${sequence.current++}`;
11
+ assignSequenceIdentifiers(branch.value, sequence);
12
+ }
13
+ }
14
+ //#endregion
15
+ //#region src/features/messages/types.ts
16
+ var Base = class {
17
+ toICUString() {
18
+ return convertMessageToIcu(this);
19
+ }
20
+ toHashString() {
21
+ const context = this instanceof CompositeMessage ? this.descriptor.context : void 0;
22
+ return generateHash(this.toICUString(), context);
23
+ }
24
+ };
25
+ var LiteralMessage = class extends Base {
26
+ constructor(text) {
27
+ super();
28
+ this.text = text;
29
+ }
30
+ };
31
+ var ArgumentMessage = class extends Base {
32
+ constructor(identifier, expression) {
33
+ super();
34
+ this.identifier = identifier;
35
+ this.expression = expression;
36
+ }
37
+ };
38
+ var ElementMessage = class extends Base {
39
+ constructor(identifier, children, expression) {
40
+ super();
41
+ this.identifier = identifier;
42
+ this.children = children;
43
+ this.expression = expression;
44
+ }
45
+ };
46
+ var ChoiceMessage = class extends Base {
47
+ constructor(kind, identifier, branches, expression) {
48
+ super();
49
+ this.kind = kind;
50
+ this.identifier = identifier;
51
+ this.branches = branches;
52
+ this.expression = expression;
53
+ }
54
+ };
55
+ var CompositeMessage = class extends Base {
56
+ constructor(descriptor, comments, references, children, accessor) {
57
+ super();
58
+ this.descriptor = descriptor;
59
+ this.comments = comments;
60
+ this.references = references;
61
+ this.children = children;
62
+ this.accessor = accessor;
63
+ }
64
+ };
65
+ //#endregion
66
+ //#region src/features/messages/convert.ts
67
+ function convertMessageToIcu(message) {
68
+ function internalConvertMessageToIcu(message) {
69
+ switch (true) {
70
+ case message instanceof LiteralMessage: return String(message.text);
71
+ case message instanceof ArgumentMessage: return `{${String(message.identifier)}}`;
72
+ case message instanceof ElementMessage: {
73
+ const children = message.children.map((m) => internalConvertMessageToIcu(m)).join("");
74
+ return `<${String(message.identifier)}>${children}</${String(message.identifier)}>`;
75
+ }
76
+ case message instanceof ChoiceMessage: {
77
+ const branches = message.branches.map(({ identifier, value }) => ({
78
+ identifier: Number.isNaN(+String(identifier)) ? String(identifier) : `=${+String(identifier)}`,
79
+ value: internalConvertMessageToIcu(value)
80
+ })).map(({ identifier, value }) => ` ${identifier} {${value}}\n`).join("");
81
+ const format = message.kind === "ordinal" ? "selectordinal" : message.kind;
82
+ return `{${String(message.identifier)}, ${format},\n${branches}}`;
83
+ }
84
+ case message instanceof CompositeMessage: return Object.entries(message.children).map(([, m]) => internalConvertMessageToIcu(m)).join("");
85
+ default: throw new Error("Unknown message type", { cause: message });
86
+ }
87
+ }
88
+ return internalConvertMessageToIcu(message).trim();
89
+ }
90
+ //#endregion
91
+ export { AUTO_INCREMENT_IDENTIFIER, ArgumentMessage, ChoiceMessage, CompositeMessage, ElementMessage, LiteralMessage, assignSequenceIdentifiers, convertMessageToIcu, generateHash };
@@ -0,0 +1,17 @@
1
+ require("./index.cjs");
2
+ let js_sha256 = require("js-sha256");
3
+ //#region src/features/messages/hash.ts
4
+ function generateHash(input, context) {
5
+ const hasher = js_sha256.sha256.create();
6
+ hasher.update(`${input}\u{001F}${context || ""}`);
7
+ const elements = hasher.toString().match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) || [];
8
+ const bytes = Uint8Array.from(elements);
9
+ return btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "").slice(0, 6);
10
+ }
11
+ //#endregion
12
+ Object.defineProperty(exports, "generateHash", {
13
+ enumerable: true,
14
+ get: function() {
15
+ return generateHash;
16
+ }
17
+ });
@@ -0,0 +1,11 @@
1
+ import { sha256 } from "js-sha256";
2
+ //#region src/features/messages/hash.ts
3
+ function generateHash(input, context) {
4
+ const hasher = sha256.create();
5
+ hasher.update(`${input}\u{001F}${context || ""}`);
6
+ const elements = hasher.toString().match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) || [];
7
+ const bytes = Uint8Array.from(elements);
8
+ return btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "").slice(0, 6);
9
+ }
10
+ //#endregion
11
+ export { generateHash as t };
package/dist/index.cjs ADDED
@@ -0,0 +1,77 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let picomatch = require("picomatch");
25
+ picomatch = __toESM(picomatch, 1);
26
+ let zod = require("zod");
27
+ zod = __toESM(zod, 1);
28
+ zod.object({
29
+ message: zod.string(),
30
+ translation: zod.string().optional(),
31
+ id: zod.string().optional(),
32
+ context: zod.string().optional(),
33
+ comments: zod.string().array(),
34
+ references: zod.string().array()
35
+ });
36
+ const Formatter = zod.object({
37
+ extension: zod.templateLiteral([".", zod.string()]),
38
+ parse: zod.custom((v) => typeof v === "function"),
39
+ stringify: zod.custom((v) => typeof v === "function")
40
+ });
41
+ const Transformer = zod.object({
42
+ match: zod.custom((v) => typeof v === "function"),
43
+ extract: zod.custom((v) => typeof v === "function"),
44
+ transform: zod.custom((v) => typeof v === "function")
45
+ });
46
+ const Bucket = zod.object({
47
+ include: zod.string().array(),
48
+ exclude: zod.string().array().optional(),
49
+ output: zod.templateLiteral([
50
+ zod.string(),
51
+ "{locale}",
52
+ zod.string(),
53
+ ".{extension}"
54
+ ]),
55
+ formatter: Formatter,
56
+ transformer: Transformer.transform((t) => [t]).or(Transformer.array()).transform((t) => ({
57
+ match: (id) => t.some((t) => t.match(id)),
58
+ extract: (code, id) => t.flatMap((t) => t.match(id) ? t.extract(code, id) : []),
59
+ transform: (code, id) => t.reduce((p, t) => t.match(id) ? t.transform(p, id) : p, code)
60
+ }))
61
+ }).transform((v) => ({
62
+ ...v,
63
+ match: (0, picomatch.default)(v.include, { ignore: v.exclude }),
64
+ output: Object.assign(v.output, { match: (0, picomatch.default)(v.output.replace("{locale}", "*").replace("{extension}", v.formatter.extension.slice(1))) })
65
+ }));
66
+ const Config = zod.object({
67
+ locales: zod.tuple([zod.string()], zod.string()),
68
+ buckets: Bucket.array()
69
+ });
70
+ //#endregion
71
+ //#region src/index.ts
72
+ function defineConfig(config) {
73
+ return Config.parse(config);
74
+ }
75
+ //#endregion
76
+ exports.__toESM = __toESM;
77
+ exports.defineConfig = defineConfig;
@@ -0,0 +1,38 @@
1
+ import { a as Transformer, i as Message, n as Config, r as Formatter, t as Bucket } from "./shapes-CJyTfZXd.cjs";
2
+ import { input } from "zod";
3
+ import * as _$picomatch_lib_picomatch_js0 from "picomatch/lib/picomatch.js";
4
+
5
+ //#region src/index.d.ts
6
+ declare function defineConfig<C extends input<typeof Config>>(config: C): {
7
+ locales: [string, ...string[]];
8
+ buckets: {
9
+ match: (id: string) => boolean;
10
+ output: `${string}{locale}${string}.{extension}` & {
11
+ match: _$picomatch_lib_picomatch_js0.Matcher;
12
+ };
13
+ include: string[];
14
+ formatter: {
15
+ extension: `.${string}`;
16
+ parse: (content: string) => Message[];
17
+ stringify: (messages: Message[], context: {
18
+ locale: string;
19
+ existingContent?: string;
20
+ }) => string;
21
+ };
22
+ transformer: {
23
+ match: (id: string) => boolean;
24
+ extract: (code: string, id: string) => {
25
+ message: string;
26
+ comments: string[];
27
+ references: string[];
28
+ translation?: string | undefined;
29
+ id?: string | undefined;
30
+ context?: string | undefined;
31
+ }[];
32
+ transform: (code: string, id: string) => string;
33
+ };
34
+ exclude?: string[] | undefined;
35
+ }[];
36
+ };
37
+ //#endregion
38
+ export { Bucket, Config, Formatter, Message, Transformer, defineConfig };
@@ -0,0 +1,38 @@
1
+ import { a as Transformer, i as Message, n as Config, r as Formatter, t as Bucket } from "./shapes-DETrtvZf.mjs";
2
+ import { input } from "zod";
3
+ import * as _$picomatch_lib_picomatch_js0 from "picomatch/lib/picomatch.js";
4
+
5
+ //#region src/index.d.ts
6
+ declare function defineConfig<C extends input<typeof Config>>(config: C): {
7
+ locales: [string, ...string[]];
8
+ buckets: {
9
+ match: (id: string) => boolean;
10
+ output: `${string}{locale}${string}.{extension}` & {
11
+ match: _$picomatch_lib_picomatch_js0.Matcher;
12
+ };
13
+ include: string[];
14
+ formatter: {
15
+ extension: `.${string}`;
16
+ parse: (content: string) => Message[];
17
+ stringify: (messages: Message[], context: {
18
+ locale: string;
19
+ existingContent?: string;
20
+ }) => string;
21
+ };
22
+ transformer: {
23
+ match: (id: string) => boolean;
24
+ extract: (code: string, id: string) => {
25
+ message: string;
26
+ comments: string[];
27
+ references: string[];
28
+ translation?: string | undefined;
29
+ id?: string | undefined;
30
+ context?: string | undefined;
31
+ }[];
32
+ transform: (code: string, id: string) => string;
33
+ };
34
+ exclude?: string[] | undefined;
35
+ }[];
36
+ };
37
+ //#endregion
38
+ export { Bucket, Config, Formatter, Message, Transformer, defineConfig };
package/dist/index.mjs ADDED
@@ -0,0 +1,51 @@
1
+ import picomatch from "picomatch";
2
+ import * as z from "zod";
3
+ z.object({
4
+ message: z.string(),
5
+ translation: z.string().optional(),
6
+ id: z.string().optional(),
7
+ context: z.string().optional(),
8
+ comments: z.string().array(),
9
+ references: z.string().array()
10
+ });
11
+ const Formatter = z.object({
12
+ extension: z.templateLiteral([".", z.string()]),
13
+ parse: z.custom((v) => typeof v === "function"),
14
+ stringify: z.custom((v) => typeof v === "function")
15
+ });
16
+ const Transformer = z.object({
17
+ match: z.custom((v) => typeof v === "function"),
18
+ extract: z.custom((v) => typeof v === "function"),
19
+ transform: z.custom((v) => typeof v === "function")
20
+ });
21
+ const Bucket = z.object({
22
+ include: z.string().array(),
23
+ exclude: z.string().array().optional(),
24
+ output: z.templateLiteral([
25
+ z.string(),
26
+ "{locale}",
27
+ z.string(),
28
+ ".{extension}"
29
+ ]),
30
+ formatter: Formatter,
31
+ transformer: Transformer.transform((t) => [t]).or(Transformer.array()).transform((t) => ({
32
+ match: (id) => t.some((t) => t.match(id)),
33
+ extract: (code, id) => t.flatMap((t) => t.match(id) ? t.extract(code, id) : []),
34
+ transform: (code, id) => t.reduce((p, t) => t.match(id) ? t.transform(p, id) : p, code)
35
+ }))
36
+ }).transform((v) => ({
37
+ ...v,
38
+ match: picomatch(v.include, { ignore: v.exclude }),
39
+ output: Object.assign(v.output, { match: picomatch(v.output.replace("{locale}", "*").replace("{extension}", v.formatter.extension.slice(1))) })
40
+ }));
41
+ const Config = z.object({
42
+ locales: z.tuple([z.string()], z.string()),
43
+ buckets: Bucket.array()
44
+ });
45
+ //#endregion
46
+ //#region src/index.ts
47
+ function defineConfig(config) {
48
+ return Config.parse(config);
49
+ }
50
+ //#endregion
51
+ export { defineConfig };
@@ -0,0 +1,115 @@
1
+ import { createRequire } from "node:module";
2
+ import { dirname, extname, join, parse } from "node:path";
3
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { createHash } from "node:crypto";
5
+ import { tmpdir } from "node:os";
6
+ //#region src/features/loader/files.ts
7
+ const SUPPORTED_CONFIG_FILES = [
8
+ "saykit.config.js",
9
+ "saykit.config.cjs",
10
+ "saykit.config.mjs",
11
+ "saykit.config.ts",
12
+ "saykit.config.mts",
13
+ "saykit.config.cts"
14
+ ];
15
+ function getConfigFileCandidates(name) {
16
+ return SUPPORTED_CONFIG_FILES.map((file) => file.replace("saykit", name));
17
+ }
18
+ function findConfigFile(moduleName, projectDir) {
19
+ for (const fileName of getConfigFileCandidates(moduleName)) {
20
+ const id = join(projectDir, fileName);
21
+ if (existsSync(id)) return { id };
22
+ }
23
+ return null;
24
+ }
25
+ //#endregion
26
+ //#region src/features/loader/module.ts
27
+ function findNearestTsConfig(fromPath) {
28
+ let dir = dirname(fromPath);
29
+ const { root } = parse(dir);
30
+ while (true) {
31
+ const candidate = join(dir, "tsconfig.json");
32
+ if (existsSync(candidate)) return candidate;
33
+ if (dir === root) return null;
34
+ dir = dirname(dir);
35
+ }
36
+ }
37
+ function findCacheDir(fromPath) {
38
+ let dir = dirname(fromPath);
39
+ const { root } = parse(dir);
40
+ while (true) {
41
+ const nm = join(dir, "node_modules");
42
+ if (existsSync(nm)) return join(nm, ".cache", "saykit", "config");
43
+ if (dir === root) return join(tmpdir(), "saykit", "config");
44
+ dir = dirname(dir);
45
+ }
46
+ }
47
+ function transpile(path, tsConfigPath, require) {
48
+ const ts = require("typescript");
49
+ const { config: tsConfig, error } = tsConfigPath ? ts.readConfigFile(tsConfigPath, ts.sys.readFile) : {
50
+ config: {},
51
+ error: null
52
+ };
53
+ if (error) throw error;
54
+ tsConfig.compilerOptions = {
55
+ ...tsConfig.compilerOptions,
56
+ allowJs: true,
57
+ esModuleInterop: true,
58
+ module: ts.ModuleKind.CommonJS,
59
+ moduleResolution: ts.ModuleResolutionKind.NodeJs,
60
+ target: ts.ScriptTarget.ES2022,
61
+ noEmit: false
62
+ };
63
+ return ts.transpileModule(readFileSync(path, "utf8"), tsConfig).outputText;
64
+ }
65
+ function loadWithCache(path) {
66
+ const require = createRequire(path);
67
+ const mtimeMs = statSync(path).mtimeMs;
68
+ const tsConfigPath = findNearestTsConfig(path);
69
+ const tsConfigMtimeMs = tsConfigPath ? statSync(tsConfigPath).mtimeMs : 0;
70
+ const hash = createHash("sha1").update(`${path}\0${tsConfigPath ?? ""}\0${tsConfigMtimeMs}`).digest("hex").slice(0, 16);
71
+ const cacheDir = findCacheDir(path);
72
+ const cachePath = join(cacheDir, `${hash}.${mtimeMs}.cjs`);
73
+ try {
74
+ if (!existsSync(cachePath)) {
75
+ mkdirSync(cacheDir, { recursive: true });
76
+ writeFileSync(cachePath, transpile(path, tsConfigPath, require));
77
+ if (existsSync(cacheDir)) {
78
+ for (const entry of readdirSync(cacheDir)) if (entry.startsWith(`${hash}.`) && entry !== `${hash}.${mtimeMs}.cjs`) try {
79
+ unlinkSync(join(cacheDir, entry));
80
+ } catch {}
81
+ }
82
+ }
83
+ const resolved = require.resolve(cachePath);
84
+ delete require.cache[resolved];
85
+ const module = require(cachePath);
86
+ delete require.cache[resolved];
87
+ return module?.default ?? module;
88
+ } catch (error) {
89
+ throw new Error("Failed to import module", { cause: error });
90
+ }
91
+ }
92
+ const js = (path) => loadWithCache(path);
93
+ const ts = (path) => loadWithCache(path);
94
+ const configLoaders = Object.freeze({
95
+ ".js": js,
96
+ ".mjs": js,
97
+ ".cjs": js,
98
+ ".ts": ts,
99
+ ".mts": ts,
100
+ ".cts": ts
101
+ });
102
+ //#endregion
103
+ //#region src/features/loader/resolve.ts
104
+ function resolveConfig(name = "saykit") {
105
+ const file = findConfigFile(name, process.cwd());
106
+ if (!file) throw new Error(`Could not find config file for "${name}"`);
107
+ const ext = extname(file.id).toLowerCase();
108
+ const load = ext in configLoaders ? configLoaders[ext] : null;
109
+ if (!load) throw new Error(`Unsupported config file type "${ext}" for "${name}"`);
110
+ const config = load(file.id);
111
+ if (!config || typeof config !== "object") throw new Error(`Invalid config file for "${name}"`);
112
+ return config;
113
+ }
114
+ //#endregion
115
+ export { resolveConfig as t };