gdelt-ts-client 1.0.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,252 @@
1
+ /**
2
+ * Enhanced query builder with TypeScript template literal types and IntelliSense support
3
+ */
4
+ /**
5
+ * Fluent query builder for constructing complex GDELT queries with type safety
6
+ */
7
+ export declare class QueryBuilder {
8
+ private components;
9
+ /**
10
+ * Add a basic search term or phrase
11
+ */
12
+ search(term: string): this;
13
+ /**
14
+ * Add a phrase search (exact match)
15
+ */
16
+ phrase(phrase: string): this;
17
+ /**
18
+ * Add multiple terms with OR logic
19
+ */
20
+ anyOf(...terms: string[]): this;
21
+ /**
22
+ * Add multiple terms with AND logic
23
+ */
24
+ allOf(...terms: string[]): this;
25
+ /**
26
+ * Exclude a term or phrase
27
+ */
28
+ not(term: string): this;
29
+ /**
30
+ * Filter by domain
31
+ */
32
+ fromDomain(domain: string, exact?: boolean): this;
33
+ /**
34
+ * Filter by source country
35
+ */
36
+ fromCountry(country: string): this;
37
+ /**
38
+ * Filter by source language
39
+ */
40
+ inLanguage(language: string): this;
41
+ /**
42
+ * Filter by tone (emotional sentiment)
43
+ */
44
+ withTone(operator: '>' | '<' | '=', value: number): this;
45
+ /**
46
+ * Filter by absolute tone (emotional intensity)
47
+ */
48
+ withAbsoluteTone(operator: '>' | '<' | '=', value: number): this;
49
+ /**
50
+ * Filter for positive tone articles
51
+ */
52
+ withPositiveTone(threshold?: number): this;
53
+ /**
54
+ * Filter for negative tone articles
55
+ */
56
+ withNegativeTone(threshold?: number): this;
57
+ /**
58
+ * Filter for neutral tone articles
59
+ */
60
+ withNeutralTone(range?: number): this;
61
+ /**
62
+ * Filter for highly emotional articles (regardless of positive/negative)
63
+ */
64
+ withHighEmotion(threshold?: number): this;
65
+ /**
66
+ * Filter by GDELT theme
67
+ */
68
+ withTheme(theme: string): this;
69
+ /**
70
+ * Filter for images with specific tags
71
+ */
72
+ withImageTag(tag: string): this;
73
+ /**
74
+ * Filter for images with web tags
75
+ */
76
+ withImageWebTag(tag: string): this;
77
+ /**
78
+ * Filter for images with OCR/metadata content
79
+ */
80
+ withImageOCR(content: string): this;
81
+ /**
82
+ * Filter by image face count
83
+ */
84
+ withImageFaceCount(operator: '>' | '<' | '=', count: number): this;
85
+ /**
86
+ * Filter by image face tone
87
+ */
88
+ withImageFaceTone(operator: '>' | '<' | '=', tone: number): this;
89
+ /**
90
+ * Filter by how often image appears on web
91
+ */
92
+ withImageWebCount(operator: '>' | '<' | '=', count: number): this;
93
+ /**
94
+ * Filter for novel images (rarely seen on web)
95
+ */
96
+ withNovelImages(threshold?: number): this;
97
+ /**
98
+ * Filter for popular images (frequently seen on web)
99
+ */
100
+ withPopularImages(threshold?: number): this;
101
+ /**
102
+ * Add proximity constraint (words must appear within distance)
103
+ */
104
+ withProximity(distance: number, ...words: string[]): this;
105
+ /**
106
+ * Require word to appear minimum number of times
107
+ */
108
+ withRepeat(count: number, word: string): this;
109
+ /**
110
+ * Add custom query component
111
+ */
112
+ custom(query: string): this;
113
+ /**
114
+ * Group current components with parentheses
115
+ */
116
+ group(): this;
117
+ /**
118
+ * Clear all components and start fresh
119
+ */
120
+ clear(): this;
121
+ /**
122
+ * Build the final query string
123
+ */
124
+ build(): string;
125
+ /**
126
+ * Get a copy of the current components
127
+ */
128
+ getComponents(): string[];
129
+ /**
130
+ * Check if the builder has any components
131
+ */
132
+ isEmpty(): boolean;
133
+ }
134
+ /**
135
+ * Query builder specialized for article searches
136
+ */
137
+ export declare class ArticleQueryBuilder extends QueryBuilder {
138
+ /**
139
+ * Search for breaking news articles
140
+ */
141
+ breakingNews(): this;
142
+ /**
143
+ * Search for opinion articles
144
+ */
145
+ opinions(): this;
146
+ /**
147
+ * Search for local news
148
+ */
149
+ localNews(location?: string): this;
150
+ }
151
+ /**
152
+ * Query builder specialized for image searches
153
+ */
154
+ export declare class ImageQueryBuilder extends QueryBuilder {
155
+ /**
156
+ * Search for violent content images
157
+ */
158
+ violentContent(): this;
159
+ /**
160
+ * Search for medical content images
161
+ */
162
+ medicalContent(): this;
163
+ /**
164
+ * Search for disaster-related images
165
+ */
166
+ disasters(): this;
167
+ /**
168
+ * Search for political event images
169
+ */
170
+ politicalEvents(): this;
171
+ /**
172
+ * Search for happy/positive images
173
+ */
174
+ positiveImages(): this;
175
+ /**
176
+ * Search for sad/negative images
177
+ */
178
+ negativeImages(): this;
179
+ }
180
+ /**
181
+ * Create a new general query builder
182
+ */
183
+ export declare function createQuery(): QueryBuilder;
184
+ /**
185
+ * Create a new article-specialized query builder
186
+ */
187
+ export declare function createArticleQuery(): ArticleQueryBuilder;
188
+ /**
189
+ * Create a new image-specialized query builder
190
+ */
191
+ export declare function createImageQuery(): ImageQueryBuilder;
192
+ /**
193
+ * Create a quick phrase query
194
+ */
195
+ export declare function phrase(text: string): string;
196
+ /**
197
+ * Create a quick OR query
198
+ */
199
+ export declare function anyOf(...terms: string[]): string;
200
+ /**
201
+ * Create a quick exclusion query
202
+ */
203
+ export declare function exclude(term: string): string;
204
+ /**
205
+ * Create a domain filter
206
+ */
207
+ export declare function fromDomain(domain: string, exact?: boolean): string;
208
+ /**
209
+ * Create a country filter
210
+ */
211
+ export declare function fromCountry(country: string): string;
212
+ /**
213
+ * Create a language filter
214
+ */
215
+ export declare function inLanguage(language: string): string;
216
+ /**
217
+ * Create a tone filter
218
+ */
219
+ export declare function withTone(operator: '>' | '<' | '=', value: number): string;
220
+ /**
221
+ * Create a theme filter
222
+ */
223
+ export declare function withTheme(theme: string): string;
224
+ /**
225
+ * Validate that a query string is well-formed
226
+ */
227
+ export declare function isValidQuery(query: string): boolean;
228
+ /**
229
+ * Validate that a query has balanced quotes
230
+ */
231
+ export declare function hasBalancedQuotes(query: string): boolean;
232
+ /**
233
+ * Get query complexity score (approximate)
234
+ */
235
+ export declare function getQueryComplexity(query: string): number;
236
+ export declare const QueryHelpers: {
237
+ readonly createQuery: typeof createQuery;
238
+ readonly createArticleQuery: typeof createArticleQuery;
239
+ readonly createImageQuery: typeof createImageQuery;
240
+ readonly phrase: typeof phrase;
241
+ readonly anyOf: typeof anyOf;
242
+ readonly exclude: typeof exclude;
243
+ readonly fromDomain: typeof fromDomain;
244
+ readonly fromCountry: typeof fromCountry;
245
+ readonly inLanguage: typeof inLanguage;
246
+ readonly withTone: typeof withTone;
247
+ readonly withTheme: typeof withTheme;
248
+ readonly isValidQuery: typeof isValidQuery;
249
+ readonly hasBalancedQuotes: typeof hasBalancedQuotes;
250
+ readonly getQueryComplexity: typeof getQueryComplexity;
251
+ };
252
+ //# sourceMappingURL=query-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../../src/types/query-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,458 @@
1
+ "use strict";
2
+ /**
3
+ * Enhanced query builder with TypeScript template literal types and IntelliSense support
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.QueryHelpers = exports.ImageQueryBuilder = exports.ArticleQueryBuilder = exports.QueryBuilder = void 0;
7
+ exports.createQuery = createQuery;
8
+ exports.createArticleQuery = createArticleQuery;
9
+ exports.createImageQuery = createImageQuery;
10
+ exports.phrase = phrase;
11
+ exports.anyOf = anyOf;
12
+ exports.exclude = exclude;
13
+ exports.fromDomain = fromDomain;
14
+ exports.fromCountry = fromCountry;
15
+ exports.inLanguage = inLanguage;
16
+ exports.withTone = withTone;
17
+ exports.withTheme = withTheme;
18
+ exports.isValidQuery = isValidQuery;
19
+ exports.hasBalancedQuotes = hasBalancedQuotes;
20
+ exports.getQueryComplexity = getQueryComplexity;
21
+ /* eslint-disable @typescript-eslint/explicit-member-accessibility, @typescript-eslint/naming-convention, @typescript-eslint/prefer-nullish-coalescing */
22
+ // Import only what we need to avoid circular dependencies
23
+ // ===== QUERY BUILDER CLASS =====
24
+ /**
25
+ * Fluent query builder for constructing complex GDELT queries with type safety
26
+ */
27
+ class QueryBuilder {
28
+ constructor() {
29
+ this.components = [];
30
+ }
31
+ /**
32
+ * Add a basic search term or phrase
33
+ */
34
+ search(term) {
35
+ this.components.push(term);
36
+ return this;
37
+ }
38
+ /**
39
+ * Add a phrase search (exact match)
40
+ */
41
+ phrase(phrase) {
42
+ this.components.push(`"${phrase}"`);
43
+ return this;
44
+ }
45
+ /**
46
+ * Add multiple terms with OR logic
47
+ */
48
+ anyOf(...terms) {
49
+ if (terms.length > 1) {
50
+ this.components.push(`(${terms.join(' OR ')})`);
51
+ }
52
+ else if (terms.length === 1 && terms[0]) {
53
+ this.components.push(terms[0]);
54
+ }
55
+ return this;
56
+ }
57
+ /**
58
+ * Add multiple terms with AND logic
59
+ */
60
+ allOf(...terms) {
61
+ terms.forEach(term => this.components.push(term));
62
+ return this;
63
+ }
64
+ /**
65
+ * Exclude a term or phrase
66
+ */
67
+ not(term) {
68
+ this.components.push(`-${term}`);
69
+ return this;
70
+ }
71
+ /**
72
+ * Filter by domain
73
+ */
74
+ fromDomain(domain, exact = false) {
75
+ const operator = exact ? 'domainis' : 'domain';
76
+ this.components.push(`${operator}:${domain}`);
77
+ return this;
78
+ }
79
+ /**
80
+ * Filter by source country
81
+ */
82
+ fromCountry(country) {
83
+ this.components.push(`sourcecountry:${country}`);
84
+ return this;
85
+ }
86
+ /**
87
+ * Filter by source language
88
+ */
89
+ inLanguage(language) {
90
+ this.components.push(`sourcelang:${language}`);
91
+ return this;
92
+ }
93
+ /**
94
+ * Filter by tone (emotional sentiment)
95
+ */
96
+ withTone(operator, value) {
97
+ this.components.push(`tone${operator}${value}`);
98
+ return this;
99
+ }
100
+ /**
101
+ * Filter by absolute tone (emotional intensity)
102
+ */
103
+ withAbsoluteTone(operator, value) {
104
+ this.components.push(`toneabs${operator}${value}`);
105
+ return this;
106
+ }
107
+ /**
108
+ * Filter for positive tone articles
109
+ */
110
+ withPositiveTone(threshold = 2) {
111
+ return this.withTone('>', threshold);
112
+ }
113
+ /**
114
+ * Filter for negative tone articles
115
+ */
116
+ withNegativeTone(threshold = -2) {
117
+ return this.withTone('<', threshold);
118
+ }
119
+ /**
120
+ * Filter for neutral tone articles
121
+ */
122
+ withNeutralTone(range = 1) {
123
+ this.components.push(`toneabs<${range}`);
124
+ return this;
125
+ }
126
+ /**
127
+ * Filter for highly emotional articles (regardless of positive/negative)
128
+ */
129
+ withHighEmotion(threshold = 5) {
130
+ return this.withAbsoluteTone('>', threshold);
131
+ }
132
+ /**
133
+ * Filter by GDELT theme
134
+ */
135
+ withTheme(theme) {
136
+ this.components.push(`theme:${theme.toUpperCase()}`);
137
+ return this;
138
+ }
139
+ /**
140
+ * Filter for images with specific tags
141
+ */
142
+ withImageTag(tag) {
143
+ this.components.push(`imagetag:"${tag}"`);
144
+ return this;
145
+ }
146
+ /**
147
+ * Filter for images with web tags
148
+ */
149
+ withImageWebTag(tag) {
150
+ this.components.push(`imagewebtag:"${tag}"`);
151
+ return this;
152
+ }
153
+ /**
154
+ * Filter for images with OCR/metadata content
155
+ */
156
+ withImageOCR(content) {
157
+ this.components.push(`imageocrmeta:"${content}"`);
158
+ return this;
159
+ }
160
+ /**
161
+ * Filter by image face count
162
+ */
163
+ withImageFaceCount(operator, count) {
164
+ this.components.push(`imagenumfaces${operator}${count}`);
165
+ return this;
166
+ }
167
+ /**
168
+ * Filter by image face tone
169
+ */
170
+ withImageFaceTone(operator, tone) {
171
+ this.components.push(`imagefacetone${operator}${tone}`);
172
+ return this;
173
+ }
174
+ /**
175
+ * Filter by how often image appears on web
176
+ */
177
+ withImageWebCount(operator, count) {
178
+ this.components.push(`imagewebcount${operator}${count}`);
179
+ return this;
180
+ }
181
+ /**
182
+ * Filter for novel images (rarely seen on web)
183
+ */
184
+ withNovelImages(threshold = 10) {
185
+ return this.withImageWebCount('<', threshold);
186
+ }
187
+ /**
188
+ * Filter for popular images (frequently seen on web)
189
+ */
190
+ withPopularImages(threshold = 100) {
191
+ return this.withImageWebCount('>', threshold);
192
+ }
193
+ /**
194
+ * Add proximity constraint (words must appear within distance)
195
+ */
196
+ withProximity(distance, ...words) {
197
+ if (words.length >= 2) {
198
+ this.components.push(`near${distance}:"${words.join(' ')}"`);
199
+ }
200
+ return this;
201
+ }
202
+ /**
203
+ * Require word to appear minimum number of times
204
+ */
205
+ withRepeat(count, word) {
206
+ this.components.push(`repeat${count}:"${word}"`);
207
+ return this;
208
+ }
209
+ /**
210
+ * Add custom query component
211
+ */
212
+ custom(query) {
213
+ this.components.push(query);
214
+ return this;
215
+ }
216
+ /**
217
+ * Group current components with parentheses
218
+ */
219
+ group() {
220
+ if (this.components.length > 1) {
221
+ const grouped = `(${this.components.join(' ')})`;
222
+ this.components = [grouped];
223
+ }
224
+ return this;
225
+ }
226
+ /**
227
+ * Clear all components and start fresh
228
+ */
229
+ clear() {
230
+ this.components = [];
231
+ return this;
232
+ }
233
+ /**
234
+ * Build the final query string
235
+ */
236
+ build() {
237
+ return this.components.join(' ');
238
+ }
239
+ /**
240
+ * Get a copy of the current components
241
+ */
242
+ getComponents() {
243
+ return [...this.components];
244
+ }
245
+ /**
246
+ * Check if the builder has any components
247
+ */
248
+ isEmpty() {
249
+ return this.components.length === 0;
250
+ }
251
+ }
252
+ exports.QueryBuilder = QueryBuilder;
253
+ // ===== SPECIALIZED QUERY BUILDERS =====
254
+ /**
255
+ * Query builder specialized for article searches
256
+ */
257
+ class ArticleQueryBuilder extends QueryBuilder {
258
+ /**
259
+ * Search for breaking news articles
260
+ */
261
+ breakingNews() {
262
+ return this.anyOf('breaking', 'urgent', 'just in', 'developing');
263
+ }
264
+ /**
265
+ * Search for opinion articles
266
+ */
267
+ opinions() {
268
+ return this.anyOf('opinion', 'editorial', 'commentary', 'analysis');
269
+ }
270
+ /**
271
+ * Search for local news
272
+ */
273
+ localNews(location) {
274
+ if (location) {
275
+ return this.allOf('local', location);
276
+ }
277
+ return this.search('local');
278
+ }
279
+ }
280
+ exports.ArticleQueryBuilder = ArticleQueryBuilder;
281
+ /**
282
+ * Query builder specialized for image searches
283
+ */
284
+ class ImageQueryBuilder extends QueryBuilder {
285
+ /**
286
+ * Search for violent content images
287
+ */
288
+ violentContent() {
289
+ return this.withImageTag('safesearchviolence');
290
+ }
291
+ /**
292
+ * Search for medical content images
293
+ */
294
+ medicalContent() {
295
+ return this.withImageTag('safesearchmedical');
296
+ }
297
+ /**
298
+ * Search for disaster-related images
299
+ */
300
+ disasters() {
301
+ return this.anyOf('imagetag:"flood"', 'imagetag:"fire"', 'imagetag:"earthquake"', 'imagetag:"rubble"');
302
+ }
303
+ /**
304
+ * Search for political event images
305
+ */
306
+ politicalEvents() {
307
+ return this.anyOf('imagetag:"crowd"', 'imagetag:"protest"', 'imagetag:"rally"', 'imagetag:"podium"');
308
+ }
309
+ /**
310
+ * Search for happy/positive images
311
+ */
312
+ positiveImages() {
313
+ return this.withImageFaceTone('>', 1);
314
+ }
315
+ /**
316
+ * Search for sad/negative images
317
+ */
318
+ negativeImages() {
319
+ return this.withImageFaceTone('<', -1);
320
+ }
321
+ }
322
+ exports.ImageQueryBuilder = ImageQueryBuilder;
323
+ // ===== QUERY HELPER FUNCTIONS =====
324
+ /**
325
+ * Create a new general query builder
326
+ */
327
+ function createQuery() {
328
+ return new QueryBuilder();
329
+ }
330
+ /**
331
+ * Create a new article-specialized query builder
332
+ */
333
+ function createArticleQuery() {
334
+ return new ArticleQueryBuilder();
335
+ }
336
+ /**
337
+ * Create a new image-specialized query builder
338
+ */
339
+ function createImageQuery() {
340
+ return new ImageQueryBuilder();
341
+ }
342
+ /**
343
+ * Create a quick phrase query
344
+ */
345
+ function phrase(text) {
346
+ return `"${text}"`;
347
+ }
348
+ /**
349
+ * Create a quick OR query
350
+ */
351
+ function anyOf(...terms) {
352
+ if (terms.length === 0)
353
+ return '';
354
+ if (terms.length === 1)
355
+ return terms[0] || '';
356
+ return `(${terms.join(' OR ')})`;
357
+ }
358
+ /**
359
+ * Create a quick exclusion query
360
+ */
361
+ function exclude(term) {
362
+ return `-${term}`;
363
+ }
364
+ /**
365
+ * Create a domain filter
366
+ */
367
+ function fromDomain(domain, exact = false) {
368
+ const operator = exact ? 'domainis' : 'domain';
369
+ return `${operator}:${domain}`;
370
+ }
371
+ /**
372
+ * Create a country filter
373
+ */
374
+ function fromCountry(country) {
375
+ return `sourcecountry:${country}`;
376
+ }
377
+ /**
378
+ * Create a language filter
379
+ */
380
+ function inLanguage(language) {
381
+ return `sourcelang:${language}`;
382
+ }
383
+ /**
384
+ * Create a tone filter
385
+ */
386
+ function withTone(operator, value) {
387
+ return `tone${operator}${value}`;
388
+ }
389
+ /**
390
+ * Create a theme filter
391
+ */
392
+ function withTheme(theme) {
393
+ return `theme:${theme.toUpperCase()}`;
394
+ }
395
+ // ===== QUERY VALIDATION HELPERS =====
396
+ /**
397
+ * Validate that a query string is well-formed
398
+ */
399
+ function isValidQuery(query) {
400
+ if (!query || query.trim().length === 0) {
401
+ return false;
402
+ }
403
+ // Check for balanced parentheses
404
+ let parenCount = 0;
405
+ for (const char of query) {
406
+ if (char === '(')
407
+ parenCount++;
408
+ if (char === ')')
409
+ parenCount--;
410
+ if (parenCount < 0)
411
+ return false;
412
+ }
413
+ return parenCount === 0;
414
+ }
415
+ /**
416
+ * Validate that a query has balanced quotes
417
+ */
418
+ function hasBalancedQuotes(query) {
419
+ const quotes = query.match(/"/g);
420
+ return !quotes || quotes.length % 2 === 0;
421
+ }
422
+ /**
423
+ * Get query complexity score (approximate)
424
+ */
425
+ function getQueryComplexity(query) {
426
+ let complexity = 0;
427
+ // Base complexity
428
+ complexity += query.split(' ').length;
429
+ // Operators add complexity
430
+ complexity += (query.match(/\bOR\b/g) || []).length * 2;
431
+ complexity += (query.match(/\bAND\b/g) || []).length * 1;
432
+ complexity += (query.match(/\bNOT\b/g) || []).length * 1;
433
+ // Special operators add complexity
434
+ const operatorPattern = /\b(?:domain|domainis|sourcecountry|sourcelang|theme|tone|toneabs|imagetag|imagewebtag|imageocrmeta|imagenumfaces|imagefacetone|imagewebcount):/g;
435
+ complexity += (query.match(operatorPattern) || []).length * 3;
436
+ // Proximity and repeat operators
437
+ complexity += (query.match(/\bnear\d+:/g) || []).length * 4;
438
+ complexity += (query.match(/\brepeat\d+:/g) || []).length * 2;
439
+ return complexity;
440
+ }
441
+ // ===== EXPORT EVERYTHING =====
442
+ exports.QueryHelpers = {
443
+ createQuery,
444
+ createArticleQuery,
445
+ createImageQuery,
446
+ phrase,
447
+ anyOf,
448
+ exclude,
449
+ fromDomain,
450
+ fromCountry,
451
+ inLanguage,
452
+ withTone,
453
+ withTheme,
454
+ isValidQuery,
455
+ hasBalancedQuotes,
456
+ getQueryComplexity
457
+ };
458
+ //# sourceMappingURL=query-builder.js.map