flowquery 1.0.6 → 1.0.8

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 (49) hide show
  1. package/README.md +30 -138
  2. package/dist/compute/runner.d.ts +1 -22
  3. package/dist/compute/runner.d.ts.map +1 -1
  4. package/dist/compute/runner.js.map +1 -1
  5. package/dist/extensibility.d.ts +28 -2
  6. package/dist/extensibility.d.ts.map +1 -1
  7. package/dist/extensibility.js +39 -15
  8. package/dist/extensibility.js.map +1 -1
  9. package/dist/flowquery.min.js +1 -1
  10. package/dist/index.browser.d.ts.map +1 -1
  11. package/dist/index.browser.js +0 -80
  12. package/dist/index.browser.js.map +1 -1
  13. package/dist/index.node.d.ts +3 -3
  14. package/dist/index.node.d.ts.map +1 -1
  15. package/dist/index.node.js +0 -80
  16. package/dist/index.node.js.map +1 -1
  17. package/dist/parsing/functions/function_factory.d.ts +3 -80
  18. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  19. package/dist/parsing/functions/function_factory.js +8 -127
  20. package/dist/parsing/functions/function_factory.js.map +1 -1
  21. package/dist/parsing/functions/function_metadata.d.ts +28 -35
  22. package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
  23. package/dist/parsing/functions/function_metadata.js +88 -61
  24. package/dist/parsing/functions/function_metadata.js.map +1 -1
  25. package/docs/flowquery.min.js +1 -1
  26. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  27. package/misc/apps/RAG/package.json +1 -1
  28. package/misc/apps/RAG/src/plugins/index.ts +29 -33
  29. package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +28 -32
  30. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +29 -33
  31. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +55 -59
  32. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +61 -71
  33. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +8 -8
  34. package/package.json +1 -1
  35. package/src/compute/runner.ts +1 -26
  36. package/src/extensibility.ts +38 -2
  37. package/src/index.browser.ts +2 -88
  38. package/src/index.node.ts +3 -92
  39. package/src/parsing/functions/function_factory.ts +13 -154
  40. package/src/parsing/functions/function_metadata.ts +96 -94
  41. package/tests/extensibility.test.ts +601 -0
  42. package/dist/parsing/functions/extensibility/index.d.ts +0 -37
  43. package/dist/parsing/functions/extensibility/index.d.ts.map +0 -1
  44. package/dist/parsing/functions/extensibility/index.js +0 -50
  45. package/dist/parsing/functions/extensibility/index.js.map +0 -1
  46. package/misc/apps/RAG/src/plugins/PluginRegistry.ts +0 -136
  47. package/misc/apps/RAG/src/plugins/types.ts +0 -52
  48. package/src/parsing/functions/extensibility/index.ts +0 -54
  49. package/tests/parsing/function_plugins.test.ts +0 -369
@@ -3,7 +3,7 @@
3
3
  * Core categories: scalar, aggregate, predicate, async
4
4
  * Additional categories for organization: string, math, data, etc.
5
5
  */
6
- export type FunctionCategory = "scalar" | "aggregate" | "predicate" | "async" | "string" | "math" | "data" | "introspection" | string;
6
+ export type FunctionCategory = "scalar" | "aggregate" | "predicate" | "async" | string;
7
7
 
8
8
  /**
9
9
  * Schema definition for function arguments and outputs.
@@ -54,8 +54,8 @@ export interface FunctionMetadata {
54
54
  name: string;
55
55
  /** Human-readable description of what the function does */
56
56
  description: string;
57
- /** Category for grouping functions */
58
- category?: FunctionCategory;
57
+ /** Category that determines function type and behavior */
58
+ category: FunctionCategory;
59
59
  /** Array of parameter schemas */
60
60
  parameters: ParameterSchema[];
61
61
  /** Output schema */
@@ -64,40 +64,75 @@ export interface FunctionMetadata {
64
64
  examples?: string[];
65
65
  /** Additional notes or caveats */
66
66
  notes?: string;
67
- /** Whether this is an async data provider (for LOAD operations) */
68
- isAsyncProvider?: boolean;
69
67
  }
70
68
 
71
69
  /**
72
- * Options for registering a sync function with metadata.
70
+ * Type for async data provider functions used in LOAD operations.
73
71
  */
