@dependabit/manifest 0.1.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.
@@ -0,0 +1,266 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { writeFile, mkdir, rm } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import {
5
+ readConfig,
6
+ parseConfig,
7
+ stringifyConfig,
8
+ getEffectiveMonitoringRules,
9
+ shouldIgnoreUrl
10
+ } from '../src/config.js';
11
+ import type { DependabitConfig } from '../src/schema.js';
12
+
13
+ const TEST_DIR = '/tmp/dependabit-config-tests';
14
+
15
+ describe('Config Operations Tests', () => {
16
+ beforeEach(async () => {
17
+ await mkdir(TEST_DIR, { recursive: true });
18
+ });
19
+
20
+ afterEach(async () => {
21
+ await rm(TEST_DIR, { recursive: true, force: true });
22
+ });
23
+
24
+ describe('readConfig and parseConfig', () => {
25
+ it('should parse valid YAML config', async () => {
26
+ const yaml = `
27
+ version: "1"
28
+ llm:
29
+ provider: github-copilot
30
+ model: gpt-4
31
+ maxTokens: 4000
32
+ temperature: 0.3
33
+ schedule:
34
+ interval: daily
35
+ time: "02:00"
36
+ timezone: UTC
37
+ `;
38
+
39
+ const config = parseConfig(yaml);
40
+ expect(config.version).toBe('1');
41
+ expect(config.llm?.provider).toBe('github-copilot');
42
+ expect(config.schedule.interval).toBe('daily');
43
+ });
44
+
45
+ it('should read config from file', async () => {
46
+ const yaml = `
47
+ version: "1"
48
+ schedule:
49
+ interval: weekly
50
+ day: monday
51
+ `;
52
+
53
+ const path = join(TEST_DIR, 'config.yml');
54
+ await writeFile(path, yaml, 'utf-8');
55
+
56
+ const config = await readConfig(path);
57
+ expect(config.version).toBe('1');
58
+ expect(config.schedule.interval).toBe('weekly');
59
+ });
60
+
61
+ it('should apply defaults for missing fields', () => {
62
+ const yaml = `
63
+ version: "1"
64
+ `;
65
+
66
+ const config = parseConfig(yaml);
67
+ expect(config.schedule.interval).toBe('daily');
68
+ expect(config.schedule.timezone).toBe('UTC');
69
+ });
70
+
71
+ it('should validate config structure', () => {
72
+ const invalidYaml = `
73
+ version: "2"
74
+ `;
75
+
76
+ expect(() => parseConfig(invalidYaml)).toThrow();
77
+ });
78
+ });
79
+
80
+ describe('stringifyConfig', () => {
81
+ it('should convert config to YAML', () => {
82
+ const config: DependabitConfig = {
83
+ version: '1',
84
+ schedule: {
85
+ interval: 'daily',
86
+ timezone: 'UTC'
87
+ }
88
+ };
89
+
90
+ const yaml = stringifyConfig(config);
91
+ expect(yaml).toContain('version:');
92
+ expect(yaml).toContain('daily');
93
+ });
94
+
95
+ it('should validate before stringifying', () => {
96
+ const invalid = {
97
+ version: '2'
98
+ } as any;
99
+
100
+ expect(() => stringifyConfig(invalid)).toThrow();
101
+ });
102
+ });
103
+
104
+ describe('getEffectiveMonitoringRules', () => {
105
+ it('should return global defaults when no override', () => {
106
+ const config: DependabitConfig = {
107
+ version: '1',
108
+ schedule: {
109
+ interval: 'daily',
110
+ timezone: 'UTC'
111
+ },
112
+ monitoring: {
113
+ enabled: true,
114
+ autoUpdate: true,
115
+ falsePositiveThreshold: 0.1
116
+ }
117
+ };
118
+
119
+ const rules = getEffectiveMonitoringRules(config, 'https://github.com/microsoft/TypeScript');
120
+
121
+ expect(rules.enabled).toBe(true);
122
+ expect(rules.checkFrequency).toBe('daily');
123
+ expect(rules.ignoreChanges).toBe(false);
124
+ });
125
+
126
+ it('should apply dependency-specific overrides', () => {
127
+ const config: DependabitConfig = {
128
+ version: '1',
129
+ schedule: {
130
+ interval: 'daily',
131
+ timezone: 'UTC'
132
+ },
133
+ dependencies: [
134
+ {
135
+ url: 'https://github.com/microsoft/TypeScript',
136
+ schedule: {
137
+ interval: 'hourly',
138
+ timezone: 'UTC'
139
+ },
140
+ monitoring: {
141
+ enabled: true,
142
+ checkFrequency: 'hourly',
143
+ ignoreChanges: false
144
+ }
145
+ }
146
+ ]
147
+ };
148
+
149
+ const rules = getEffectiveMonitoringRules(config, 'https://github.com/microsoft/TypeScript');
150
+
151
+ expect(rules.checkFrequency).toBe('hourly');
152
+ });
153
+
154
+ it('should merge global and override settings', () => {
155
+ const config: DependabitConfig = {
156
+ version: '1',
157
+ schedule: {
158
+ interval: 'daily',
159
+ timezone: 'UTC'
160
+ },
161
+ monitoring: {
162
+ enabled: true,
163
+ autoUpdate: true,
164
+ falsePositiveThreshold: 0.1
165
+ },
166
+ dependencies: [
167
+ {
168
+ url: 'https://github.com/microsoft/TypeScript',
169
+ monitoring: {
170
+ enabled: true,
171
+ checkFrequency: 'hourly',
172
+ ignoreChanges: true
173
+ }
174
+ }
175
+ ]
176
+ };
177
+
178
+ const rules = getEffectiveMonitoringRules(config, 'https://github.com/microsoft/TypeScript');
179
+
180
+ expect(rules.enabled).toBe(true);
181
+ expect(rules.checkFrequency).toBe('hourly');
182
+ expect(rules.ignoreChanges).toBe(true);
183
+ });
184
+ });
185
+
186
+ describe('shouldIgnoreUrl', () => {
187
+ it('should return false when no ignore rules', () => {
188
+ const config: DependabitConfig = {
189
+ version: '1',
190
+ schedule: {
191
+ interval: 'daily',
192
+ timezone: 'UTC'
193
+ }
194
+ };
195
+
196
+ expect(shouldIgnoreUrl(config, 'https://github.com/test/repo')).toBe(false);
197
+ });
198
+
199
+ it('should match exact URLs', () => {
200
+ const config: DependabitConfig = {
201
+ version: '1',
202
+ schedule: {
203
+ interval: 'daily',
204
+ timezone: 'UTC'
205
+ },
206
+ ignore: {
207
+ urls: ['https://example.com/deprecated']
208
+ }
209
+ };
210
+
211
+ expect(shouldIgnoreUrl(config, 'https://example.com/deprecated')).toBe(true);
212
+ expect(shouldIgnoreUrl(config, 'https://example.com/current')).toBe(false);
213
+ });
214
+
215
+ it('should match regex patterns', () => {
216
+ const config: DependabitConfig = {
217
+ version: '1',
218
+ schedule: {
219
+ interval: 'daily',
220
+ timezone: 'UTC'
221
+ },
222
+ ignore: {
223
+ patterns: ['.*\\.example\\.com.*', '.*deprecated.*']
224
+ }
225
+ };
226
+
227
+ expect(shouldIgnoreUrl(config, 'https://subdomain.example.com/path')).toBe(true);
228
+ expect(shouldIgnoreUrl(config, 'https://github.com/deprecated-repo')).toBe(true);
229
+ expect(shouldIgnoreUrl(config, 'https://github.com/active-repo')).toBe(false);
230
+ });
231
+
232
+ it('should match either URLs or patterns', () => {
233
+ const config: DependabitConfig = {
234
+ version: '1',
235
+ schedule: {
236
+ interval: 'daily',
237
+ timezone: 'UTC'
238
+ },
239
+ ignore: {
240
+ urls: ['https://exact-match.com'],
241
+ patterns: ['.*pattern.*']
242
+ }
243
+ };
244
+
245
+ expect(shouldIgnoreUrl(config, 'https://exact-match.com')).toBe(true);
246
+ expect(shouldIgnoreUrl(config, 'https://some-pattern-match.com')).toBe(true);
247
+ });
248
+
249
+ it('should handle invalid regex patterns gracefully', () => {
250
+ const config: DependabitConfig = {
251
+ version: '1',
252
+ schedule: {
253
+ interval: 'daily',
254
+ timezone: 'UTC'
255
+ },
256
+ ignore: {
257
+ patterns: ['[invalid', '.*valid.*']
258
+ }
259
+ };
260
+
261
+ // Invalid pattern should be skipped, valid pattern should work
262
+ expect(shouldIgnoreUrl(config, 'https://validurl.com')).toBe(true);
263
+ expect(shouldIgnoreUrl(config, 'https://other.com')).toBe(false);
264
+ });
265
+ });
266
+ });
package/src/config.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import YAML from 'yaml';
3
+ import { type DependabitConfig } from './schema.js';
4
+ import { validateConfig } from './validator.js';
5
+
6
+ /**
7
+ * Parse and validate a YAML configuration file
8
+ */
9
+ export async function readConfig(path: string): Promise<DependabitConfig> {
10
+ const content = await readFile(path, 'utf-8');
11
+ const data = YAML.parse(content);
12
+ return validateConfig(data);
13
+ }
14
+
15
+ /**
16
+ * Parse YAML string to config
17
+ */
18
+ export function parseConfig(yaml: string): DependabitConfig {
19
+ const data = YAML.parse(yaml);
20
+ return validateConfig(data);
21
+ }
22
+
23
+ /**
24
+ * Convert config to YAML string
25
+ */
26
+ export function stringifyConfig(config: DependabitConfig): string {
27
+ // Validate before stringifying
28
+ validateConfig(config);
29
+ return YAML.stringify(config);
30
+ }
31
+
32
+ /**
33
+ * Get effective monitoring rules for a dependency
34
+ * Merges global config with dependency-specific overrides
35
+ */
36
+ export function getEffectiveMonitoringRules(
37
+ config: DependabitConfig,
38
+ dependencyUrl: string
39
+ ): {
40
+ enabled: boolean;
41
+ checkFrequency: 'hourly' | 'daily' | 'weekly' | 'monthly';
42
+ ignoreChanges: boolean;
43
+ } {
44
+ // Start with global defaults
45
+ const globalEnabled = config.monitoring?.enabled ?? true;
46
+ const globalCheckFrequency = config.schedule?.interval ?? 'daily';
47
+
48
+ // Find dependency-specific override
49
+ const override = config.dependencies?.find((dep) => dep.url === dependencyUrl);
50
+
51
+ if (override?.monitoring) {
52
+ return {
53
+ enabled: override.monitoring.enabled ?? globalEnabled,
54
+ checkFrequency:
55
+ override.monitoring.checkFrequency ?? override.schedule?.interval ?? globalCheckFrequency,
56
+ ignoreChanges: override.monitoring.ignoreChanges ?? false
57
+ };
58
+ }
59
+
60
+ return {
61
+ enabled: globalEnabled,
62
+ checkFrequency: globalCheckFrequency,
63
+ ignoreChanges: false
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Check if a URL should be ignored based on config
69
+ */
70
+ export function shouldIgnoreUrl(config: DependabitConfig, url: string): boolean {
71
+ if (!config.ignore) {
72
+ return false;
73
+ }
74
+
75
+ // Check exact URL matches
76
+ if (config.ignore.urls?.includes(url)) {
77
+ return true;
78
+ }
79
+
80
+ // Check regex patterns with error handling
81
+ if (config.ignore.patterns) {
82
+ for (const pattern of config.ignore.patterns) {
83
+ try {
84
+ const regex = new RegExp(pattern);
85
+ if (regex.test(url)) {
86
+ return true;
87
+ }
88
+ } catch {
89
+ // Invalid regex pattern - log warning but continue
90
+ console.warn(`Invalid regex pattern in config.ignore.patterns: ${pattern}`);
91
+ }
92
+ }
93
+ }
94
+
95
+ return false;
96
+ }
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ // Entry point for @dependabit/manifest
2
+
3
+ // Export schemas and types
4
+ export * from './schema.js';
5
+
6
+ // Export validators
7
+ export * from './validator.js';
8
+
9
+ // Export manifest operations
10
+ export * from './manifest.js';
11
+
12
+ // Export config operations
13
+ export * from './config.js';
14
+
15
+ // Export size checking
16
+ export * from './size-check.js';