@cullit/config 1.0.0 → 1.5.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.
- package/dist/index.d.ts +10 -1
- package/dist/index.js +63 -15
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ interface SourceConfig {
|
|
|
17
17
|
type: string;
|
|
18
18
|
owner?: string;
|
|
19
19
|
repo?: string;
|
|
20
|
+
repoPath?: string;
|
|
20
21
|
enrichment?: EnrichmentType[];
|
|
21
22
|
}
|
|
22
23
|
interface PublishTarget {
|
|
@@ -54,10 +55,18 @@ interface ConfluenceConfig {
|
|
|
54
55
|
interface NotionConfig {
|
|
55
56
|
databaseId: string;
|
|
56
57
|
}
|
|
58
|
+
interface RepoSource {
|
|
59
|
+
url?: string;
|
|
60
|
+
path?: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
from?: string;
|
|
63
|
+
to?: string;
|
|
64
|
+
}
|
|
57
65
|
interface CullConfig {
|
|
58
66
|
ai: AIConfig;
|
|
59
67
|
source: SourceConfig;
|
|
60
68
|
publish: PublishTarget[];
|
|
69
|
+
repos?: RepoSource[];
|
|
61
70
|
jira?: JiraConfig;
|
|
62
71
|
linear?: LinearConfig;
|
|
63
72
|
openclaw?: OpenClawConfig;
|
|
@@ -74,4 +83,4 @@ interface CullConfig {
|
|
|
74
83
|
*/
|
|
75
84
|
declare function loadConfig(cwdOrPath?: string): CullConfig;
|
|
76
85
|
|
|
77
|
-
export { type AIConfig, type AIProvider, type Audience, type BitbucketConfig, type ConfluenceConfig, type CullConfig, type EnrichmentType, type GitLabConfig, type JiraConfig, type LinearConfig, type NotionConfig, type OpenClawConfig, type OutputFormat, type PublishTarget, type PublisherType, type SourceConfig, type Tone, loadConfig };
|
|
86
|
+
export { type AIConfig, type AIProvider, type Audience, type BitbucketConfig, type ConfluenceConfig, type CullConfig, type EnrichmentType, type GitLabConfig, type JiraConfig, type LinearConfig, type NotionConfig, type OpenClawConfig, type OutputFormat, type PublishTarget, type PublisherType, type RepoSource, type SourceConfig, type Tone, loadConfig };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,14 @@ function loadConfig(cwdOrPath = process.cwd()) {
|
|
|
25
25
|
return mergeWithDefaults(resolved);
|
|
26
26
|
}
|
|
27
27
|
function parseSimpleYaml(raw) {
|
|
28
|
+
const RESERVED_KEYS = ["__proto__", "constructor", "prototype"];
|
|
29
|
+
const safeKey = (k) => {
|
|
30
|
+
const trimmed = k.trim();
|
|
31
|
+
if (RESERVED_KEYS.includes(trimmed)) {
|
|
32
|
+
throw new Error(`Config error: reserved key "${trimmed}" is not allowed`);
|
|
33
|
+
}
|
|
34
|
+
return trimmed;
|
|
35
|
+
};
|
|
28
36
|
const result = {};
|
|
29
37
|
let currentSection = "";
|
|
30
38
|
let currentArray = null;
|
|
@@ -37,10 +45,10 @@ function parseSimpleYaml(raw) {
|
|
|
37
45
|
const [key, ...valParts] = trimmed.split(":");
|
|
38
46
|
const val = valParts.join(":").trim();
|
|
39
47
|
if (val) {
|
|
40
|
-
result[key
|
|
48
|
+
result[safeKey(key)] = parseValue(val);
|
|
41
49
|
} else {
|
|
42
|
-
result[key
|
|
43
|
-
currentSection = key
|
|
50
|
+
result[safeKey(key)] = {};
|
|
51
|
+
currentSection = safeKey(key);
|
|
44
52
|
}
|
|
45
53
|
currentArray = null;
|
|
46
54
|
continue;
|
|
@@ -58,7 +66,7 @@ function parseSimpleYaml(raw) {
|
|
|
58
66
|
}
|
|
59
67
|
const obj = {};
|
|
60
68
|
const [k, ...vParts] = content.split(":");
|
|
61
|
-
obj[k
|
|
69
|
+
obj[safeKey(k)] = parseValue(vParts.join(":").trim());
|
|
62
70
|
currentArray.push(obj);
|
|
63
71
|
} else {
|
|
64
72
|
if (currentSection && currentArrayKey) {
|
|
@@ -82,15 +90,15 @@ function parseSimpleYaml(raw) {
|
|
|
82
90
|
if (currentArray && currentArray.length > 0) {
|
|
83
91
|
const lastObj = currentArray[currentArray.length - 1];
|
|
84
92
|
if (typeof lastObj === "object") {
|
|
85
|
-
lastObj[key
|
|
93
|
+
lastObj[safeKey(key)] = parseValue(val);
|
|
86
94
|
continue;
|
|
87
95
|
}
|
|
88
96
|
}
|
|
89
97
|
if (currentSection) {
|
|
90
|
-
result[currentSection][key
|
|
98
|
+
result[currentSection][safeKey(key)] = parseValue(val);
|
|
91
99
|
}
|
|
92
100
|
} else {
|
|
93
|
-
currentArrayKey = key
|
|
101
|
+
currentArrayKey = safeKey(key);
|
|
94
102
|
currentArray = null;
|
|
95
103
|
if (currentSection) {
|
|
96
104
|
result[currentSection][currentArrayKey] = {};
|
|
@@ -118,9 +126,11 @@ function parseValue(val) {
|
|
|
118
126
|
return val;
|
|
119
127
|
}
|
|
120
128
|
function resolveEnvVars(obj) {
|
|
121
|
-
if (typeof obj === "string"
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
if (typeof obj === "string") {
|
|
130
|
+
if (obj.startsWith("$")) {
|
|
131
|
+
const envKey = obj.startsWith("${") && obj.endsWith("}") ? obj.slice(2, -1) : obj.substring(1);
|
|
132
|
+
return process.env[envKey] || obj;
|
|
133
|
+
}
|
|
124
134
|
}
|
|
125
135
|
if (Array.isArray(obj)) return obj.map(resolveEnvVars);
|
|
126
136
|
if (obj && typeof obj === "object") {
|
|
@@ -145,15 +155,53 @@ function mergeWithDefaults(parsed) {
|
|
|
145
155
|
publish: normalizePublishTargets(parsed.publish || DEFAULT_CONFIG.publish),
|
|
146
156
|
jira: parsed.jira,
|
|
147
157
|
linear: parsed.linear,
|
|
148
|
-
openclaw: parsed.openclaw
|
|
158
|
+
openclaw: parsed.openclaw,
|
|
159
|
+
gitlab: parsed.gitlab,
|
|
160
|
+
bitbucket: parsed.bitbucket,
|
|
161
|
+
confluence: parsed.confluence,
|
|
162
|
+
notion: parsed.notion,
|
|
163
|
+
...parsed.repos ? { repos: validateRepos(parsed.repos) } : {}
|
|
149
164
|
};
|
|
150
165
|
}
|
|
166
|
+
function validateRepos(repos) {
|
|
167
|
+
if (!Array.isArray(repos)) {
|
|
168
|
+
throw new Error('Config error: "repos" must be an array');
|
|
169
|
+
}
|
|
170
|
+
return repos.map((repo, i) => {
|
|
171
|
+
if (!repo || typeof repo !== "object") {
|
|
172
|
+
throw new Error(`Config error: repos[${i}] must be an object`);
|
|
173
|
+
}
|
|
174
|
+
if (!repo.url && !repo.path) {
|
|
175
|
+
throw new Error(`Config error: repos[${i}] must have either "url" or "path"`);
|
|
176
|
+
}
|
|
177
|
+
if (repo.url && typeof repo.url !== "string") {
|
|
178
|
+
throw new Error(`Config error: repos[${i}].url must be a string`);
|
|
179
|
+
}
|
|
180
|
+
if (repo.path && typeof repo.path !== "string") {
|
|
181
|
+
throw new Error(`Config error: repos[${i}].path must be a string`);
|
|
182
|
+
}
|
|
183
|
+
return repo;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
151
186
|
function normalizePublishTargets(targets) {
|
|
152
187
|
return targets.map((t) => {
|
|
153
|
-
const normalized = {
|
|
154
|
-
if (t.
|
|
155
|
-
|
|
156
|
-
|
|
188
|
+
const normalized = { ...t };
|
|
189
|
+
if (t.webhook_url && !t.webhookUrl) {
|
|
190
|
+
normalized.webhookUrl = t.webhook_url;
|
|
191
|
+
delete normalized["webhook_url"];
|
|
192
|
+
}
|
|
193
|
+
if (t.parent_page_id && !t.parentPageId) {
|
|
194
|
+
normalized.parentPageId = t.parent_page_id;
|
|
195
|
+
delete normalized["parent_page_id"];
|
|
196
|
+
}
|
|
197
|
+
if (t.space_key && !t.spaceKey) {
|
|
198
|
+
normalized.spaceKey = t.space_key;
|
|
199
|
+
delete normalized["space_key"];
|
|
200
|
+
}
|
|
201
|
+
if (t.database_id && !t.databaseId) {
|
|
202
|
+
normalized.databaseId = t.database_id;
|
|
203
|
+
delete normalized["database_id"];
|
|
204
|
+
}
|
|
157
205
|
return normalized;
|
|
158
206
|
});
|
|
159
207
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cullit/config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Config loader for Cullit — YAML config parsing with env var resolution.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
29
|
-
"dev": "tsup src/index.ts --format esm --watch"
|
|
29
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
30
|
+
"test": "vitest run"
|
|
30
31
|
}
|
|
31
32
|
}
|