74
- export interface RegisterFunctionOptions {
75
- /** Factory function that creates the Function instance */
76
- factory: () => any;
77
- /** Function metadata for documentation */
78
- metadata: FunctionMetadata;
79
- }
72
+ export type AsyncDataProvider = (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
80
73
 
81
74
  /**
82
- * Options for registering an async data provider with metadata.
75
+ * Centralized registry for function metadata, factories, and async providers.
76
+ * Encapsulates all registration logic for the @FunctionDef decorator.
83
77
  */
84
- export interface RegisterAsyncProviderOptions {
85
- /** Async generator or function that returns data */
86
- provider: (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
87
- /** Function metadata for documentation */
88
- metadata: FunctionMetadata;
89
- }
78
+ class FunctionRegistry {
79
+ private static metadata: Map<string, FunctionMetadata> = new Map<string, FunctionMetadata>();
80
+ private static factories: Map<string, () => any> = new Map<string, () => any>();
81
+ private static asyncProviders: Map<string, AsyncDataProvider> = new Map<string, AsyncDataProvider>();
90
82
 
91
- /**
92
- * Registry for function metadata collected via decorators.
93
- */
94
- const functionMetadataRegistry: Map<string, FunctionMetadata> = new Map();
83
+ /** Derives a camelCase display name from a class name, removing 'Loader' suffix. */
84
+ private static deriveDisplayName(className: string): string {
85
+ const baseName: string = className.endsWith('Loader') ? className.slice(0, -6) : className;
86
+ return baseName.charAt(0).toLowerCase() + baseName.slice(1);
87
+ }
95
88
 
96
- /**
97
- * Registry for function factories collected via decorators.
98
- * Allows @FunctionDef to automatically register functions for instantiation.
99
- */
100
- const functionFactoryRegistry: Map<string, () => any> = new Map();
89
+ /** Registers an async data provider class. */
90
+ static registerAsync<T extends new (...args: any[]) => any>(constructor: T, options: FunctionDefOptions): void {
91
+ const displayName: string = this.deriveDisplayName(constructor.name);
92
+ const registryKey: string = displayName.toLowerCase();
93
+
94
+ this.metadata.set(registryKey, { name: displayName, ...options });
95
+ this.asyncProviders.set(registryKey, (...args: any[]) => new constructor().fetch(...args));
96
+ }
97
+
98
+ /** Registers a regular function class. */
99
+ static registerFunction<T extends new (...args: any[]) => any>(constructor: T, options: FunctionDefOptions): void {
100
+ const instance: any = new constructor();
101
+ const baseName: string = (instance.name?.toLowerCase() || constructor.name.toLowerCase());
102
+ const displayName: string = baseName.includes(':') ? baseName.split(':')[0] : baseName;
103
+ const registryKey: string = options.category ? `${displayName}:${options.category}` : displayName;
104
+
105
+ this.metadata.set(registryKey, { name: displayName, ...options });
106
+
107
+ if (options.category !== 'predicate') {
108
+ this.factories.set(displayName, () => new constructor());
109
+ }
110
+ this.factories.set(registryKey, () => new constructor());
111
+ }
112
+
113
+ static getAllMetadata(): FunctionMetadata[] {
114
+ return Array.from(this.metadata.values());
115
+ }
116
+
117
+ static getMetadata(name: string, category?: string): FunctionMetadata | undefined {
118
+ const lowerName: string = name.toLowerCase();
119
+ if (category) return this.metadata.get(`${lowerName}:${category}`);
120
+ for (const meta of this.metadata.values()) {
121
+ if (meta.name === lowerName) return meta;
122
+ }
123
+ return undefined;
124
+ }
125
+
126
+ static getFactory(name: string, category?: string): (() => any) | undefined {
127
+ const lowerName: string = name.toLowerCase();
128
+ if (category) return this.factories.get(`${lowerName}:${category}`);
129
+ return this.factories.get(lowerName);
130
+ }
131
+
132
+ static getAsyncProvider(name: string): AsyncDataProvider | undefined {
133
+ return this.asyncProviders.get(name.toLowerCase());
134
+ }
135
+ }
101
136
 
102
137
  /**
103
138
  * Decorator options - metadata without the name (derived from class).
@@ -106,13 +141,19 @@ export type FunctionDefOptions = Omit<FunctionMetadata, 'name'>;
106
141
 
107
142
  /**
108
143
  * Class decorator that registers function metadata.
109
- * The function name is derived from the class's constructor call to super().
144
+ * The function name is derived from the class's constructor call to super() for regular functions,
145
+ * or from the class name for async providers.
146
+ *
147
+ * For async providers (category: "async"), the class must have a `fetch` method that returns
148
+ * an AsyncGenerator. The function name is derived from the class name (removing 'Loader' suffix
149
+ * if present) and converted to camelCase.
110
150
  *
111
151
  * @param options - Function metadata (excluding name)
112
152
  * @returns Class decorator
113
153
  *
114
154
  * @example
115
155
  * ```typescript
156
+ * // Regular function
116
157
  * @FunctionDef({
117
158
  * description: "Calculates the sum of numeric values",
118
159
  * category: "aggregate",
@@ -121,94 +162,55 @@ export type FunctionDefOptions = Omit<FunctionMetadata, 'name'>;
121
162
  * examples: ["WITH [1, 2, 3] AS nums UNWIND nums AS n RETURN sum(n)"]
122
163
  * })
123
164
  * class Sum extends AggregateFunction { ... }
165
+ *
166
+ * // Async data provider
167
+ * @FunctionDef({
168
+ * description: "Fetches random cat facts from the Cat Facts API",
169
+ * category: "async",
170
+ * parameters: [{ name: "count", description: "Number of facts", type: "number", required: false, default: 1 }],
171
+ * output: { description: "Cat fact object", type: "object" },
172
+ * examples: ["LOAD JSON FROM catFacts(5) AS fact RETURN fact.text"]
173
+ * })
174
+ * class CatFactsLoader {
175
+ * async *fetch(count: number = 1): AsyncGenerator<any> { ... }
176
+ * }
124
177
  * ```
125
178
  */
126
179
  export function FunctionDef(options: FunctionDefOptions) {
127
180
  return function <T extends new (...args: any[]) => any>(constructor: T): T {
128
- // Create an instance to get the function name from super() call
129
- const instance = new constructor();
130
- const baseName = instance.name?.toLowerCase() || constructor.name.toLowerCase();
131
-
132
- // Use category-qualified key to avoid collisions (e.g., sum vs sum:predicate)
133
- // but store the display name without the qualifier
134
- const displayName = baseName.includes(':') ? baseName.split(':')[0] : baseName;
135
- const registryKey = options.category ? `${displayName}:${options.category}` : displayName;
136
-
137
- // Register metadata with display name but category-qualified key
138
- const metadata: FunctionMetadata = {
139
- name: displayName,
140
- ...options
141
- };
142
- functionMetadataRegistry.set(registryKey, metadata);
143
-
144
- // Register factory function for automatic instantiation
145
- // Only register to the simple name if no collision exists (predicate functions use qualified keys)
146
- if (options.category !== 'predicate') {
147
- functionFactoryRegistry.set(displayName, () => new constructor());
181
+ if (options.category === 'async') {
182
+ FunctionRegistry.registerAsync(constructor, options);
183
+ } else {
184
+ FunctionRegistry.registerFunction(constructor, options);
148
185
  }
149
- functionFactoryRegistry.set(registryKey, () => new constructor());
150
-
151
186
  return constructor;
152
187
  };
153
188
  }
154
189
 
155
190
  /**
156
191
  * Gets all registered function metadata from decorators.
157
- *
158
- * @returns Array of function metadata
159
192
  */
160
193
  export function getRegisteredFunctionMetadata(): FunctionMetadata[] {
161
- return Array.from(functionMetadataRegistry.values());
194
+ return FunctionRegistry.getAllMetadata();
162
195
  }
163
196
 
164
197
  /**
165
198
  * Gets a registered function factory by name.
166
- * Used by FunctionFactory to instantiate decorator-registered functions.
167
- *
168
- * @param name - Function name (case-insensitive)
169
- * @param category - Optional category to disambiguate (e.g., 'predicate')
170
- * @returns Factory function or undefined
171
199
  */
172
200
  export function getRegisteredFunctionFactory(name: string, category?: string): (() => any) | undefined {
173
- const lowerName = name.toLowerCase();
174
-
175
- // If category specified, look for exact match
176
- if (category) {
177
- return functionFactoryRegistry.get(`${lowerName}:${category}`);
178
- }
179
-
180
- // Try direct match first
181
- if (functionFactoryRegistry.has(lowerName)) {
182
- return functionFactoryRegistry.get(lowerName);
183
- }
184
-
185
- return undefined;
201
+ return FunctionRegistry.getFactory(name, category);
186
202
  }
187
203
 
188
204
  /**
189
205
  * Gets metadata for a specific function by name.
190
- * If multiple functions share the same name (e.g., aggregate vs predicate),
191
- * optionally specify the category to get the specific one.
192
- *
193
- * @param name - Function name (case-insensitive)
194
- * @param category - Optional category to disambiguate
195
- * @returns Function metadata or undefined
196
206
  */
197
207
  export function getFunctionMetadata(name: string, category?: string): FunctionMetadata | undefined {
198
- const lowerName = name.toLowerCase();
199
-
200
- // If category specified, look for exact match
201
- if (category) {
202
- return functionMetadataRegistry.get(`${lowerName}:${category}`);
203
- }
204
-
205
- // Otherwise, first try direct match (for functions without category conflicts)
206
- // Then search for any function with matching name
207
- for (const [key, meta] of functionMetadataRegistry) {
208
- if (meta.name === lowerName) {
209
- return meta;
210
- }
211
- }
212
-
213
- return undefined;
208
+ return FunctionRegistry.getMetadata(name, category);
209
+ }
210
+
211
+ /**
212
+ * Gets a registered async data provider by name.
213
+ */
214
+ export function getRegisteredAsyncProvider(name: string): AsyncDataProvider | undefined {
215
+ return FunctionRegistry.getAsyncProvider(name);
214
216
  }